From 255bfba9e34d6d84ebd6abc00aaec76fb84303b8 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Sat, 17 May 2025 19:38:36 +0200 Subject: [PATCH] Cleaned up diagnose system. Fixed smaller inconsistencies --- .../Admin/Sys/DiagnoseController.cs | 22 ++-- .../Diagnose/CoreConfigDiagnoseProvider.cs | 26 ++-- .../Diagnose/LogsDiagnoseProvider.cs | 20 ++- .../Services/DiagnoseService.cs | 75 ++++++----- .../UI/Views/Admin/Sys/Diagnose.razor | 117 ++++++++++-------- .../Admin/Sys/GenerateDiagnoseRequest.cs | 6 + .../Admin/Sys/DiagnoseProvideResponse.cs | 1 - 7 files changed, 153 insertions(+), 114 deletions(-) create mode 100644 Moonlight.Shared/Http/Requests/Admin/Sys/GenerateDiagnoseRequest.cs diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs index c541d877..94ae9d51 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs @@ -10,6 +10,7 @@ namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys; [ApiController] [Route("api/admin/system/diagnose")] +[RequirePermission("admin.system.diagnose")] public class DiagnoseController : Controller { private readonly DiagnoseService DiagnoseService; @@ -20,20 +21,21 @@ public class DiagnoseController : Controller } [HttpPost] - [RequirePermission("admin.system.diagnose")] - public async Task Diagnose([FromBody] string[]? requestedDiagnoseProviders = null) + public async Task Diagnose([FromBody] GenerateDiagnoseRequest request) { - var stream = new MemoryStream(); + var stream = await DiagnoseService.GenerateDiagnose(request.Providers); - await DiagnoseService.GenerateDiagnose(stream, requestedDiagnoseProviders); - - return File(stream, "application/zip", "diagnose.zip"); + await Results.Stream( + stream, + contentType: "application/zip", + fileDownloadName: "diagnose.zip" + ) + .ExecuteAsync(HttpContext); } - [HttpGet("available")] - [RequirePermission("admin.system.diagnose")] - public async Task GetAvailable() + [HttpGet("providers")] + public async Task GetProviders() { - return await DiagnoseService.GetAvailable(); + return await DiagnoseService.GetProviders(); } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs index e0b1480a..689148aa 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs @@ -24,28 +24,34 @@ public class CoreConfigDiagnoseProvider : IDiagnoseProvider public async Task ModifyZipArchive(ZipArchive archive) { - var json = JsonSerializer.Serialize(Config); - var config = JsonSerializer.Deserialize(json); + var config = JsonSerializer.Deserialize(json); if (config == null) { - await archive.AddText("core/config.txt","Could not fetch config."); - + await archive.AddText("core/config.txt", "Could not fetch config."); return; } - + config.Database.Password = CheckForNullOrEmpty(config.Database.Password); - + config.Authentication.OAuth2.ClientSecret = CheckForNullOrEmpty(config.Authentication.OAuth2.ClientSecret); - + config.Authentication.OAuth2.Secret = CheckForNullOrEmpty(config.Authentication.OAuth2.Secret); config.Authentication.Secret = CheckForNullOrEmpty(config.Authentication.Secret); - + config.Authentication.OAuth2.ClientId = CheckForNullOrEmpty(config.Authentication.OAuth2.ClientId); - await archive.AddText("core/config.txt", - JsonSerializer.Serialize(config, new JsonSerializerOptions() { WriteIndented = true })); + await archive.AddText( + "core/config.txt", + JsonSerializer.Serialize( + config, + new JsonSerializerOptions() + { + WriteIndented = true + } + ) + ); } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs index c731dd3b..0ef1e82b 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs @@ -1,6 +1,4 @@ using System.IO.Compression; -using System.Text; -using MoonCore.Helpers; using Moonlight.ApiServer.Extensions; using Moonlight.ApiServer.Interfaces; @@ -10,15 +8,15 @@ public class LogsDiagnoseProvider : IDiagnoseProvider { public async Task ModifyZipArchive(ZipArchive archive) { + var path = Path.Combine("storage", "logs", "latest.log"); - var logs = await File.ReadAllTextAsync(PathBuilder.File("storage", "logs", "latest.log")); - - if (string.IsNullOrEmpty(logs)) - { - await archive.AddText("logs.txt", "Could not read the logs"); - return; - } - - await archive.AddText("logs.txt", logs); + if (!File.Exists(path)) + { + await archive.AddText("logs.txt", "Logs file latest.log has not been found"); + return; + } + + var logsContent = await File.ReadAllTextAsync(path); + await archive.AddText("logs.txt", logsContent); } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs index 01a6b4ec..a5844b04 100644 --- a/Moonlight.ApiServer/Services/DiagnoseService.cs +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -1,6 +1,7 @@ using Moonlight.ApiServer.Interfaces; using System.IO.Compression; using MoonCore.Attributes; +using MoonCore.Exceptions; using Moonlight.Shared.Http.Responses.Admin.Sys; namespace Moonlight.ApiServer.Services; @@ -9,13 +10,18 @@ namespace Moonlight.ApiServer.Services; public class DiagnoseService { private readonly IEnumerable DiagnoseProviders; + private readonly ILogger Logger; - public DiagnoseService(IEnumerable diagnoseProviders) + public DiagnoseService( + IEnumerable diagnoseProviders, + ILogger logger + ) { DiagnoseProviders = diagnoseProviders; + Logger = logger; } - public async Task GetAvailable() + public Task GetProviders() { var availableProviders = new List(); @@ -26,55 +32,64 @@ public class DiagnoseService var type = diagnoseProvider.GetType().FullName; // The type name is null if the type is a generic type, unlikely, but still could happen - if (type != null) - availableProviders.Add(new DiagnoseProvideResponse() - { - Name = name, - Type = type - }); + if (type == null) + continue; + + availableProviders.Add(new DiagnoseProvideResponse() + { + Name = name, + Type = type + }); } - return availableProviders.ToArray(); + return Task.FromResult( + availableProviders.ToArray() + ); } - public async Task GenerateDiagnose(Stream outputStream, string[]? requestedProviders) + public async Task GenerateDiagnose(string[] requestedProviders) { IDiagnoseProvider[] providers; - - if (requestedProviders != null && requestedProviders.Length > 0) + + if (requestedProviders.Length == 0) + providers = DiagnoseProviders.ToArray(); + else { - var requesteDiagnoseProviders = new List(); + var foundProviders = new List(); foreach (var requestedProvider in requestedProviders) { var provider = DiagnoseProviders.FirstOrDefault(x => x.GetType().FullName == requestedProvider); - if (provider != null) - requesteDiagnoseProviders.Add(provider); + if (provider == null) + continue; + + foundProviders.Add(provider); } - providers = requesteDiagnoseProviders.ToArray(); - } - else - { - providers = DiagnoseProviders.ToArray(); + providers = foundProviders.ToArray(); } try { - using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true)) - { - foreach (var provider in providers) - { - await provider.ModifyZipArchive(zip); - } - } + var outputStream = new MemoryStream(); + var zipArchive = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true); - outputStream.Seek(0, SeekOrigin.Begin); + foreach (var provider in providers) + { + await provider.ModifyZipArchive(zipArchive); + } + + zipArchive.Dispose(); + + outputStream.Position = 0; + return outputStream; } - catch (Exception ex) + catch (Exception e) { - throw new Exception($"An unknown error occured while building the Diagnose: {ex.Message}"); + Logger.LogError("An unhandled error occured while generated the diagnose file: {e}", e); + + throw new HttpApiException("An unhandled error occured while generating the diagnose file", 500); } } } \ No newline at end of file diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor index aa35a00b..0a544f41 100644 --- a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor +++ b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor @@ -2,8 +2,8 @@ @using MoonCore.Attributes @using MoonCore.Helpers +@using Moonlight.Shared.Http.Requests.Admin.Sys @using Moonlight.Shared.Http.Responses.Admin.Sys -@using Moonlight.Shared.Misc @attribute [RequirePermission("admin.system.diagnose")] @@ -11,7 +11,7 @@ @inject DownloadService DownloadService
- +
@@ -22,27 +22,43 @@

If you're experiencing issues or need help via our Discord, you're in the right place here! - By pressing the button below, Moonlight will run all available diagnostic checks and package the results into a + By pressing the button below, Moonlight will run all available diagnostic checks and package the results + into a downloadable zip file. - The report includes useful information about your system, plugins, and environment, making it easier to identify problems or share with support. + The report includes useful information about your system, plugins, and environment, making it easier to + identify problems or share with support.

- + Generate diagnose - -
- Advanced + +
+ + Advanced + @if (DropdownOpen) + { + + } + else + { + + } + +
-
- +
+
- + @foreach (var item in AvailableProviders) {
- - + +
} @@ -54,54 +70,51 @@ @code { - - private async Task GenerateDiagnose(WButton _) - { - string[] payload = []; - - if (!SelectAll) - { - // filter the providers which have been selected if not all providers have been selected - payload = AvailableProviders - .Where(x => x.Value) - .Select(x => x.Key) - .Select(x => x.Type) - .ToArray(); - } - - var stream = await ApiClient.PostStream("api/admin/system/diagnose", payload); - - await DownloadService.DownloadStream("diagnose.zip", stream); - } - private bool DropdownOpen = false; - private bool AllSelected = true; private Dictionary AvailableProviders; - - private async Task ToggleDropDown() - { - DropdownOpen = !DropdownOpen; - - await InvokeAsync(StateHasChanged); - } - private async Task Load(LazyLoader arg) - { - AvailableProviders = (await ApiClient.GetJson("api/admin/system/diagnose/available")) - .ToDictionary(x => x, _ => true); - } - private bool SelectAll { get => AvailableProviders.Values.All(v => v); set { - // flip every entry to the new value - var keys = AvailableProviders.Keys.ToList(); - foreach (var k in keys) - { + foreach (var k in AvailableProviders.Keys) AvailableProviders[k] = value; - } } } + + private async Task Load(LazyLoader arg) + { + var providers = await ApiClient.GetJson( + "api/admin/system/diagnose/providers" + ); + + AvailableProviders = providers + .ToDictionary(x => x, _ => true); + } + + private async Task GenerateDiagnose(WButton _) + { + var request = new GenerateDiagnoseRequest(); + + if (!SelectAll) + { + // filter the providers which have been selected if not all providers have been selected + request.Providers = AvailableProviders + .Where(x => x.Value) + .Select(x => x.Key.Type) + .ToArray(); + } + + var stream = await ApiClient.PostStream("api/admin/system/diagnose", request); + + await DownloadService.DownloadStream("diagnose.zip", stream); + } + + + private async Task ToggleDropDown() + { + DropdownOpen = !DropdownOpen; + await InvokeAsync(StateHasChanged); + } } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/Admin/Sys/GenerateDiagnoseRequest.cs b/Moonlight.Shared/Http/Requests/Admin/Sys/GenerateDiagnoseRequest.cs new file mode 100644 index 00000000..3757ab8e --- /dev/null +++ b/Moonlight.Shared/Http/Requests/Admin/Sys/GenerateDiagnoseRequest.cs @@ -0,0 +1,6 @@ +namespace Moonlight.Shared.Http.Requests.Admin.Sys; + +public class GenerateDiagnoseRequest +{ + public string[] Providers { get; set; } = []; +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs b/Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs index e1882266..6a23a991 100644 --- a/Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs +++ b/Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs @@ -3,6 +3,5 @@ namespace Moonlight.Shared.Http.Responses.Admin.Sys; public class DiagnoseProvideResponse { public string Name { get; set; } - public string Type { get; set; } } \ No newline at end of file