Implemented version fetching from source control git server. Added self version detection and update checks

This commit was merged in pull request #8.
This commit is contained in:
2026-02-01 14:47:32 +01:00
parent 76a8a72e83
commit c8fe11bd2b
11 changed files with 274 additions and 20 deletions

View File

@@ -1,26 +1,36 @@
using System.Diagnostics;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Moonlight.Api.Helpers;
namespace Moonlight.Api.Services;
public class ApplicationService : IHostedLifecycleService
public class ApplicationService : IHostedService
{
private readonly VersionService VersionService;
private readonly ILogger<ApplicationService> Logger;
public DateTimeOffset StartedAt { get; private set; }
public string VersionName { get; private set; } = "N/A";
public bool IsUpToDate { get; set; } = true;
public string OperatingSystem { get; private set; } = "N/A";
public ApplicationService(VersionService versionService, ILogger<ApplicationService> logger)
{
VersionService = versionService;
Logger = logger;
}
public Task<long> GetMemoryUsageAsync()
{
using var currentProcess = Process.GetCurrentProcess();
return Task.FromResult(currentProcess.WorkingSet64);
}
public async Task<double> GetCpuUsageAsync()
{
using var currentProcess = Process.GetCurrentProcess();
// Get initial values
var startCpuTime = currentProcess.TotalProcessorTime;
var startTime = DateTime.UtcNow;
@@ -39,26 +49,37 @@ public class ApplicationService : IHostedLifecycleService
return Math.Round(cpuUsagePercent, 2);
}
public async Task StartedAsync(CancellationToken cancellationToken)
public async Task StartAsync(CancellationToken cancellationToken)
{
StartedAt = DateTimeOffset.UtcNow;
// TODO: Update / version check
VersionName = "v2.1.0 (a2d4edc0e5)";
IsUpToDate = true;
OperatingSystem = OsHelper.GetName();
try
{
var currentVersion = await VersionService.GetInstanceVersionAsync();
var latestVersion = await VersionService.GetLatestVersionAsync();
VersionName = currentVersion.Identifier;
IsUpToDate = latestVersion == null || currentVersion.Identifier == latestVersion.Identifier;
Logger.LogInformation("Running Moonlight Panel {version} on {operatingSystem}", VersionName, OperatingSystem);
if (!IsUpToDate)
Logger.LogWarning("Your instance is not up-to-date");
if (currentVersion.IsDevelopment)
Logger.LogWarning("Your instance is running a development version");
if (currentVersion.IsPreRelease)
Logger.LogWarning("Your instance is running a pre-release version");
}
catch (Exception e)
{
Logger.LogError(e, "An unhandled exception occurred while fetching version details");
}
}
#region Unused
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StoppingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
#endregion
}

View File

@@ -0,0 +1,140 @@
using System.Text.Json.Nodes;
using System.Text.RegularExpressions;
using Microsoft.Extensions.Options;
using Moonlight.Api.Configuration;
using Moonlight.Api.Models;
namespace Moonlight.Api.Services;
public partial class VersionService
{
private readonly IOptions<VersionOptions> Options;
private readonly IHttpClientFactory HttpClientFactory;
private const string VersionPath = "/app/version";
private const string GiteaServer = "https://git.battlestati.one";
private const string GiteaRepository = "Moonlight-Panel/Moonlight";
[GeneratedRegex(@"^v(?!1(\.|$))\d+\.[A-Za-z0-9]+(\.[A-Za-z0-9]+)*$")]
private static partial Regex RegexFilter();
public VersionService(
IOptions<VersionOptions> options,
IHttpClientFactory httpClientFactory
)
{
Options = options;
HttpClientFactory = httpClientFactory;
}
public async Task<MoonlightVersion[]> GetVersionsAsync()
{
if (Options.Value.OfflineMode)
return [];
var versions = new List<MoonlightVersion>();
var httpClient = HttpClientFactory.CreateClient();
// Tags
const string tagsPath = $"{GiteaServer}/api/v1/repos/{GiteaRepository}/tags";
await using var tagsJsonStream = await httpClient.GetStreamAsync(tagsPath);
var tagsJson = await JsonNode.ParseAsync(tagsJsonStream);
if (tagsJson != null)
{
foreach (var node in tagsJson.AsArray())
{
if (node == null)
continue;
var name = node["name"]?.GetValue<string>() ?? "N/A";
var createdAt = node["createdAt"]?.GetValue<DateTimeOffset>() ?? DateTimeOffset.MinValue;
if(!RegexFilter().IsMatch(name))
continue;
versions.Add(new MoonlightVersion(
name,
name.EndsWith('b'),
false,
createdAt
));
}
}
// Branches
const string branchesPath = $"{GiteaServer}/api/v1/repos/{GiteaRepository}/branches";
await using var branchesJsonStream = await httpClient.GetStreamAsync(branchesPath);
var branchesJson = await JsonNode.ParseAsync(branchesJsonStream);
if (branchesJson != null)
{
foreach (var node in branchesJson.AsArray())
{
if (node == null)
continue;
var name = node["name"]?.GetValue<string>() ?? "N/A";
var commit = node["commit"];
if (commit == null)
continue;
var createdAt = commit["timestamp"]?.GetValue<DateTimeOffset>() ?? DateTimeOffset.MinValue;
if(!RegexFilter().IsMatch(name))
continue;
versions.Add(new MoonlightVersion(
name,
name.EndsWith('b'),
true,
createdAt
));
}
}
return versions.ToArray();
}
public async Task<MoonlightVersion> GetInstanceVersionAsync()
{
var knownVersions = await GetVersionsAsync();
string versionIdentifier;
if (!string.IsNullOrWhiteSpace(Options.Value.CurrentOverride))
versionIdentifier = Options.Value.CurrentOverride;
else
{
if (File.Exists(VersionPath))
versionIdentifier = await File.ReadAllTextAsync(VersionPath);
else
versionIdentifier = "unknown";
}
var version = knownVersions.FirstOrDefault(x => x.Identifier == versionIdentifier);
if (version != null)
return version;
return new MoonlightVersion(
versionIdentifier,
false,
false,
DateTimeOffset.UtcNow
);
}
public async Task<MoonlightVersion?> GetLatestVersionAsync()
{
var versions = await GetVersionsAsync();
return versions
.Where(x => x is { IsDevelopment: false, IsPreRelease: false })
.OrderByDescending(x => x.CreatedAt)
.FirstOrDefault();
}
}