Implemented system overview

This commit is contained in:
Masu Baumgartner
2024-11-08 14:49:49 +01:00
parent add4c3e99f
commit 764ebe3586
6 changed files with 174 additions and 19 deletions

View File

@@ -0,0 +1,38 @@
using Microsoft.AspNetCore.Mvc;
using MoonCore.Attributes;
using Moonlight.ApiServer.Services;
using Moonlight.Shared.Http.Responses.Admin.Sys;
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
[ApiController]
[Route("api/admin/system")]
public class SystemController : Controller
{
private readonly ApplicationService ApplicationService;
public SystemController(ApplicationService applicationService)
{
ApplicationService = applicationService;
}
[HttpGet]
[RequirePermission("admin.system.overview")]
public async Task<SystemOverviewResponse> GetOverview()
{
return new()
{
Uptime = await ApplicationService.GetUptime(),
CpuUsage = await ApplicationService.GetCpuUsage(),
MemoryUsage = await ApplicationService.GetMemoryUsage(),
OperatingSystem = await ApplicationService.GetOsName()
};
}
[HttpPost("shutdown")]
[RequirePermission("admin.system.shutdown")]
public async Task Shutdown()
{
await ApplicationService.Shutdown();
}
}

View File

@@ -0,0 +1,95 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using MoonCore.Attributes;
namespace Moonlight.ApiServer.Services;
[Singleton]
public class ApplicationService
{
private ILogger<ApplicationService> Logger;
private readonly IHost Host;
public ApplicationService(ILogger<ApplicationService> logger, IHost host)
{
Logger = logger;
Host = host;
}
public Task<string> GetOsName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Windows platform detected
var osVersion = Environment.OSVersion.Version;
return Task.FromResult($"Windows {osVersion.Major}.{osVersion.Minor}.{osVersion.Build}");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
var releaseRaw = File
.ReadAllLines("/etc/os-release")
.FirstOrDefault(x => x.StartsWith("PRETTY_NAME="));
if (string.IsNullOrEmpty(releaseRaw))
return Task.FromResult("Linux (unknown release)");
var release = releaseRaw
.Replace("PRETTY_NAME=", "")
.Replace("\"", "");
if(string.IsNullOrEmpty(release))
return Task.FromResult("Linux (unknown release)");
return Task.FromResult(release);
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
// macOS platform detected
var osVersion = Environment.OSVersion.Version;
return Task.FromResult($"macOS {osVersion.Major}.{osVersion.Minor}.{osVersion.Build}");
}
// Unknown platform
return Task.FromResult("N/A");
}
public Task<long> GetMemoryUsage()
{
var process = Process.GetCurrentProcess();
var bytes = process.PrivateMemorySize64;
return Task.FromResult(bytes);
}
public Task<TimeSpan> GetUptime()
{
var process = Process.GetCurrentProcess();
var uptime = DateTime.Now - process.StartTime;
return Task.FromResult(uptime);
}
public Task<int> GetCpuUsage()
{
var process = Process.GetCurrentProcess();
var cpuTime = process.TotalProcessorTime;
var wallClockTime = DateTime.UtcNow - process.StartTime.ToUniversalTime();
var cpuUsage = (int)(100.0 * cpuTime.TotalMilliseconds / wallClockTime.TotalMilliseconds / Environment.ProcessorCount);
return Task.FromResult(cpuUsage);
}
public Task Shutdown()
{
Logger.LogCritical("Restart of api server has been requested");
Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(1));
await Host.StopAsync(CancellationToken.None);
});
return Task.CompletedTask;
}
}

View File

@@ -288,9 +288,6 @@ public static class Startup
// TODO: Make modular
configuration.ProcessComplete = async (serviceProvider, accessData) =>
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("OAuth2 Handler");
var oauth2Providers = serviceProvider.GetRequiredService<IOAuth2Provider[]>();
// Find oauth2 provider
@@ -321,6 +318,9 @@ public static class Startup
}
catch (Exception e)
{
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger(provider.GetType());
logger.LogTrace("An error occured while syncing user with oauth2 provider: {e}", e);
throw new HttpApiException("Unable to synchronize with oauth2 provider", 400);
}

View File

@@ -58,7 +58,7 @@ public class DefaultSidebarItemProvider : ISidebarItemProvider
Path = "/admin/system",
Priority = 3,
RequiresExactMatch = false,
Permission = "admin.system.info"
Permission = "admin.system.overview"
},
];
}

View File

@@ -1,30 +1,43 @@
@page "/admin/system"
@using MoonCore.Attributes
@using MoonCore.Helpers
@using Moonlight.Client.UI.Components
@using Moonlight.Shared.Http.Responses.Admin.Sys
@attribute [RequirePermission("admin.system.read")]
@attribute [RequirePermission("admin.system.overview")]
<div class="gap-5 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
<StatCard Title="CPU Usage" Text="2%" Icon="bi bi-cpu"/>
<StatCard Title="Memory Usage" Text="71 MB" Icon="bi bi-memory"/>
<StatCard Title="Host OS" Text="Debian 12" Icon="bi bi-motherboard"/>
<StatCard Title="Uptime" Text="1d 5h 12h 3s" Icon="bi bi-clock-history"/>
<div class="card card-body">
<div class="flex justify-center">
<WButton OnClick="Restart" CssClasses="btn btn-danger w-full">
<i class="bi bi-arrow-repeat text-xl text-white me-2"></i>
Restart
</WButton>
@inject HttpApiClient ApiClient
<LazyLoader Load="LoadOverview">
<div class="gap-5 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
<StatCard Title="CPU Usage" Text="@(OverviewData.CpuUsage + "%")" Icon="bi bi-cpu"/>
<StatCard Title="Memory Usage" Text="@(Formatter.FormatSize(OverviewData.MemoryUsage))" Icon="bi bi-memory"/>
<StatCard Title="Host OS" Text="@(OverviewData.OperatingSystem)" Icon="bi bi-motherboard"/>
<StatCard Title="Uptime" Text="@(Formatter.FormatUptime(OverviewData.Uptime))" Icon="bi bi-clock-history"/>
<div class="card card-body">
<div class="flex justify-center">
<WButton OnClick="Restart" CssClasses="btn btn-danger w-full">
<i class="bi bi-arrow-repeat text-xl text-white me-2"></i>
Restart/Shutdown
</WButton>
</div>
</div>
</div>
</div>
</LazyLoader>
@code
{
private SystemOverviewResponse OverviewData;
private async Task LoadOverview(LazyLoader arg)
{
OverviewData = await ApiClient.GetJson<SystemOverviewResponse>("api/admin/system");
}
private async Task Restart(WButton _)
{
await ApiClient.Post("api/admin/system/shutdown");
}
}

View File

@@ -0,0 +1,9 @@
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
public class SystemOverviewResponse
{
public int CpuUsage { get; set; }
public long MemoryUsage { get; set; }
public string OperatingSystem { get; set; }
public TimeSpan Uptime { get; set; }
}