Recreated plugin with new project template. Started implementing server system daemon
This commit is contained in:
@@ -1,161 +1,111 @@
|
||||
using MoonlightServers.Daemon.ServerSystem.Enums;
|
||||
using MoonlightServers.Daemon.ServerSystem.Interfaces;
|
||||
using MoonlightServers.Daemon.ServerSystem.Models;
|
||||
using Stateless;
|
||||
using MoonlightServers.Daemon.Models;
|
||||
using MoonlightServers.Daemon.ServerSystem.Abstractions;
|
||||
using MoonlightServers.Daemon.Services;
|
||||
|
||||
namespace MoonlightServers.Daemon.ServerSystem;
|
||||
|
||||
public partial class Server : IAsyncDisposable
|
||||
{
|
||||
public int Identifier => InnerContext.Identifier;
|
||||
public ServerContext Context => InnerContext;
|
||||
public ServerState State { get; private set; }
|
||||
|
||||
public IConsole Console { get; }
|
||||
public IFileSystem RuntimeFileSystem { get; }
|
||||
public IFileSystem InstallationFileSystem { get; }
|
||||
public IInstallation Installation { get; }
|
||||
public IOnlineDetector OnlineDetector { get; }
|
||||
public IReporter Reporter { get; }
|
||||
public IRestorer Restorer { get; }
|
||||
public IRuntime Runtime { get; }
|
||||
public IStatistics Statistics { get; }
|
||||
public StateMachine<ServerState, ServerTrigger> StateMachine { get; private set; }
|
||||
private IRuntimeEnvironment? RuntimeEnvironment;
|
||||
private RuntimeConfiguration RuntimeConfiguration;
|
||||
private IRuntimeStorage? RuntimeStorage;
|
||||
|
||||
private readonly IServerStateHandler[] Handlers;
|
||||
private IInstallEnvironment? InstallEnvironment;
|
||||
private InstallConfiguration InstallConfiguration;
|
||||
private IInstallStorage? InstallStorage;
|
||||
|
||||
private readonly IServerComponent[] AllComponents;
|
||||
private readonly ServerContext InnerContext;
|
||||
private readonly IRuntimeEnvironmentService RuntimeEnvironmentService;
|
||||
private readonly IInstallEnvironmentService InstallEnvironmentService;
|
||||
private readonly IRuntimeStorageService RuntimeStorageService;
|
||||
private readonly IInstallStorageService InstallStorageService;
|
||||
|
||||
private readonly ServerConfigurationService ConfigurationService;
|
||||
private readonly string Uuid;
|
||||
private readonly ILogger Logger;
|
||||
|
||||
private readonly SemaphoreSlim Lock = new(1, 1);
|
||||
|
||||
public Server(
|
||||
ILogger logger,
|
||||
ServerContext context,
|
||||
IConsole console,
|
||||
IFileSystem runtimeFileSystem,
|
||||
IFileSystem installationFileSystem,
|
||||
IInstallation installation,
|
||||
IOnlineDetector onlineDetector,
|
||||
IReporter reporter,
|
||||
IRestorer restorer,
|
||||
IRuntime runtime,
|
||||
IStatistics statistics,
|
||||
IEnumerable<IServerStateHandler> handlers,
|
||||
IEnumerable<IServerComponent> additionalComponents
|
||||
string uuid,
|
||||
IRuntimeEnvironmentService runtimeEnvironmentService,
|
||||
IInstallEnvironmentService installEnvironmentService,
|
||||
IRuntimeStorageService runtimeStorageService,
|
||||
IInstallStorageService installStorageService,
|
||||
ServerConfigurationService configurationService,
|
||||
ILogger logger
|
||||
)
|
||||
{
|
||||
Uuid = uuid;
|
||||
RuntimeEnvironmentService = runtimeEnvironmentService;
|
||||
InstallEnvironmentService = installEnvironmentService;
|
||||
RuntimeStorageService = runtimeStorageService;
|
||||
InstallStorageService = installStorageService;
|
||||
ConfigurationService = configurationService;
|
||||
Logger = logger;
|
||||
InnerContext = context;
|
||||
Console = console;
|
||||
RuntimeFileSystem = runtimeFileSystem;
|
||||
InstallationFileSystem = installationFileSystem;
|
||||
Installation = installation;
|
||||
OnlineDetector = onlineDetector;
|
||||
Reporter = reporter;
|
||||
Restorer = restorer;
|
||||
Runtime = runtime;
|
||||
Statistics = statistics;
|
||||
|
||||
IEnumerable<IServerComponent> defaultComponents =
|
||||
[
|
||||
Console, RuntimeFileSystem, InstallationFileSystem, Installation, OnlineDetector, Reporter, Restorer,
|
||||
Runtime, Statistics
|
||||
];
|
||||
|
||||
AllComponents = defaultComponents.Concat(additionalComponents).ToArray();
|
||||
|
||||
Handlers = handlers.ToArray();
|
||||
}
|
||||
|
||||
private void ConfigureStateMachine(ServerState initialState)
|
||||
{
|
||||
StateMachine = new StateMachine<ServerState, ServerTrigger>(
|
||||
initialState, FiringMode.Queued
|
||||
);
|
||||
|
||||
StateMachine.Configure(ServerState.Offline)
|
||||
.Permit(ServerTrigger.Start, ServerState.Starting)
|
||||
.Permit(ServerTrigger.Install, ServerState.Installing)
|
||||
.PermitReentry(ServerTrigger.Fail);
|
||||
|
||||
StateMachine.Configure(ServerState.Starting)
|
||||
.Permit(ServerTrigger.DetectOnline, ServerState.Online)
|
||||
.Permit(ServerTrigger.Fail, ServerState.Offline)
|
||||
.Permit(ServerTrigger.Exited, ServerState.Offline)
|
||||
.Permit(ServerTrigger.Stop, ServerState.Stopping)
|
||||
.Permit(ServerTrigger.Kill, ServerState.Stopping);
|
||||
|
||||
StateMachine.Configure(ServerState.Online)
|
||||
.Permit(ServerTrigger.Stop, ServerState.Stopping)
|
||||
.Permit(ServerTrigger.Kill, ServerState.Stopping)
|
||||
.Permit(ServerTrigger.Exited, ServerState.Offline);
|
||||
|
||||
StateMachine.Configure(ServerState.Stopping)
|
||||
.PermitReentry(ServerTrigger.Fail)
|
||||
.PermitReentry(ServerTrigger.Kill)
|
||||
.Permit(ServerTrigger.Exited, ServerState.Offline);
|
||||
|
||||
StateMachine.Configure(ServerState.Installing)
|
||||
.Permit(ServerTrigger.Fail, ServerState.Offline) // TODO: Add kill
|
||||
.Permit(ServerTrigger.Exited, ServerState.Offline);
|
||||
}
|
||||
|
||||
private void ConfigureStateMachineEvents()
|
||||
{
|
||||
// Configure the calling of the handlers
|
||||
StateMachine.OnTransitionedAsync(async transition =>
|
||||
{
|
||||
var hasFailed = false;
|
||||
|
||||
foreach (var handler in Handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
await handler.ExecuteAsync(transition);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(
|
||||
e,
|
||||
"Handler {name} has thrown an unexpected exception",
|
||||
handler.GetType().FullName
|
||||
);
|
||||
|
||||
hasFailed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!hasFailed)
|
||||
return; // Everything went fine, we can exit now
|
||||
|
||||
// Something has failed, lets check if we can handle the error
|
||||
// via a fail trigger
|
||||
|
||||
if(!StateMachine.CanFire(ServerTrigger.Fail))
|
||||
return;
|
||||
|
||||
// Trigger the fail so the server gets a chance to handle the error softly
|
||||
await StateMachine.FireAsync(ServerTrigger.Fail);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
foreach (var component in AllComponents)
|
||||
await component.InitializeAsync();
|
||||
Logger.LogTrace("Initializing");
|
||||
|
||||
var restoredState = ServerState.Offline;
|
||||
await Lock.WaitAsync();
|
||||
|
||||
ConfigureStateMachine(restoredState);
|
||||
ConfigureStateMachineEvents();
|
||||
try
|
||||
{
|
||||
// Restore state
|
||||
State = await RestoreAsync();
|
||||
|
||||
Logger.LogTrace("Initialization complete, restored to state {State}", State);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Lock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnConsoleMessageAsync(string message)
|
||||
{
|
||||
Console.WriteLine($"Console: {message}");
|
||||
}
|
||||
|
||||
private async Task OnStatisticsReceivedAsync(ServerStatistics statistics)
|
||||
{
|
||||
}
|
||||
|
||||
private Task ChangeStateAsync(ServerState newState)
|
||||
{
|
||||
Logger.LogTrace("State changed from {OldState} to {NewState}", State, newState);
|
||||
|
||||
State = newState;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
foreach (var handler in Handlers)
|
||||
await handler.DisposeAsync();
|
||||
|
||||
foreach (var component in AllComponents)
|
||||
await component.DisposeAsync();
|
||||
Logger.LogTrace("Disposing");
|
||||
|
||||
if (RuntimeEnvironment != null)
|
||||
{
|
||||
Logger.LogTrace("Detaching and disposing runtime environment");
|
||||
|
||||
RuntimeEnvironment.Console.OnOutput -= OnConsoleMessageAsync;
|
||||
RuntimeEnvironment.Statistics.OnStatisticsReceived -= OnStatisticsReceivedAsync;
|
||||
RuntimeEnvironment.OnExited -= OnRuntimeExitedAsync;
|
||||
|
||||
await RuntimeEnvironment.DisposeAsync();
|
||||
}
|
||||
|
||||
if (InstallEnvironment != null)
|
||||
{
|
||||
Logger.LogTrace("Detaching and disposing install environment");
|
||||
|
||||
InstallEnvironment.Console.OnOutput -= OnConsoleMessageAsync;
|
||||
InstallEnvironment.Statistics.OnStatisticsReceived -= OnStatisticsReceivedAsync;
|
||||
InstallEnvironment.OnExited -= OnInstallExitedAsync;
|
||||
|
||||
await InstallEnvironment.DisposeAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user