finished diagnose system

This commit is contained in:
mxritzdev
2025-05-12 19:00:09 +02:00
parent bd8ea67017
commit a4e0175173
7 changed files with 155 additions and 14 deletions

View File

@@ -1,5 +1,12 @@
using System.IO.Compression;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging.Console;
using MoonCore.Attributes; 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.ApiServer.Services;
using Moonlight.Shared.Http.Responses.Admin.Sys; using Moonlight.Shared.Http.Responses.Admin.Sys;
@@ -10,10 +17,14 @@ namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
public class SystemController : Controller public class SystemController : Controller
{ {
private readonly ApplicationService ApplicationService; private readonly ApplicationService ApplicationService;
private readonly IEnumerable<IDiagnoseProvider> DiagnoseProviders;
private readonly DiagnoseService DiagnoseService;
public SystemController(ApplicationService applicationService) public SystemController(ApplicationService applicationService, IEnumerable<IDiagnoseProvider> diagnoseProviders, DiagnoseService diagnoseService)
{ {
ApplicationService = applicationService; ApplicationService = applicationService;
DiagnoseProviders = diagnoseProviders;
DiagnoseService = diagnoseService;
} }
[HttpGet] [HttpGet]
@@ -35,4 +46,15 @@ public class SystemController : Controller
{ {
await ApplicationService.Shutdown(); await ApplicationService.Shutdown();
} }
[HttpGet("diagnose")]
[RequirePermission("admin.system.diagnose")]
public async Task<IActionResult> Diagnose()
{
var stream = new MemoryStream();
await DiagnoseService.GenerateDiagnose(stream);
return File(stream, "application/zip", "diagnose.zip");
}
} }

View File

@@ -6,11 +6,15 @@ namespace Moonlight.ApiServer.Implementations.Diagnose;
public class CoreDiagnoseProvider : IDiagnoseProvider public class CoreDiagnoseProvider : IDiagnoseProvider
{ {
public async Task<DiagnoseEntry> GetFiles() public DiagnoseEntry[] GetFiles()
{ {
return new DiagnoseFile() return
[
new DiagnoseFile()
{ {
Name = "test.txt",
GetContent = () => Encoding.UTF8.GetBytes("hello world") GetContent = () => Encoding.UTF8.GetBytes("hello world")
}; }
];
} }
} }

View File

@@ -1,6 +0,0 @@
namespace Moonlight.ApiServer.Implementations.Diagnose;
public class TestProvider
{
}

View File

@@ -1,6 +1,8 @@
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Moonlight.ApiServer.Configuration; using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Database; using Moonlight.ApiServer.Database;
using Moonlight.ApiServer.Implementations.Diagnose;
using Moonlight.ApiServer.Interfaces;
using Moonlight.ApiServer.Interfaces.Startup; using Moonlight.ApiServer.Interfaces.Startup;
namespace Moonlight.ApiServer.Implementations.Startup; namespace Moonlight.ApiServer.Implementations.Startup;
@@ -50,6 +52,12 @@ public class CoreStartup : IPluginStartup
#endregion #endregion
#region Diagnose
builder.Services.AddSingleton<IDiagnoseProvider, CoreDiagnoseProvider>();
#endregion
return Task.CompletedTask; return Task.CompletedTask;
} }

View File

@@ -4,5 +4,5 @@ namespace Moonlight.ApiServer.Interfaces;
public interface IDiagnoseProvider public interface IDiagnoseProvider
{ {
public Task<DiagnoseEntry> GetFiles(); public DiagnoseEntry[] GetFiles();
} }

View File

@@ -2,7 +2,7 @@ namespace Moonlight.ApiServer.Models.Diagnose;
public abstract class DiagnoseEntry public abstract class DiagnoseEntry
{ {
public string Name { get; set; } = ""; public required string Name { get; set; } = "";
public abstract bool IsDirectory { get; } public abstract bool IsDirectory { get; }
} }

View File

@@ -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; namespace Moonlight.ApiServer.Services;
[Scoped]
public class DiagnoseService public class DiagnoseService
{ {
private readonly IEnumerable<IDiagnoseProvider> DiagnoseProviders;
public DiagnoseService(IEnumerable<IDiagnoseProvider> 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<Dictionary<string, byte[]>> ProcessDiagnoseEntry(string? path, DiagnoseEntry entry)
{
var fileEntries = new Dictionary<string, byte[]>();
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<Dictionary<string, byte[]>> ProcessDiagnoseDirectory(string? path, DiagnoseDirectory directory)
{
var result = new Dictionary<string, byte[]>();
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<KeyValuePair<string, byte[]>> ProcessDiagnoseFile(string? path, DiagnoseFile file)
{
var filePath = path != null ? string.Join("/", path, file.Name) : file.Name;
var bytes = file.GetContent();
return new KeyValuePair<string, byte[]>(filePath, bytes);
}
} }