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