Skip to content

Commit

Permalink
add backend metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
zznty committed Aug 30, 2024
1 parent ac7f0e9 commit 0a12ebf
Show file tree
Hide file tree
Showing 26 changed files with 319 additions and 104 deletions.
87 changes: 87 additions & 0 deletions MusicX.Core/Services/BackendConnectionService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using System.Net.Http.Json;
using MusicX.Core.Models;
using MusicX.Shared;
using Newtonsoft.Json;
using NLog;

namespace MusicX.Core.Services;

public class BackendConnectionService(Logger logger, string appVersion)
{
private string? _token;
public readonly HttpClient Client = new();

public string Host { get; set; } =
#if DEBUG
"http://localhost:2024";
#else
"https://musicx.zznty.ru";
#endif

public async void ReportMetric(string eventName, string? source = null)
{
if (string.IsNullOrEmpty(_token))
throw new NullReferenceException("Token is null");

try
{
using var response = await Client.PostAsJsonAsync($"/metrics/{eventName}/report", new ReportMetricRequest(appVersion, source));
response.EnsureSuccessStatusCode();
}
catch (Exception e)
{
logger.Error(e, "Error while reporting event metric {0}", eventName);
throw;
}
}

public async Task<string> GetTokenAsync(long userId)
{
if (_token is not null) return _token;
logger.Info("Получение временного токена Слушать вместе");

var host = await GetHostAsync();

Client.BaseAddress = new(host);
using var response = await Client.PostAsJsonAsync("/token", userId);
response.EnsureSuccessStatusCode();

_token = await response.Content.ReadFromJsonAsync<string>() ??
throw new NullReferenceException("Got null response for token request");

Client.DefaultRequestHeaders.Authorization = new("Bearer", _token);

return _token;
}

private async Task<string> GetHostAsync()
{
if (!string.IsNullOrEmpty(Host))
return Host;

try
{
logger.Info("Получение адресса сервера Послушать вместе");
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("https://fooxboy.blob.core.windows.net/musicx/ListenTogetherServers.json");

var contents = await response.Content.ReadAsStringAsync();

var servers = JsonConvert.DeserializeObject<ListenTogetherServersModel>(contents);

return Host =
#if DEBUG
servers.Test;
#else
servers.Production;
#endif
}
}
catch(Exception)
{
return "http://212.192.40.71:5000";
}

}
}
65 changes: 6 additions & 59 deletions MusicX.Core/Services/ListenTogetherService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class ListenTogetherService : IAsyncDisposable
private readonly Logger _logger;
private HubConnection _connection;
private IEnumerable<IDisposable> _subscriptions;
private readonly BackendConnectionService _backendConnectionService;

/// <summary>
/// Изменилась позиция трека
Expand Down Expand Up @@ -66,14 +67,14 @@ public class ListenTogetherService : IAsyncDisposable

public string SessionId { get; set; }

public string ConnectUrl => $"{Host}/connect?id={SessionId}";
public string ConnectUrl => $"{_backendConnectionService.Host}/connect?id={SessionId}";

public string Host { get; private set; } = "https://musicx.zznty.ru:8443";
public string? Token { get; set; }

public ListenTogetherService(Logger logger)
public ListenTogetherService(Logger logger, BackendConnectionService backendConnectionService)
{
_logger = logger;
_backendConnectionService = backendConnectionService;

SessionOwnerStoped += SessionUserStoped;
}
Expand Down Expand Up @@ -211,24 +212,17 @@ public async Task LeavePlaySessionAsync()
LeaveSession?.Invoke();
}

public async Task LoginAsync(long userId)
{
Token = await GetTokenAsync(userId);
}

public async Task ConnectToServerAsync(long userId)
{
_logger.Info("Подключение к серверу Слушать вместе");

await GetListenTogetherHostAsync();

var token = await GetTokenAsync(userId);
var token = await _backendConnectionService.GetTokenAsync(userId);

this.Token = token;

_connection = new HubConnectionBuilder()
.WithAutomaticReconnect()
.WithUrl($"{Host}/hubs/listen", options =>
.WithUrl($"{_backendConnectionService.Host}/hubs/listen", options =>
options.AccessTokenProvider = () => Task.FromResult(Token)!)
.AddProtobufProtocol()
.Build();
Expand Down Expand Up @@ -275,53 +269,6 @@ public async Task<UsersList> GetListenersInSession()
}


private async Task<string> GetTokenAsync(long userId)
{
_logger.Info("Получение временного токена Слушать вместе");

using var client = new HttpClient
{
BaseAddress = new(Host)
};
using var response = await client.PostAsJsonAsync("/token", userId);
response.EnsureSuccessStatusCode();

var token = await response.Content.ReadFromJsonAsync<string>() ?? throw new NullReferenceException("Got null response for token request");

return token;
}

private async Task<string> GetListenTogetherHostAsync()
{
if (!string.IsNullOrEmpty(Host))
return Host;

try
{
_logger.Info("Получение адресса сервера Послушать вместе");
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("https://fooxboy.blob.core.windows.net/musicx/ListenTogetherServers.json");

var contents = await response.Content.ReadAsStringAsync();

var servers = JsonConvert.DeserializeObject<ListenTogetherServersModel>(contents);

return Host =
#if DEBUG
servers.Test;
#else
servers.Production;
#endif
}
}
catch(Exception)
{
return "http://212.192.40.71:5000";
}

}

private async Task SessionUserStoped()
{
await _connection.StopAsync();
Expand Down
53 changes: 10 additions & 43 deletions MusicX.Core/Services/UserRadioService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,28 @@
using System.Net.Http.Json;
using System.Text;
using System.Threading.Tasks;
using VkNet.Abstractions;
using VkNet.Model.Attachments;

namespace MusicX.Core.Services
{
public class UserRadioService
public class UserRadioService(Logger logger, BackendConnectionService backendConnectionService)
{
private readonly Logger _logger;
private readonly ListenTogetherService _listenTogetherService;
private readonly IUsersCategory _usersCategory;

public bool IsStarted { get; private set; }

public UserRadioService(Logger logger, ListenTogetherService listenTogetherService, IUsersCategory usersCategory)
{
_logger = logger;
_listenTogetherService = listenTogetherService;
_usersCategory = usersCategory;
}

public async Task<List<Station>> GetStationsList()
{
_logger.Info("Получение списка всех доступных станций");
logger.Info("Получение списка всех доступных станций");

var stations = await HttpRequestAsync<List<Station>>("getStations", new Dictionary<string, string>());

_logger.Info($"Получено {stations.Count} пользовательских станций");
logger.Info($"Получено {stations.Count} пользовательских станций");

return stations;
}

public Task<Station> CreateStationAsync(string sessionId, string title, string cover, string decription, long ownerId, string ownerName, string ownerPhoto)
{
_logger.Info($"Создание пользовательской радиостанции с ID {sessionId}");
logger.Info($"Создание пользовательской радиостанции с ID {sessionId}");

var p = new Dictionary<string, string>()
{
Expand All @@ -61,7 +49,7 @@ public Task<Station> CreateStationAsync(string sessionId, string title, string c

public Task<bool> DeleteStationAsync(string sessionId)
{
_logger.Info($"Удаление пользовательской радиостанции с ID {sessionId}");
logger.Info($"Удаление пользовательской радиостанции с ID {sessionId}");

var p = new Dictionary<string, string>()
{
Expand All @@ -75,56 +63,35 @@ public Task<bool> DeleteStationAsync(string sessionId)

public async Task<string> UploadCoverAsync(string path)
{
using var httpClient = await GetHttpClientAsync();
await using var stream = File.OpenRead(path);

var data = new MultipartFormDataContent
{
{ new StreamContent(stream), "image", "image" }
};

using var response = await httpClient.PostAsync("/radio/uploadImage", data);
using var response = await backendConnectionService.Client.PostAsync("/radio/uploadImage", data);

response.EnsureSuccessStatusCode();

return $"{_listenTogetherService.Host}/{await response.Content.ReadAsStringAsync()}";
return $"{backendConnectionService.Host}/{await response.Content.ReadAsStringAsync()}";
}

private async Task<TResponse> HttpRequestAsync<TResponse>(string method, Dictionary<string, string> parameters)
{
try
{
using var httpClient = await GetHttpClientAsync();

var p = parameters.Select(x => x.Key + "=" + x.Value);

return await httpClient.GetFromJsonAsync<TResponse>("/radio/" + method + "?" + string.Join("&", p));
return await backendConnectionService.Client.GetFromJsonAsync<TResponse>("/radio/" + method + "?" + string.Join("&", p));
}
catch(Exception ex)
{
_logger.Info($"Произошла ошибка при запросе: {ex}");
_logger.Error(ex);
logger.Info($"Произошла ошибка при запросе: {ex}");
logger.Error(ex);
throw;
}

}

private async ValueTask<HttpClient> GetHttpClientAsync()
{
if (_listenTogetherService.Token is null)
{
var users = await _usersCategory.GetAsync(Enumerable.Empty<long>());
await _listenTogetherService.LoginAsync(users[0].Id);
}

return new HttpClient
{
BaseAddress = new Uri(_listenTogetherService.Host),
DefaultRequestHeaders =
{
Authorization = new("Bearer", _listenTogetherService.Token)
}
};
}
}
}
31 changes: 31 additions & 0 deletions MusicX.Server/Controllers/MetricsController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Security.Claims;
using InfluxDB.Client;
using InfluxDB.Client.Api.Domain;
using InfluxDB.Client.Writes;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MusicX.Shared;

namespace MusicX.Server.Controllers;

[Route("metrics")]
[Authorize]
public class MetricsController(IWriteApiAsync writeApi) : Controller
{
[HttpPost("{eventName}/report")]
public async Task Report(string eventName, [FromBody] ReportMetricRequest metricRequest)
{
var userId = User.Claims.Single(b => b.Type == ClaimTypes.NameIdentifier).Value;

var point = PointData.Measurement(eventName)
.Tag("userId", userId)
.Tag("version", metricRequest.AppVersion)
.Field("value", 1)
.Timestamp(DateTime.Now, WritePrecision.Ms);

if (!string.IsNullOrEmpty(metricRequest.Source))
point = point.Tag("source", metricRequest.Source);

await writeApi.WritePointAsync(point);
}
}
2 changes: 1 addition & 1 deletion MusicX.Server/MusicX.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="InfluxDB.Client" Version="4.16.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.7" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="8.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
Expand All @@ -20,7 +21,6 @@
</ItemGroup>

<ItemGroup>
<Folder Include="Exceptions\" />
<Folder Include="files\" />
</ItemGroup>

Expand Down
5 changes: 5 additions & 0 deletions MusicX.Server/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using InfluxDB.Client;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -48,6 +49,10 @@
builder.Services.AddSingleton<SessionService>();
builder.Services.AddTransient<ListenTogetherService>();

builder.Services.AddScoped<IInfluxDBClient>(_ => new InfluxDBClient(builder.Configuration.GetConnectionString("influxdb")));
builder.Services.AddScoped<IWriteApiAsync>(
provider => provider.GetRequiredService<IInfluxDBClient>().GetWriteApiAsync());

var app = builder.Build();

#if DEBUG
Expand Down
4 changes: 3 additions & 1 deletion MusicX.Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"Audience": "https://localhost/",
"Key": "This is a sample secret key - please don't use in production environment.'"
},

"ConnectionStrings": {
"InfluxDb": "http://localhost:8086/?logLevel=BASIC&org=musicx&bucket=metrics&token=94aS7aYiepHMckB5P_lHywIICm6XDq31BVYzX4YpxAflNx4bO7TJ7YaOfdAtR-uHO_wNh4E7WAEUR5EVLSVacA=="
},
"UsersCategories": {
"Developers": [ 308764786, 316614260 ],
"Recoms": [ 0 ],
Expand Down
3 changes: 3 additions & 0 deletions MusicX.Shared/ReportMetricRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace MusicX.Shared;

public record ReportMetricRequest(string AppVersion, string? Source);
Loading

0 comments on commit 0a12ebf

Please sign in to comment.