Implemented system overview
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
95
Moonlight.ApiServer/Services/ApplicationService.cs
Normal file
95
Moonlight.ApiServer/Services/ApplicationService.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -288,9 +288,6 @@ public static class Startup
|
|||||||
// TODO: Make modular
|
// TODO: Make modular
|
||||||
configuration.ProcessComplete = async (serviceProvider, accessData) =>
|
configuration.ProcessComplete = async (serviceProvider, accessData) =>
|
||||||
{
|
{
|
||||||
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
|
|
||||||
var logger = loggerFactory.CreateLogger("OAuth2 Handler");
|
|
||||||
|
|
||||||
var oauth2Providers = serviceProvider.GetRequiredService<IOAuth2Provider[]>();
|
var oauth2Providers = serviceProvider.GetRequiredService<IOAuth2Provider[]>();
|
||||||
|
|
||||||
// Find oauth2 provider
|
// Find oauth2 provider
|
||||||
@@ -321,6 +318,9 @@ public static class Startup
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
logger.LogTrace("An error occured while syncing user with oauth2 provider: {e}", e);
|
||||||
throw new HttpApiException("Unable to synchronize with oauth2 provider", 400);
|
throw new HttpApiException("Unable to synchronize with oauth2 provider", 400);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class DefaultSidebarItemProvider : ISidebarItemProvider
|
|||||||
Path = "/admin/system",
|
Path = "/admin/system",
|
||||||
Priority = 3,
|
Priority = 3,
|
||||||
RequiresExactMatch = false,
|
RequiresExactMatch = false,
|
||||||
Permission = "admin.system.info"
|
Permission = "admin.system.overview"
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,43 @@
|
|||||||
@page "/admin/system"
|
@page "/admin/system"
|
||||||
|
|
||||||
@using MoonCore.Attributes
|
@using MoonCore.Attributes
|
||||||
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Client.UI.Components
|
@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">
|
@inject HttpApiClient ApiClient
|
||||||
<StatCard Title="CPU Usage" Text="2%" Icon="bi bi-cpu"/>
|
|
||||||
<StatCard Title="Memory Usage" Text="71 MB" Icon="bi bi-memory"/>
|
<LazyLoader Load="LoadOverview">
|
||||||
<StatCard Title="Host OS" Text="Debian 12" Icon="bi bi-motherboard"/>
|
<div class="gap-5 grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
|
||||||
<StatCard Title="Uptime" Text="1d 5h 12h 3s" Icon="bi bi-clock-history"/>
|
<StatCard Title="CPU Usage" Text="@(OverviewData.CpuUsage + "%")" Icon="bi bi-cpu"/>
|
||||||
|
<StatCard Title="Memory Usage" Text="@(Formatter.FormatSize(OverviewData.MemoryUsage))" Icon="bi bi-memory"/>
|
||||||
<div class="card card-body">
|
<StatCard Title="Host OS" Text="@(OverviewData.OperatingSystem)" Icon="bi bi-motherboard"/>
|
||||||
<div class="flex justify-center">
|
<StatCard Title="Uptime" Text="@(Formatter.FormatUptime(OverviewData.Uptime))" Icon="bi bi-clock-history"/>
|
||||||
<WButton OnClick="Restart" CssClasses="btn btn-danger w-full">
|
|
||||||
<i class="bi bi-arrow-repeat text-xl text-white me-2"></i>
|
<div class="card card-body">
|
||||||
Restart
|
<div class="flex justify-center">
|
||||||
</WButton>
|
<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>
|
</div>
|
||||||
</div>
|
</LazyLoader>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
private SystemOverviewResponse OverviewData;
|
||||||
|
|
||||||
|
private async Task LoadOverview(LazyLoader arg)
|
||||||
|
{
|
||||||
|
OverviewData = await ApiClient.GetJson<SystemOverviewResponse>("api/admin/system");
|
||||||
|
}
|
||||||
|
|
||||||
private async Task Restart(WButton _)
|
private async Task Restart(WButton _)
|
||||||
{
|
{
|
||||||
|
await ApiClient.Post("api/admin/system/shutdown");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user