mirror of
https://github.com/gwdevhub/Daybreak.git
synced 2026-07-24 03:56:30 +00:00
123 lines
4.1 KiB
C#
123 lines
4.1 KiB
C#
using Daybreak.Configuration.Options;
|
|
using Daybreak.Shared.Services.ExecutableManagement;
|
|
using Daybreak.Shared.Services.Options;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
using System.Core.Extensions;
|
|
using System.Extensions;
|
|
|
|
namespace Daybreak.Services.ExecutableManagement;
|
|
|
|
internal sealed class GuildWarsExecutableManager(
|
|
IOptionsProvider optionsProvider,
|
|
IOptionsMonitor<GuildwarsExecutableOptions> liveUpdateableOptions,
|
|
ILogger<GuildWarsExecutableManager> logger) : IGuildWarsExecutableManager, IHostedService
|
|
{
|
|
private readonly static TimeSpan ExecutableVerificationLatency = TimeSpan.FromSeconds(5);
|
|
private readonly static SemaphoreSlim ExecutablesSemaphore = new(1, 1);
|
|
|
|
private readonly IOptionsProvider optionsProvider = optionsProvider.ThrowIfNull();
|
|
private readonly IOptionsMonitor<GuildwarsExecutableOptions> liveUpdateableOptions = liveUpdateableOptions.ThrowIfNull();
|
|
private readonly ILogger<GuildWarsExecutableManager> logger = logger.ThrowIfNull();
|
|
|
|
async Task IHostedService.StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
await this.VerifyExecutables(cancellationToken);
|
|
}
|
|
|
|
Task IHostedService.StopAsync(CancellationToken cancellationToken)
|
|
{
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public IEnumerable<string> GetExecutableList()
|
|
{
|
|
ExecutablesSemaphore.Wait();
|
|
|
|
var list = this.liveUpdateableOptions.CurrentValue.ExecutablePaths.Where(this.IsValidExecutable).ToList();
|
|
ExecutablesSemaphore.Release();
|
|
|
|
return list;
|
|
}
|
|
|
|
public void AddExecutable(string executablePath)
|
|
{
|
|
var fullPath = Path.GetFullPath(executablePath);
|
|
ExecutablesSemaphore.Wait();
|
|
|
|
var options = this.liveUpdateableOptions.CurrentValue;
|
|
var list = options.ExecutablePaths;
|
|
if (list.None(e => e == executablePath))
|
|
{
|
|
list.Insert(0, executablePath);
|
|
}
|
|
|
|
options.ExecutablePaths = list;
|
|
this.optionsProvider.SaveOption(options);
|
|
ExecutablesSemaphore.Release();
|
|
}
|
|
|
|
public void RemoveExecutable(string executablePath)
|
|
{
|
|
var fullPath = Path.GetFullPath(executablePath);
|
|
ExecutablesSemaphore.Wait();
|
|
|
|
var options = this.liveUpdateableOptions.CurrentValue;
|
|
var list = options.ExecutablePaths;
|
|
if (list.Any(e => e == executablePath))
|
|
{
|
|
list.Remove(executablePath);
|
|
}
|
|
|
|
options.ExecutablePaths = list;
|
|
this.optionsProvider.SaveOption(options);
|
|
ExecutablesSemaphore.Release();
|
|
}
|
|
|
|
public bool IsValidExecutable(string executablePath)
|
|
{
|
|
return IsValidExecutableInternal(executablePath);
|
|
}
|
|
|
|
private async Task VerifyExecutables(CancellationToken cancellationToken)
|
|
{
|
|
var scopedLogger = this.logger.CreateScopedLogger(nameof(this.VerifyExecutables), string.Empty);
|
|
while (!cancellationToken.IsCancellationRequested)
|
|
{
|
|
await ExecutablesSemaphore.WaitAsync(cancellationToken);
|
|
|
|
var executables = this.liveUpdateableOptions.CurrentValue.ExecutablePaths;
|
|
var deletedExecutable = false;
|
|
for (var i = 0; i < executables.Count; i++)
|
|
{
|
|
var executable = executables[i];
|
|
if (IsValidExecutableInternal(executable))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
scopedLogger.LogWarning($"Detected deleted executable at {executable}");
|
|
deletedExecutable = true;
|
|
executables.Remove(executable);
|
|
i--;
|
|
}
|
|
|
|
if (deletedExecutable)
|
|
{
|
|
var options = this.liveUpdateableOptions.CurrentValue;
|
|
options.ExecutablePaths = executables;
|
|
this.optionsProvider.SaveOption(options);
|
|
}
|
|
|
|
ExecutablesSemaphore.Release();
|
|
await Task.Delay(ExecutableVerificationLatency, cancellationToken);
|
|
}
|
|
}
|
|
|
|
private static bool IsValidExecutableInternal(string executablePath)
|
|
{
|
|
return File.Exists(executablePath);
|
|
}
|
|
}
|