From 8ac2d20d8a3d2246f6c6ce890c84b66cd29f7db0 Mon Sep 17 00:00:00 2001 From: moritz Date: Sun, 11 May 2025 13:03:44 +0200 Subject: [PATCH 01/14] added base diagnose, is not working, yet, still contains test objects --- Moonlight.ApiServer/Helpers/DiagnoseHelper.cs | 6 ++++++ .../Diagnose/CoreDiagnoseProvider.cs | 16 ++++++++++++++++ .../Implementations/Diagnose/TestProvider.cs | 6 ++++++ .../Interfaces/IDiagnoseProvider.cs | 8 ++++++++ .../Models/Diagnose/DiagnoseDirectory.cs | 7 +++++++ .../Models/Diagnose/DiagnoseEntry.cs | 8 ++++++++ .../Models/Diagnose/DiagnoseFile.cs | 8 ++++++++ 7 files changed, 59 insertions(+) create mode 100644 Moonlight.ApiServer/Helpers/DiagnoseHelper.cs create mode 100644 Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs create mode 100644 Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs create mode 100644 Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs create mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs create mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs create mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs diff --git a/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs b/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs new file mode 100644 index 00000000..5095e355 --- /dev/null +++ b/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs @@ -0,0 +1,6 @@ +namespace Moonlight.ApiServer.Helpers; + +public class DiagnoseHelper +{ + +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs new file mode 100644 index 00000000..479c8991 --- /dev/null +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs @@ -0,0 +1,16 @@ +using System.Text; +using Moonlight.ApiServer.Interfaces; +using Moonlight.ApiServer.Models.Diagnose; + +namespace Moonlight.ApiServer.Implementations.Diagnose; + +public class CoreDiagnoseProvider : IDiagnoseProvider +{ + public async Task GetFiles() + { + return new DiagnoseFile() + { + GetContent = () => Encoding.UTF8.GetBytes("hello world") + }; + } +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs new file mode 100644 index 00000000..2b6e4b7b --- /dev/null +++ b/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs @@ -0,0 +1,6 @@ +namespace Moonlight.ApiServer.Implementations.Diagnose; + +public class TestProvider +{ + +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs new file mode 100644 index 00000000..02ad81b7 --- /dev/null +++ b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs @@ -0,0 +1,8 @@ +using Moonlight.ApiServer.Models.Diagnose; + +namespace Moonlight.ApiServer.Interfaces; + +public interface IDiagnoseProvider +{ + public Task GetFiles(); +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs new file mode 100644 index 00000000..85bda05a --- /dev/null +++ b/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs @@ -0,0 +1,7 @@ +namespace Moonlight.ApiServer.Models.Diagnose; + +public class DiagnoseDirectory : DiagnoseEntry +{ + public List Children { get; set; } = new(); + public override bool IsDirectory => true; +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs new file mode 100644 index 00000000..96dc3439 --- /dev/null +++ b/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs @@ -0,0 +1,8 @@ +namespace Moonlight.ApiServer.Models.Diagnose; + +public abstract class DiagnoseEntry +{ + public string Name { get; set; } = ""; + + public abstract bool IsDirectory { get; } +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs new file mode 100644 index 00000000..dfeeb3aa --- /dev/null +++ b/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs @@ -0,0 +1,8 @@ +namespace Moonlight.ApiServer.Models.Diagnose; + +public class DiagnoseFile : DiagnoseEntry +{ + public Func GetContent = () => []; + + public override bool IsDirectory => false; +} \ No newline at end of file From bd8ea67017d5933bb89f3ada37174be54a30485f Mon Sep 17 00:00:00 2001 From: moritz Date: Mon, 12 May 2025 16:51:29 +0200 Subject: [PATCH 02/14] zip extracts now, still some issues with the ressource building --- Moonlight.ApiServer/Helpers/DiagnoseHelper.cs | 6 ------ Moonlight.ApiServer/Services/DiagnoseService.cs | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 Moonlight.ApiServer/Helpers/DiagnoseHelper.cs create mode 100644 Moonlight.ApiServer/Services/DiagnoseService.cs diff --git a/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs b/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs deleted file mode 100644 index 5095e355..00000000 --- a/Moonlight.ApiServer/Helpers/DiagnoseHelper.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Moonlight.ApiServer.Helpers; - -public class DiagnoseHelper -{ - -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs new file mode 100644 index 00000000..1abdeafa --- /dev/null +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -0,0 +1,6 @@ +namespace Moonlight.ApiServer.Services; + +public class DiagnoseService +{ + +} \ No newline at end of file From a4e0175173b026035fd25c88ea296e840ab5b566 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Mon, 12 May 2025 19:00:09 +0200 Subject: [PATCH 03/14] finished diagnose system --- .../Controllers/Admin/Sys/SystemController.cs | 24 +++- .../Diagnose/CoreDiagnoseProvider.cs | 14 ++- .../Implementations/Diagnose/TestProvider.cs | 6 - .../Implementations/Startup/CoreStartup.cs | 8 ++ .../Interfaces/IDiagnoseProvider.cs | 2 +- .../Models/Diagnose/DiagnoseEntry.cs | 2 +- .../Services/DiagnoseService.cs | 113 ++++++++++++++++++ 7 files changed, 155 insertions(+), 14 deletions(-) delete mode 100644 Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs index b0c9f8d2..faeef12f 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs @@ -1,5 +1,12 @@ +using System.IO.Compression; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging.Console; using MoonCore.Attributes; +using MoonCore.Exceptions; +using MoonCore.Helpers; +using Moonlight.ApiServer.Helpers; +using Moonlight.ApiServer.Interfaces; +using Moonlight.ApiServer.Models.Diagnose; using Moonlight.ApiServer.Services; using Moonlight.Shared.Http.Responses.Admin.Sys; @@ -10,10 +17,14 @@ namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys; public class SystemController : Controller { private readonly ApplicationService ApplicationService; + private readonly IEnumerable DiagnoseProviders; + private readonly DiagnoseService DiagnoseService; - public SystemController(ApplicationService applicationService) + public SystemController(ApplicationService applicationService, IEnumerable diagnoseProviders, DiagnoseService diagnoseService) { ApplicationService = applicationService; + DiagnoseProviders = diagnoseProviders; + DiagnoseService = diagnoseService; } [HttpGet] @@ -35,4 +46,15 @@ public class SystemController : Controller { await ApplicationService.Shutdown(); } + + [HttpGet("diagnose")] + [RequirePermission("admin.system.diagnose")] + public async Task Diagnose() + { + var stream = new MemoryStream(); + + await DiagnoseService.GenerateDiagnose(stream); + + return File(stream, "application/zip", "diagnose.zip"); + } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs index 479c8991..92d5d09a 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs @@ -6,11 +6,15 @@ namespace Moonlight.ApiServer.Implementations.Diagnose; public class CoreDiagnoseProvider : IDiagnoseProvider { - public async Task GetFiles() + public DiagnoseEntry[] GetFiles() { - return new DiagnoseFile() - { - GetContent = () => Encoding.UTF8.GetBytes("hello world") - }; + return + [ + new DiagnoseFile() + { + Name = "test.txt", + GetContent = () => Encoding.UTF8.GetBytes("hello world") + } + ]; } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs deleted file mode 100644 index 2b6e4b7b..00000000 --- a/Moonlight.ApiServer/Implementations/Diagnose/TestProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Moonlight.ApiServer.Implementations.Diagnose; - -public class TestProvider -{ - -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs b/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs index 6ca274db..19782349 100644 --- a/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs +++ b/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs @@ -1,6 +1,8 @@ using Microsoft.OpenApi.Models; using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Database; +using Moonlight.ApiServer.Implementations.Diagnose; +using Moonlight.ApiServer.Interfaces; using Moonlight.ApiServer.Interfaces.Startup; namespace Moonlight.ApiServer.Implementations.Startup; @@ -48,6 +50,12 @@ public class CoreStartup : IPluginStartup builder.Services.AddDbContext(); + #endregion + + #region Diagnose + + builder.Services.AddSingleton(); + #endregion return Task.CompletedTask; diff --git a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs index 02ad81b7..d2f1b95c 100644 --- a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs @@ -4,5 +4,5 @@ namespace Moonlight.ApiServer.Interfaces; public interface IDiagnoseProvider { - public Task GetFiles(); + public DiagnoseEntry[] GetFiles(); } \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs index 96dc3439..f83d4670 100644 --- a/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs +++ b/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs @@ -2,7 +2,7 @@ namespace Moonlight.ApiServer.Models.Diagnose; public abstract class DiagnoseEntry { - public string Name { get; set; } = ""; + public required string Name { get; set; } = ""; public abstract bool IsDirectory { get; } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs index 1abdeafa..3c4aca15 100644 --- a/Moonlight.ApiServer/Services/DiagnoseService.cs +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -1,6 +1,119 @@ +using MoonCore.Helpers; +using Moonlight.ApiServer.Interfaces; +using Moonlight.ApiServer.Models.Diagnose; +using System.IO.Compression; +using MoonCore.Attributes; + namespace Moonlight.ApiServer.Services; +[Scoped] public class DiagnoseService { + + private readonly IEnumerable DiagnoseProviders; + + public DiagnoseService(IEnumerable diagnoseProviders) + { + DiagnoseProviders = diagnoseProviders; + } + + public async Task GenerateDiagnose(Stream outputStream) + { + var tasks = DiagnoseProviders + .SelectMany(x => x.GetFiles()) + .Select(async x => await ProcessDiagnoseEntry(null, x)); + + + var fileEntries = (await Task.WhenAll(tasks)) + .SelectMany(x => x) + .ToDictionary(); + + + try + { + + using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true)) + { + foreach (var kv in fileEntries) + { + string entryName = kv.Key.Replace('\\', '/'); + byte[] data = kv.Value; + + // Optionally pick CompressionLevel.Optimal or NoCompression + var entry = zip.CreateEntry(entryName, CompressionLevel.Fastest); + + using (var entryStream = entry.Open()) + using (var ms = new MemoryStream(data)) + { + await ms.CopyToAsync(entryStream); + } + } + } + + outputStream.Seek(0, SeekOrigin.Begin); + } + catch (Exception ex) + { + throw new Exception($"An unknown error occured while building the Diagnose: {ex.Message}"); + } + } + private async Task> ProcessDiagnoseEntry(string? path, DiagnoseEntry entry) + { + var fileEntries = new Dictionary(); + + switch (entry) + { + case DiagnoseDirectory diagnoseDirectory: + { + var files = await ProcessDiagnoseDirectory(path, diagnoseDirectory); + + foreach (var file in files) + { + fileEntries.Add(file.Key, file.Value); + } + + break; + } + case DiagnoseFile diagnoseFile: + { + var file = await ProcessDiagnoseFile(path, diagnoseFile); + + fileEntries.Add(file.Key, file.Value); + + break; + } + } + + return fileEntries; + } + + private async Task> ProcessDiagnoseDirectory(string? path, DiagnoseDirectory directory) + { + var result = new Dictionary(); + + var directoryPath = path != null ? string.Join("/", path, directory.Name) : directory.Name; + + foreach (var entry in directory.Children) + { + var files = await ProcessDiagnoseEntry(directoryPath, entry); + + foreach (var file in files) + { + result.Add(file.Key, file.Value); + } + } + + return result; + } + + private async Task> ProcessDiagnoseFile(string? path, DiagnoseFile file) + { + + var filePath = path != null ? string.Join("/", path, file.Name) : file.Name; + + var bytes = file.GetContent(); + + return new KeyValuePair(filePath, bytes); + } } \ No newline at end of file From bc25210fe41777b6a01c1de622840d89bd3f3ff3 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Mon, 12 May 2025 19:36:27 +0200 Subject: [PATCH 04/14] added config to diagnose, while censoring sensitive data --- .../Diagnose/CoreDiagnoseProvider.cs | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs index 92d5d09a..53028d59 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs @@ -1,4 +1,7 @@ using System.Text; +using System.Text.Json; +using MoonCore.Helpers; +using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Interfaces; using Moonlight.ApiServer.Models.Diagnose; @@ -8,13 +11,58 @@ public class CoreDiagnoseProvider : IDiagnoseProvider { public DiagnoseEntry[] GetFiles() { + // TODO: + // - read logs out from file for the diagnose below + return [ - new DiagnoseFile() + new DiagnoseDirectory() { - Name = "test.txt", - GetContent = () => Encoding.UTF8.GetBytes("hello world") + Name = "core", + Children = [ + + new DiagnoseFile() + { + Name = "logs.txt", + GetContent = () => Encoding.UTF8.GetBytes("placeholder") + }, + + new DiagnoseFile() + { + Name = "logs.txt", + GetContent = () => + { + + var configJson = File.ReadAllText(PathBuilder.File("storage", "app.json")); + + var config = JsonSerializer.Deserialize(configJson); + + if (config == null) + { + return Encoding.UTF8.GetBytes("could not fetch config"); + } + + 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); + + return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(config)); + } + } + + ] } ]; } + + private string CheckForNullOrEmpty(string? content) + { + return string.IsNullOrEmpty(content) + ? "ISEMPTY" + : "ISNOTEMPTY"; + } } \ No newline at end of file From 753cb04dfe2f077900020e84995601615e93ad0c Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Tue, 13 May 2025 14:06:59 +0200 Subject: [PATCH 05/14] improved the config in the diagnose --- .../Diagnose/CoreDiagnoseProvider.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs index 53028d59..be89d2ee 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs @@ -9,6 +9,8 @@ namespace Moonlight.ApiServer.Implementations.Diagnose; public class CoreDiagnoseProvider : IDiagnoseProvider { + private readonly AppConfiguration Config; + public DiagnoseEntry[] GetFiles() { // TODO: @@ -29,19 +31,17 @@ public class CoreDiagnoseProvider : IDiagnoseProvider new DiagnoseFile() { - Name = "logs.txt", + Name = "config.txt", GetContent = () => { - - var configJson = File.ReadAllText(PathBuilder.File("storage", "app.json")); - - var config = JsonSerializer.Deserialize(configJson); + var json = JsonSerializer.Serialize(Config); + var config = JsonSerializer.Deserialize(json); if (config == null) { - return Encoding.UTF8.GetBytes("could not fetch config"); + return Encoding.UTF8.GetBytes("Could not fetch config."); } - + config.Database.Password = CheckForNullOrEmpty(config.Database.Password); config.Authentication.OAuth2.ClientSecret = CheckForNullOrEmpty(config.Authentication.OAuth2.ClientSecret); @@ -50,7 +50,7 @@ public class CoreDiagnoseProvider : IDiagnoseProvider config.Authentication.Secret = CheckForNullOrEmpty(config.Authentication.Secret); - return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(config)); + return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(config, new JsonSerializerOptions() { WriteIndented = true})); } } From ba736d2b19b62fe5543120c7285e505c9e511e54 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Tue, 13 May 2025 14:14:22 +0200 Subject: [PATCH 06/14] added file logging and log rotation --- Moonlight.ApiServer/Startup.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Moonlight.ApiServer/Startup.cs b/Moonlight.ApiServer/Startup.cs index baf2ee51..4e691bbb 100644 --- a/Moonlight.ApiServer/Startup.cs +++ b/Moonlight.ApiServer/Startup.cs @@ -123,6 +123,7 @@ public class Startup private Task CreateStorage() { Directory.CreateDirectory("storage"); + Directory.CreateDirectory(PathBuilder.Dir("storage", "logs")); Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins")); return Task.CompletedTask; @@ -426,7 +427,10 @@ public class Startup { configuration.Console.Enable = true; configuration.Console.EnableAnsiMode = true; - configuration.FileLogging.Enable = false; + configuration.FileLogging.Enable = true; + configuration.FileLogging.Path = PathBuilder.File("storage", "logs", "latest.log"); + configuration.FileLogging.EnableLogRotation = true; + configuration.FileLogging.RotateLogNameTemplate = PathBuilder.File("storage", "logs", "apiserver.{0}.log"); }); LoggerFactory = new LoggerFactory(); From 49848db96f1385d2a80c188ce358830541533990 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Tue, 13 May 2025 14:26:29 +0200 Subject: [PATCH 07/14] added logs to the diagnose --- .../Diagnose/CoreDiagnoseProvider.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs index be89d2ee..aff19bfd 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs @@ -10,12 +10,14 @@ namespace Moonlight.ApiServer.Implementations.Diagnose; public class CoreDiagnoseProvider : IDiagnoseProvider { private readonly AppConfiguration Config; - + + public CoreDiagnoseProvider(AppConfiguration config) + { + Config = config; + } + public DiagnoseEntry[] GetFiles() { - // TODO: - // - read logs out from file for the diagnose below - return [ new DiagnoseDirectory() @@ -26,7 +28,15 @@ public class CoreDiagnoseProvider : IDiagnoseProvider new DiagnoseFile() { Name = "logs.txt", - GetContent = () => Encoding.UTF8.GetBytes("placeholder") + GetContent = () => + { + var logs = File.ReadAllText(PathBuilder.File("storage", "logs", "latest.log")); + + if (string.IsNullOrEmpty(logs)) + return Encoding.UTF8.GetBytes("Could not get the latest logs."); + + return Encoding.UTF8.GetBytes(logs); + } }, new DiagnoseFile() From 0743bad93c96859f6a6873ce7b0f4485ddbb9c5a Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Tue, 13 May 2025 15:28:46 +0200 Subject: [PATCH 08/14] added ui for the diagnose system --- .../UI/Views/Admin/Sys/Diagnose.razor | 46 +++++++++++++++++++ Moonlight.Client/UiConstants.cs | 4 +- 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor new file mode 100644 index 00000000..079cf665 --- /dev/null +++ b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor @@ -0,0 +1,46 @@ +@page "/admin/system/diagnose" + +@using MoonCore.Attributes +@using MoonCore.Helpers + +@attribute [RequirePermission("admin.system.diagnose")] + +@inject HttpApiClient ApiClient +@inject DownloadService DownloadService + +
+ +
+ +
+
+
+ Diagnose +
+
+

+ 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 + downloadable zip file. + The report includes useful information about your system, plugins, and environment, making it easier to identify problems or share with support. +

+ + Generate diagnose +
+
+
+ +@code +{ + private async Task GenerateFrontend(WButton _) + { + var stream = await ApiClient.GetStream("api/admin/system/diagnose"); + + await DownloadService.DownloadStream("diagnose.zip", stream); + } +} + + +@code { + +} \ No newline at end of file diff --git a/Moonlight.Client/UiConstants.cs b/Moonlight.Client/UiConstants.cs index 9293cc7f..dce82611 100644 --- a/Moonlight.Client/UiConstants.cs +++ b/Moonlight.Client/UiConstants.cs @@ -4,12 +4,12 @@ public static class UiConstants { public static readonly string[] AdminNavNames = [ - "Overview", "Theme", "Files", "Hangfire", "Advanced" + "Overview", "Theme", "Files", "Hangfire", "Advanced", "Diagnose" ]; public static readonly string[] AdminNavLinks = [ "/admin/system", "/admin/system/theme", "/admin/system/files", "/admin/system/hangfire", - "/admin/system/advanced" + "/admin/system/advanced", "/admin/system/diagnose" ]; } \ No newline at end of file From 609a0297d590785b1a5ecf002879e54ac38ae16f Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Tue, 13 May 2025 17:22:47 +0200 Subject: [PATCH 09/14] moved diagnose to own controller, added advanced diagnose building, ui for advanced still missing --- .../Admin/Sys/DiagnoseController.cs | 44 ++++++++++++ .../Controllers/Admin/Sys/SystemController.cs | 16 +---- .../Services/DiagnoseService.cs | 71 +++++++++++++++---- .../UI/Views/Admin/Sys/Diagnose.razor | 43 +++++++++-- ...SystemAvailableDiagnoseProviderResponse.cs | 8 +++ Moonlight.Shared/Misc/DiagnoseProvider.cs | 8 +++ 6 files changed, 155 insertions(+), 35 deletions(-) create mode 100644 Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs create mode 100644 Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs create mode 100644 Moonlight.Shared/Misc/DiagnoseProvider.cs diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs new file mode 100644 index 00000000..b4ecd92c --- /dev/null +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs @@ -0,0 +1,44 @@ +using Microsoft.AspNetCore.Mvc; +using MoonCore.Attributes; +using Moonlight.ApiServer.Services; +using Moonlight.Shared.Http.Requests.Admin.Sys; +using Moonlight.Shared.Http.Responses.Admin.Sys; +using Moonlight.Shared.Misc; + + +namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys; + +[ApiController] +[Route("api/admin/system/diagnose")] +public class DiagnoseController : Controller +{ + private readonly DiagnoseService DiagnoseService; + + public DiagnoseController(DiagnoseService diagnoseService) + { + DiagnoseService = diagnoseService; + } + + [HttpPost] + [RequirePermission("admin.system.diagnose")] + public async Task Diagnose([FromBody] string[]? requestedDiagnoseProviders = null) + { + var stream = new MemoryStream(); + + await DiagnoseService.GenerateDiagnose(stream, requestedDiagnoseProviders); + + return File(stream, "application/zip", "diagnose.zip"); + } + + [HttpGet("available")] + [RequirePermission("admin.system.diagnose")] + public async Task GetAvailable() + { + var availableProviders = await DiagnoseService.GetAvailable(); + + return new SystemAvailableDiagnoseProviderResponse() + { + AvailableProviders = availableProviders + }; + } +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs index faeef12f..b2ad01ae 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs @@ -18,13 +18,12 @@ public class SystemController : Controller { private readonly ApplicationService ApplicationService; private readonly IEnumerable DiagnoseProviders; - private readonly DiagnoseService DiagnoseService; - public SystemController(ApplicationService applicationService, IEnumerable diagnoseProviders, DiagnoseService diagnoseService) + + public SystemController(ApplicationService applicationService, IEnumerable diagnoseProviders) { ApplicationService = applicationService; DiagnoseProviders = diagnoseProviders; - DiagnoseService = diagnoseService; } [HttpGet] @@ -46,15 +45,4 @@ public class SystemController : Controller { await ApplicationService.Shutdown(); } - - [HttpGet("diagnose")] - [RequirePermission("admin.system.diagnose")] - public async Task Diagnose() - { - var stream = new MemoryStream(); - - await DiagnoseService.GenerateDiagnose(stream); - - return File(stream, "application/zip", "diagnose.zip"); - } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs index 3c4aca15..5d3024af 100644 --- a/Moonlight.ApiServer/Services/DiagnoseService.cs +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -3,13 +3,14 @@ using Moonlight.ApiServer.Interfaces; using Moonlight.ApiServer.Models.Diagnose; using System.IO.Compression; using MoonCore.Attributes; +using Moonlight.Shared.Http.Responses.Admin.Sys; +using Moonlight.Shared.Misc; namespace Moonlight.ApiServer.Services; [Scoped] public class DiagnoseService { - private readonly IEnumerable DiagnoseProviders; public DiagnoseService(IEnumerable diagnoseProviders) @@ -17,21 +18,62 @@ public class DiagnoseService DiagnoseProviders = diagnoseProviders; } - public async Task GenerateDiagnose(Stream outputStream) + public async Task GetAvailable() { - var tasks = DiagnoseProviders + var availableProviders = new List(); + + foreach (var diagnoseProvider in DiagnoseProviders) + { + var name = diagnoseProvider.GetType().Name; + + 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 DiagnoseProvider() + { + Name = name, + Type = type + }); + } + + return availableProviders.ToArray(); + } + + public async Task GenerateDiagnose(Stream outputStream, string[]? requestedProviders) + { + List providers; + + if (requestedProviders != null && requestedProviders.Length > 0) + { + providers = new List(); + + foreach (var requestedProvider in requestedProviders) + { + var provider = DiagnoseProviders.FirstOrDefault(x => x.GetType().FullName == requestedProvider); + + if (provider != null) + providers.Add(provider); + } + } + else + { + providers = DiagnoseProviders.ToList(); + } + + + var tasks = providers .SelectMany(x => x.GetFiles()) .Select(async x => await ProcessDiagnoseEntry(null, x)); - + var fileEntries = (await Task.WhenAll(tasks)) .SelectMany(x => x) .ToDictionary(); - + try { - using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true)) { foreach (var kv in fileEntries) @@ -57,11 +99,11 @@ public class DiagnoseService throw new Exception($"An unknown error occured while building the Diagnose: {ex.Message}"); } } - + private async Task> ProcessDiagnoseEntry(string? path, DiagnoseEntry entry) { var fileEntries = new Dictionary(); - + switch (entry) { case DiagnoseDirectory diagnoseDirectory: @@ -80,20 +122,20 @@ public class DiagnoseService var file = await ProcessDiagnoseFile(path, diagnoseFile); fileEntries.Add(file.Key, file.Value); - + break; } } return fileEntries; } - + private async Task> ProcessDiagnoseDirectory(string? path, DiagnoseDirectory directory) { var result = new Dictionary(); - var directoryPath = path != null ? string.Join("/", path, directory.Name) : directory.Name; - + var directoryPath = path != null ? string.Join("/", path, directory.Name) : directory.Name; + foreach (var entry in directory.Children) { var files = await ProcessDiagnoseEntry(directoryPath, entry); @@ -103,14 +145,13 @@ public class DiagnoseService result.Add(file.Key, file.Value); } } - + return result; } private async Task> ProcessDiagnoseFile(string? path, DiagnoseFile file) { - - var filePath = path != null ? string.Join("/", path, file.Name) : file.Name; + var filePath = path != null ? string.Join("/", path, file.Name) : file.Name; var bytes = file.GetContent(); diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor index 079cf665..596da604 100644 --- a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor +++ b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor @@ -2,6 +2,8 @@ @using MoonCore.Attributes @using MoonCore.Helpers +@using Moonlight.Shared.Http.Responses.Admin.Sys +@using Moonlight.Shared.Misc @attribute [RequirePermission("admin.system.diagnose")] @@ -25,22 +27,51 @@ The report includes useful information about your system, plugins, and environment, making it easier to identify problems or share with support.

- Generate diagnose + Generate diagnose + + @*
*@ + @* Advanced *@ + @* *@ + @*
*@ + @* *@ + @* *@ + @* *@ + @* *@ + @* @for (int i = 0; i < AvailableProviders.Length; i++) *@ + @* { *@ + @*
*@ + @* @Formatter.ConvertCamelCaseToSpaces(AvailableProviders[i].Name) *@ + @*
*@ + @* } *@ + @* *@ + @*
*@ + @* *@ + @* *@ + @*
*@ + @* *@ + @*
*@ @code { - private async Task GenerateFrontend(WButton _) - { - var stream = await ApiClient.GetStream("api/admin/system/diagnose"); + private async Task GenerateDiagnose(WButton _) + { + var stream = await ApiClient.PostStream("api/admin/system/diagnose"); + await DownloadService.DownloadStream("diagnose.zip", stream); } -} + + private async Task Load(LazyLoader arg) + { + // AvailableProviders = (await ApiClient.GetJson("api/admin/system/diagnose/available")).AvailableProviders; + } + + + -@code { } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs b/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs new file mode 100644 index 00000000..a32fe302 --- /dev/null +++ b/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs @@ -0,0 +1,8 @@ +using Moonlight.Shared.Misc; + +namespace Moonlight.Shared.Http.Responses.Admin.Sys; + +public class SystemAvailableDiagnoseProviderResponse +{ + public DiagnoseProvider[] AvailableProviders { get; set; }= []; +} diff --git a/Moonlight.Shared/Misc/DiagnoseProvider.cs b/Moonlight.Shared/Misc/DiagnoseProvider.cs new file mode 100644 index 00000000..dd552700 --- /dev/null +++ b/Moonlight.Shared/Misc/DiagnoseProvider.cs @@ -0,0 +1,8 @@ +namespace Moonlight.Shared.Misc; + +public class DiagnoseProvider +{ + public string Name { get; set; } + + public string Type { get; set; } +} \ No newline at end of file From ebc1b9441ecc52edfd595904f275bc832fda94d5 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Wed, 14 May 2025 20:13:24 +0200 Subject: [PATCH 10/14] changed the diagnose to be easier to use --- .../Extensions/ZipArchiveExtensions.cs | 33 ++++++ .../Admin/Sys/DiagnoseController.cs | 9 +- .../Diagnose/CoreConfigDiagnoseProvider.cs | 52 +++++++++ .../Diagnose/CoreDiagnoseProvider.cs | 78 -------------- .../Diagnose/LogsDiagnoseProvider.cs | 24 +++++ .../Implementations/Startup/CoreStartup.cs | 3 +- .../Interfaces/IDiagnoseProvider.cs | 3 +- .../Services/DiagnoseService.cs | 100 +++--------------- .../UI/Views/Admin/Sys/Diagnose.razor | 86 ++++++++++----- .../Admin/Sys/DiagnoseProvideResponse.cs | 8 ++ ...SystemAvailableDiagnoseProviderResponse.cs | 8 -- Moonlight.Shared/Misc/DiagnoseProvider.cs | 8 -- 12 files changed, 193 insertions(+), 219 deletions(-) create mode 100644 Moonlight.ApiServer/Extensions/ZipArchiveExtensions.cs create mode 100644 Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs delete mode 100644 Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs create mode 100644 Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs create mode 100644 Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs delete mode 100644 Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs delete mode 100644 Moonlight.Shared/Misc/DiagnoseProvider.cs diff --git a/Moonlight.ApiServer/Extensions/ZipArchiveExtensions.cs b/Moonlight.ApiServer/Extensions/ZipArchiveExtensions.cs new file mode 100644 index 00000000..95c928d7 --- /dev/null +++ b/Moonlight.ApiServer/Extensions/ZipArchiveExtensions.cs @@ -0,0 +1,33 @@ +using System.IO.Compression; +using System.Text; + +namespace Moonlight.ApiServer.Extensions; + +public static class ZipArchiveExtensions +{ + public static async Task AddBinary(this ZipArchive archive, string name, byte[] bytes) + { + var entry = archive.CreateEntry(name); + await using var dataStream = entry.Open(); + + await dataStream.WriteAsync(bytes); + await dataStream.FlushAsync(); + } + + public static async Task AddText(this ZipArchive archive, string name, string content) + { + var data = Encoding.UTF8.GetBytes(content); + await archive.AddBinary(name, data); + } + + public static async Task AddFile(this ZipArchive archive, string name, string path) + { + var fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + var entry = archive.CreateEntry(name); + await using var dataStream = entry.Open(); + + await fs.CopyToAsync(dataStream); + await dataStream.FlushAsync(); + } +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs index b4ecd92c..c541d877 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/DiagnoseController.cs @@ -32,13 +32,8 @@ public class DiagnoseController : Controller [HttpGet("available")] [RequirePermission("admin.system.diagnose")] - public async Task GetAvailable() + public async Task GetAvailable() { - var availableProviders = await DiagnoseService.GetAvailable(); - - return new SystemAvailableDiagnoseProviderResponse() - { - AvailableProviders = availableProviders - }; + return await DiagnoseService.GetAvailable(); } } \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs new file mode 100644 index 00000000..b1c8d3f8 --- /dev/null +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs @@ -0,0 +1,52 @@ +using System.IO.Compression; +using System.Text; +using System.Text.Json; +using MoonCore.Helpers; +using Moonlight.ApiServer.Configuration; +using Moonlight.ApiServer.Extensions; +using Moonlight.ApiServer.Interfaces; +using Moonlight.ApiServer.Models.Diagnose; + +namespace Moonlight.ApiServer.Implementations.Diagnose; + +public class CoreConfigDiagnoseProvider : IDiagnoseProvider +{ + private readonly AppConfiguration Config; + + public CoreConfigDiagnoseProvider(AppConfiguration config) + { + Config = config; + } + + private string CheckForNullOrEmpty(string? content) + { + return string.IsNullOrEmpty(content) + ? "ISEMPTY" + : "ISNOTEMPTY"; + } + + public async Task ModifyZipArchive(ZipArchive archive) + { + + var json = JsonSerializer.Serialize(Config); + var config = JsonSerializer.Deserialize(json); + + if (config == null) + { + 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); + + 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/CoreDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs deleted file mode 100644 index aff19bfd..00000000 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreDiagnoseProvider.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Text; -using System.Text.Json; -using MoonCore.Helpers; -using Moonlight.ApiServer.Configuration; -using Moonlight.ApiServer.Interfaces; -using Moonlight.ApiServer.Models.Diagnose; - -namespace Moonlight.ApiServer.Implementations.Diagnose; - -public class CoreDiagnoseProvider : IDiagnoseProvider -{ - private readonly AppConfiguration Config; - - public CoreDiagnoseProvider(AppConfiguration config) - { - Config = config; - } - - public DiagnoseEntry[] GetFiles() - { - return - [ - new DiagnoseDirectory() - { - Name = "core", - Children = [ - - new DiagnoseFile() - { - Name = "logs.txt", - GetContent = () => - { - var logs = File.ReadAllText(PathBuilder.File("storage", "logs", "latest.log")); - - if (string.IsNullOrEmpty(logs)) - return Encoding.UTF8.GetBytes("Could not get the latest logs."); - - return Encoding.UTF8.GetBytes(logs); - } - }, - - new DiagnoseFile() - { - Name = "config.txt", - GetContent = () => - { - var json = JsonSerializer.Serialize(Config); - var config = JsonSerializer.Deserialize(json); - - if (config == null) - { - return Encoding.UTF8.GetBytes("Could not fetch config."); - } - - 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); - - return Encoding.UTF8.GetBytes(JsonSerializer.Serialize(config, new JsonSerializerOptions() { WriteIndented = true})); - } - } - - ] - } - ]; - } - - private string CheckForNullOrEmpty(string? content) - { - return string.IsNullOrEmpty(content) - ? "ISEMPTY" - : "ISNOTEMPTY"; - } -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs new file mode 100644 index 00000000..c731dd3b --- /dev/null +++ b/Moonlight.ApiServer/Implementations/Diagnose/LogsDiagnoseProvider.cs @@ -0,0 +1,24 @@ +using System.IO.Compression; +using System.Text; +using MoonCore.Helpers; +using Moonlight.ApiServer.Extensions; +using Moonlight.ApiServer.Interfaces; + +namespace Moonlight.ApiServer.Implementations.Diagnose; + +public class LogsDiagnoseProvider : IDiagnoseProvider +{ + public async Task ModifyZipArchive(ZipArchive archive) + { + + 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); + } +} \ No newline at end of file diff --git a/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs b/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs index 19782349..14324f0d 100644 --- a/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs +++ b/Moonlight.ApiServer/Implementations/Startup/CoreStartup.cs @@ -54,7 +54,8 @@ public class CoreStartup : IPluginStartup #region Diagnose - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); #endregion diff --git a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs index d2f1b95c..daf6d875 100644 --- a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs @@ -1,8 +1,9 @@ +using System.IO.Compression; using Moonlight.ApiServer.Models.Diagnose; namespace Moonlight.ApiServer.Interfaces; public interface IDiagnoseProvider { - public DiagnoseEntry[] GetFiles(); + public Task ModifyZipArchive(ZipArchive archive); } \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs index 5d3024af..635a3a1a 100644 --- a/Moonlight.ApiServer/Services/DiagnoseService.cs +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -2,6 +2,7 @@ using MoonCore.Helpers; using Moonlight.ApiServer.Interfaces; using Moonlight.ApiServer.Models.Diagnose; using System.IO.Compression; +using System.Text; using MoonCore.Attributes; using Moonlight.Shared.Http.Responses.Admin.Sys; using Moonlight.Shared.Misc; @@ -18,9 +19,9 @@ public class DiagnoseService DiagnoseProviders = diagnoseProviders; } - public async Task GetAvailable() + public async Task GetAvailable() { - var availableProviders = new List(); + var availableProviders = new List(); foreach (var diagnoseProvider in DiagnoseProviders) { @@ -30,7 +31,7 @@ public class DiagnoseService // The type name is null if the type is a generic type, unlikely, but still could happen if (type != null) - availableProviders.Add(new DiagnoseProvider() + availableProviders.Add(new DiagnoseProvideResponse() { Name = name, Type = type @@ -42,53 +43,34 @@ public class DiagnoseService public async Task GenerateDiagnose(Stream outputStream, string[]? requestedProviders) { - List providers; + IDiagnoseProvider[] providers; if (requestedProviders != null && requestedProviders.Length > 0) { - providers = new List(); + var requesteDiagnoseProviders = new List(); foreach (var requestedProvider in requestedProviders) { var provider = DiagnoseProviders.FirstOrDefault(x => x.GetType().FullName == requestedProvider); if (provider != null) - providers.Add(provider); + requesteDiagnoseProviders.Add(provider); } + + providers = requesteDiagnoseProviders.ToArray(); } else { - providers = DiagnoseProviders.ToList(); + providers = DiagnoseProviders.ToArray(); } - - var tasks = providers - .SelectMany(x => x.GetFiles()) - .Select(async x => await ProcessDiagnoseEntry(null, x)); - - - var fileEntries = (await Task.WhenAll(tasks)) - .SelectMany(x => x) - .ToDictionary(); - - try { using (var zip = new ZipArchive(outputStream, ZipArchiveMode.Create, leaveOpen: true)) { - foreach (var kv in fileEntries) + foreach (var provider in providers) { - string entryName = kv.Key.Replace('\\', '/'); - byte[] data = kv.Value; - - // Optionally pick CompressionLevel.Optimal or NoCompression - var entry = zip.CreateEntry(entryName, CompressionLevel.Fastest); - - using (var entryStream = entry.Open()) - using (var ms = new MemoryStream(data)) - { - await ms.CopyToAsync(entryStream); - } + await provider.ModifyZipArchive(zip); } } @@ -99,62 +81,4 @@ public class DiagnoseService throw new Exception($"An unknown error occured while building the Diagnose: {ex.Message}"); } } - - private async Task> ProcessDiagnoseEntry(string? path, DiagnoseEntry entry) - { - var fileEntries = new Dictionary(); - - switch (entry) - { - case DiagnoseDirectory diagnoseDirectory: - { - var files = await ProcessDiagnoseDirectory(path, diagnoseDirectory); - - foreach (var file in files) - { - fileEntries.Add(file.Key, file.Value); - } - - break; - } - case DiagnoseFile diagnoseFile: - { - var file = await ProcessDiagnoseFile(path, diagnoseFile); - - fileEntries.Add(file.Key, file.Value); - - break; - } - } - - return fileEntries; - } - - private async Task> ProcessDiagnoseDirectory(string? path, DiagnoseDirectory directory) - { - var result = new Dictionary(); - - var directoryPath = path != null ? string.Join("/", path, directory.Name) : directory.Name; - - foreach (var entry in directory.Children) - { - var files = await ProcessDiagnoseEntry(directoryPath, entry); - - foreach (var file in files) - { - result.Add(file.Key, file.Value); - } - } - - return result; - } - - private async Task> ProcessDiagnoseFile(string? path, DiagnoseFile file) - { - var filePath = path != null ? string.Join("/", path, file.Name) : file.Name; - - var bytes = file.GetContent(); - - return new KeyValuePair(filePath, bytes); - } } \ 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 596da604..8b84853b 100644 --- a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor +++ b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor @@ -29,27 +29,25 @@ Generate diagnose - @*
*@ - @* Advanced *@ - @* *@ - @*
*@ - @* *@ - @* *@ - @* *@ - @* *@ - @* @for (int i = 0; i < AvailableProviders.Length; i++) *@ - @* { *@ - @*
*@ - @* @Formatter.ConvertCamelCaseToSpaces(AvailableProviders[i].Name) *@ - @*
*@ - @* } *@ - @* *@ - @*
*@ - @* *@ - @* *@ - @*
*@ - @* *@ - @*
*@ +
+ Advanced +
+ +
+ + +
+ + @foreach (var item in AvailableProviders) + { +
+ + +
+ } +
+
+
@@ -59,19 +57,51 @@ private async Task GenerateDiagnose(WButton _) { - var stream = await ApiClient.PostStream("api/admin/system/diagnose"); + 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 async Task Load(LazyLoader arg) + private bool DropdownOpen = false; + private bool AllSelected = true; + private Dictionary AvailableProviders; + + private async Task ToggleDropDown() { - // AvailableProviders = (await ApiClient.GetJson("api/admin/system/diagnose/available")).AvailableProviders; + 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) + { + AvailableProviders[k] = value; + } + } + } } \ 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 new file mode 100644 index 00000000..e1882266 --- /dev/null +++ b/Moonlight.Shared/Http/Responses/Admin/Sys/DiagnoseProvideResponse.cs @@ -0,0 +1,8 @@ +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 diff --git a/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs b/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs deleted file mode 100644 index a32fe302..00000000 --- a/Moonlight.Shared/Http/Responses/Admin/Sys/SystemAvailableDiagnoseProviderResponse.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Moonlight.Shared.Misc; - -namespace Moonlight.Shared.Http.Responses.Admin.Sys; - -public class SystemAvailableDiagnoseProviderResponse -{ - public DiagnoseProvider[] AvailableProviders { get; set; }= []; -} diff --git a/Moonlight.Shared/Misc/DiagnoseProvider.cs b/Moonlight.Shared/Misc/DiagnoseProvider.cs deleted file mode 100644 index dd552700..00000000 --- a/Moonlight.Shared/Misc/DiagnoseProvider.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Moonlight.Shared.Misc; - -public class DiagnoseProvider -{ - public string Name { get; set; } - - public string Type { get; set; } -} \ No newline at end of file From c49b0005215d21aad0aa11d771a972d9eb63e83a Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Wed, 14 May 2025 20:15:07 +0200 Subject: [PATCH 11/14] Used CamelCase Formatter in Diagnose ui --- Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor index 8b84853b..aa35a00b 100644 --- a/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor +++ b/Moonlight.Client/UI/Views/Admin/Sys/Diagnose.razor @@ -42,7 +42,7 @@ {
- +
} From eab03d7f5af1b262453112cd90cf4bf122893a30 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Thu, 15 May 2025 14:09:16 +0200 Subject: [PATCH 12/14] cleaned up diagnose feature --- .../Http/Controllers/Admin/Sys/SystemController.cs | 6 ------ .../Diagnose/CoreConfigDiagnoseProvider.cs | 3 --- Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs | 1 - Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs | 7 ------- Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs | 8 -------- Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs | 8 -------- Moonlight.ApiServer/Services/DiagnoseService.cs | 4 ---- 7 files changed, 37 deletions(-) delete mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs delete mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs delete mode 100644 Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs diff --git a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs index b2ad01ae..e69efc8f 100644 --- a/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs +++ b/Moonlight.ApiServer/Http/Controllers/Admin/Sys/SystemController.cs @@ -1,12 +1,6 @@ -using System.IO.Compression; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Logging.Console; using MoonCore.Attributes; -using MoonCore.Exceptions; -using MoonCore.Helpers; -using Moonlight.ApiServer.Helpers; using Moonlight.ApiServer.Interfaces; -using Moonlight.ApiServer.Models.Diagnose; using Moonlight.ApiServer.Services; using Moonlight.Shared.Http.Responses.Admin.Sys; diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs index b1c8d3f8..29275823 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs @@ -1,11 +1,8 @@ using System.IO.Compression; -using System.Text; using System.Text.Json; -using MoonCore.Helpers; using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Extensions; using Moonlight.ApiServer.Interfaces; -using Moonlight.ApiServer.Models.Diagnose; namespace Moonlight.ApiServer.Implementations.Diagnose; diff --git a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs index daf6d875..5a4a9cf2 100644 --- a/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Interfaces/IDiagnoseProvider.cs @@ -1,5 +1,4 @@ using System.IO.Compression; -using Moonlight.ApiServer.Models.Diagnose; namespace Moonlight.ApiServer.Interfaces; diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs deleted file mode 100644 index 85bda05a..00000000 --- a/Moonlight.ApiServer/Models/Diagnose/DiagnoseDirectory.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Moonlight.ApiServer.Models.Diagnose; - -public class DiagnoseDirectory : DiagnoseEntry -{ - public List Children { get; set; } = new(); - public override bool IsDirectory => true; -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs deleted file mode 100644 index f83d4670..00000000 --- a/Moonlight.ApiServer/Models/Diagnose/DiagnoseEntry.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Moonlight.ApiServer.Models.Diagnose; - -public abstract class DiagnoseEntry -{ - public required string Name { get; set; } = ""; - - public abstract bool IsDirectory { get; } -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs b/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs deleted file mode 100644 index dfeeb3aa..00000000 --- a/Moonlight.ApiServer/Models/Diagnose/DiagnoseFile.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Moonlight.ApiServer.Models.Diagnose; - -public class DiagnoseFile : DiagnoseEntry -{ - public Func GetContent = () => []; - - public override bool IsDirectory => false; -} \ No newline at end of file diff --git a/Moonlight.ApiServer/Services/DiagnoseService.cs b/Moonlight.ApiServer/Services/DiagnoseService.cs index 635a3a1a..01a6b4ec 100644 --- a/Moonlight.ApiServer/Services/DiagnoseService.cs +++ b/Moonlight.ApiServer/Services/DiagnoseService.cs @@ -1,11 +1,7 @@ -using MoonCore.Helpers; using Moonlight.ApiServer.Interfaces; -using Moonlight.ApiServer.Models.Diagnose; using System.IO.Compression; -using System.Text; using MoonCore.Attributes; using Moonlight.Shared.Http.Responses.Admin.Sys; -using Moonlight.Shared.Misc; namespace Moonlight.ApiServer.Services; From f87e4a08008af4f6a6dc434230ff0f8841403555 Mon Sep 17 00:00:00 2001 From: mxritzdev Date: Thu, 15 May 2025 14:15:44 +0200 Subject: [PATCH 13/14] censored client id config diagnose --- .../Implementations/Diagnose/CoreConfigDiagnoseProvider.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs index 29275823..e0b1480a 100644 --- a/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs +++ b/Moonlight.ApiServer/Implementations/Diagnose/CoreConfigDiagnoseProvider.cs @@ -42,6 +42,8 @@ public class CoreConfigDiagnoseProvider : IDiagnoseProvider 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 })); From 255bfba9e34d6d84ebd6abc00aaec76fb84303b8 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Sat, 17 May 2025 19:38:36 +0200 Subject: [PATCH 14/14] 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