From f52b9e295138dbb423b2728846f107109c2d8ef7 Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Fri, 7 Jul 2023 03:06:16 +0200 Subject: [PATCH] Added telemetry reporter --- .../Telemetry/Requests/TelemetryData.cs | 11 ++++ .../Telemetry/TelemetryApiHelper.cs | 52 ++++++++++++++++ .../Telemetry/TelemetryException.cs | 32 ++++++++++ .../Services/Background/TelemetryService.cs | 62 +++++++++++++++++++ Moonlight/Program.cs | 4 ++ 5 files changed, 161 insertions(+) create mode 100644 Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs create mode 100644 Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs create mode 100644 Moonlight/App/ApiClients/Telemetry/TelemetryException.cs create mode 100644 Moonlight/App/Services/Background/TelemetryService.cs diff --git a/Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs b/Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs new file mode 100644 index 00000000..c8fafe75 --- /dev/null +++ b/Moonlight/App/ApiClients/Telemetry/Requests/TelemetryData.cs @@ -0,0 +1,11 @@ +namespace Moonlight.App.ApiClients.Telemetry.Requests; + +public class TelemetryData +{ + public string AppUrl { get; set; } = ""; + public int Servers { get; set; } + public int Nodes { get; set; } + public int Users { get; set; } + public int Databases { get; set; } + public int Webspaces { get; set; } +} \ No newline at end of file diff --git a/Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs b/Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs new file mode 100644 index 00000000..d9b07450 --- /dev/null +++ b/Moonlight/App/ApiClients/Telemetry/TelemetryApiHelper.cs @@ -0,0 +1,52 @@ +using Newtonsoft.Json; +using RestSharp; + +namespace Moonlight.App.ApiClients.Telemetry; + +public class TelemetryApiHelper +{ + private readonly RestClient Client; + + public TelemetryApiHelper() + { + Client = new(); + } + + public async Task Post(string resource, object? body) + { + var request = CreateRequest(resource); + + request.Method = Method.Post; + + request.AddParameter("application/json", JsonConvert.SerializeObject(body), ParameterType.RequestBody); + + var response = await Client.ExecuteAsync(request); + + if (!response.IsSuccessful) + { + if (response.StatusCode != 0) + { + throw new TelemetryException( + $"An error occured: ({response.StatusCode}) {response.Content}", + (int)response.StatusCode + ); + } + else + { + throw new Exception($"An internal error occured: {response.ErrorMessage}"); + } + } + } + + private RestRequest CreateRequest(string resource) + { + var url = "https://telemetry.moonlightpanel.xyz/" + resource; + + var request = new RestRequest(url) + { + Timeout = 3000000 + }; + + return request; + } +} \ No newline at end of file diff --git a/Moonlight/App/ApiClients/Telemetry/TelemetryException.cs b/Moonlight/App/ApiClients/Telemetry/TelemetryException.cs new file mode 100644 index 00000000..7b66b710 --- /dev/null +++ b/Moonlight/App/ApiClients/Telemetry/TelemetryException.cs @@ -0,0 +1,32 @@ +using System.Runtime.Serialization; + +namespace Moonlight.App.ApiClients.Telemetry; + +[Serializable] +public class TelemetryException : Exception +{ + public int StatusCode { get; set; } + + public TelemetryException() + { + } + + public TelemetryException(string message, int statusCode) : base(message) + { + StatusCode = statusCode; + } + + public TelemetryException(string message) : base(message) + { + } + + public TelemetryException(string message, Exception inner) : base(message, inner) + { + } + + protected TelemetryException( + SerializationInfo info, + StreamingContext context) : base(info, context) + { + } +} \ No newline at end of file diff --git a/Moonlight/App/Services/Background/TelemetryService.cs b/Moonlight/App/Services/Background/TelemetryService.cs new file mode 100644 index 00000000..53e1131f --- /dev/null +++ b/Moonlight/App/Services/Background/TelemetryService.cs @@ -0,0 +1,62 @@ +using Moonlight.App.ApiClients.Telemetry; +using Moonlight.App.ApiClients.Telemetry.Requests; +using Moonlight.App.Database.Entities; +using Moonlight.App.Helpers; +using Moonlight.App.Repositories; + +namespace Moonlight.App.Services.Background; + +public class TelemetryService +{ + private readonly IServiceScopeFactory ServiceScopeFactory; + private readonly ConfigService ConfigService; + + public TelemetryService( + ConfigService configService, + IServiceScopeFactory serviceScopeFactory) + { + ServiceScopeFactory = serviceScopeFactory; + ConfigService = configService; + + if(!ConfigService.DebugMode) + Task.Run(Run); + } + + private async Task Run() + { + var timer = new PeriodicTimer(TimeSpan.FromMinutes(15)); + + while (true) + { + using var scope = ServiceScopeFactory.CreateScope(); + + var serversRepo = scope.ServiceProvider.GetRequiredService>(); + var nodesRepo = scope.ServiceProvider.GetRequiredService>(); + var usersRepo = scope.ServiceProvider.GetRequiredService>(); + var webspacesRepo = scope.ServiceProvider.GetRequiredService>(); + var databaseRepo = scope.ServiceProvider.GetRequiredService>(); + + var apiHelper = scope.ServiceProvider.GetRequiredService(); + + try + { + await apiHelper.Post("telemetry", new TelemetryData() + { + Servers = serversRepo.Get().Count(), + Databases = databaseRepo.Get().Count(), + Nodes = nodesRepo.Get().Count(), + Users = usersRepo.Get().Count(), + Webspaces = webspacesRepo.Get().Count(), + AppUrl = ConfigService.Get().Moonlight.AppUrl + }); + } + catch (Exception e) + { + Logger.Warn("Error sending telemetry"); + Logger.Warn(e); + } + + await timer.WaitForNextTickAsync(); + } + } +} \ No newline at end of file diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index 1a5160a3..fb850669 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -6,6 +6,7 @@ using Moonlight.App.ApiClients.CloudPanel; using Moonlight.App.ApiClients.Daemon; using Moonlight.App.ApiClients.Modrinth; using Moonlight.App.ApiClients.Paper; +using Moonlight.App.ApiClients.Telemetry; using Moonlight.App.ApiClients.Wings; using Moonlight.App.Database; using Moonlight.App.Diagnostics.HealthChecks; @@ -236,6 +237,7 @@ namespace Moonlight builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); + builder.Services.AddScoped(); // Background services builder.Services.AddSingleton(); @@ -243,6 +245,7 @@ namespace Moonlight builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); // Other builder.Services.AddSingleton(); @@ -287,6 +290,7 @@ namespace Moonlight _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService(); + _ = app.Services.GetRequiredService(); _ = app.Services.GetRequiredService();