From b90100d250821697bdd89a7f628eb0f1e3fdeac3 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Sun, 7 Sep 2025 23:15:48 +0200 Subject: [PATCH] Implemented restorer, runtime and dummy statistics. Added service registering and fixed server factory. Moved logger to server context --- .../MoonlightServers.ApiServer.csproj | 1 - .../MoonlightServers.Daemon.csproj | 7 + .../ServerSystem/Docker/DockerConsole.cs | 1 + .../ServerSystem/Docker/DockerConstants.cs | 4 +- .../ServerSystem/Docker/DockerInstallation.cs | 7 +- .../ServerSystem/Docker/DockerRestorer.cs | 59 ++++++ .../ServerSystem/Docker/DockerRuntime.cs | 177 ++++++++++++++++++ .../ServerSystem/Docker/DockerStatistics.cs | 25 +++ .../FileSystems/RawInstallationFs.cs | 2 +- .../ServerSystem/Handlers/ShutdownHandler.cs | 2 +- .../ServerSystem/Handlers/StartupHandler.cs | 2 +- .../Implementations/RegexOnlineDetector.cs | 13 +- .../Implementations/ServerReporter.cs | 17 +- .../ServerSystem/Interfaces/IRuntime.cs | 2 +- .../ServerSystem/Models/ServerContext.cs | 2 + .../ServerSystem/Server.cs | 26 --- .../ServerSystem/ServerFactory.cs | 27 ++- MoonlightServers.Daemon/Startup.cs | 76 ++++++++ 18 files changed, 385 insertions(+), 65 deletions(-) create mode 100644 MoonlightServers.Daemon/ServerSystem/Docker/DockerRestorer.cs create mode 100644 MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs create mode 100644 MoonlightServers.Daemon/ServerSystem/Docker/DockerStatistics.cs diff --git a/MoonlightServers.ApiServer/MoonlightServers.ApiServer.csproj b/MoonlightServers.ApiServer/MoonlightServers.ApiServer.csproj index 6284d3a..7fa187a 100644 --- a/MoonlightServers.ApiServer/MoonlightServers.ApiServer.csproj +++ b/MoonlightServers.ApiServer/MoonlightServers.ApiServer.csproj @@ -17,7 +17,6 @@ - diff --git a/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj b/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj index 009d473..a1d584f 100644 --- a/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj +++ b/MoonlightServers.Daemon/MoonlightServers.Daemon.csproj @@ -57,6 +57,13 @@ <_ContentIncludedByDefault Remove="volumes\3\version_history.json" /> <_ContentIncludedByDefault Remove="volumes\3\whitelist.json" /> <_ContentIncludedByDefault Remove="storage\volumes\69\plugins\spark\config.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\banned-ips.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\banned-players.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\ops.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\plugins\spark\config.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\usercache.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\version_history.json" /> + <_ContentIncludedByDefault Remove="storage\volumes\6\whitelist.json" /> diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerConsole.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerConsole.cs index 7d6b51d..d3d8bd2 100644 --- a/MoonlightServers.Daemon/ServerSystem/Docker/DockerConsole.cs +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerConsole.cs @@ -22,6 +22,7 @@ public class DockerConsole : IConsole { DockerClient = dockerClient; Context = context; + Logger = Context.Logger; } public Task InitializeAsync() diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerConstants.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerConstants.cs index e7efc5b..8a82844 100644 --- a/MoonlightServers.Daemon/ServerSystem/Docker/DockerConstants.cs +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerConstants.cs @@ -2,6 +2,6 @@ namespace MoonlightServers.Daemon.ServerSystem.Docker; public static class DockerConstants { - public const string RuntimeNameTemplate = "monnlight-runtime-{0}"; - public const string InstallationNameTemplate = "monnlight-installation-{0}"; + public const string RuntimeNameTemplate = "moonlight-runtime-{0}"; + public const string InstallationNameTemplate = "moonlight-installation-{0}"; } \ No newline at end of file diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerInstallation.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerInstallation.cs index 7c40d35..ac6bb18 100644 --- a/MoonlightServers.Daemon/ServerSystem/Docker/DockerInstallation.cs +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerInstallation.cs @@ -16,7 +16,7 @@ public class DockerInstallation : IInstallation private readonly DockerImageService ImageService; private readonly ServerContext ServerContext; private readonly DockerClient DockerClient; - private readonly IReporter Reporter; + private IReporter Reporter => ServerContext.Server.Reporter; private readonly EventSource ExitEventSource = new(); @@ -28,7 +28,6 @@ public class DockerInstallation : IInstallation ServerContext serverContext, ServerConfigurationMapper mapper, DockerImageService imageService, - IReporter reporter, DockerEventService dockerEventService ) { @@ -36,7 +35,6 @@ public class DockerInstallation : IInstallation ServerContext = serverContext; Mapper = mapper; ImageService = imageService; - Reporter = reporter; DockerEventService = dockerEventService; } @@ -119,7 +117,8 @@ public class DockerInstallation : IInstallation // - await DockerClient.Containers.CreateContainerAsync(parameters); + var response = await DockerClient.Containers.CreateContainerAsync(parameters); + ContainerId = response.ID; await Reporter.StatusAsync("Created container"); } diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerRestorer.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerRestorer.cs new file mode 100644 index 0000000..8d22edf --- /dev/null +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerRestorer.cs @@ -0,0 +1,59 @@ +using Docker.DotNet; +using MoonlightServers.Daemon.ServerSystem.Interfaces; +using MoonlightServers.Daemon.ServerSystem.Models; + +namespace MoonlightServers.Daemon.ServerSystem.Docker; + +public class DockerRestorer : IRestorer +{ + private readonly DockerClient DockerClient; + private readonly ServerContext Context; + + public DockerRestorer(DockerClient dockerClient, ServerContext context) + { + DockerClient = dockerClient; + Context = context; + } + + public Task InitializeAsync() + => Task.CompletedTask; + + public async Task HandleRuntimeAsync() + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + try + { + var container = await DockerClient.Containers.InspectContainerAsync( + containerName + ); + + return container.State.Running; + } + catch (DockerContainerNotFoundException) + { + return false; + } + } + + public async Task HandleInstallationAsync() + { + var containerName = string.Format(DockerConstants.InstallationNameTemplate, Context.Configuration.Id); + + try + { + var container = await DockerClient.Containers.InspectContainerAsync( + containerName + ); + + return container.State.Running; + } + catch (DockerContainerNotFoundException) + { + return false; + } + } + + public ValueTask DisposeAsync() + => ValueTask.CompletedTask; +} \ No newline at end of file diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs new file mode 100644 index 0000000..8fd771e --- /dev/null +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs @@ -0,0 +1,177 @@ +using Docker.DotNet; +using Docker.DotNet.Models; +using MoonCore.Events; +using MoonlightServers.Daemon.Mappers; +using MoonlightServers.Daemon.ServerSystem.Interfaces; +using MoonlightServers.Daemon.ServerSystem.Models; +using MoonlightServers.Daemon.Services; + +namespace MoonlightServers.Daemon.ServerSystem.Docker; + +public class DockerRuntime : IRuntime +{ + private readonly DockerClient DockerClient; + private readonly ServerContext Context; + private readonly ServerConfigurationMapper Mapper; + private readonly DockerEventService DockerEventService; + private readonly DockerImageService ImageService; + private readonly EventSource ExitEventSource = new(); + + private IReporter Reporter => Context.Server.Reporter; + private IAsyncDisposable ContainerEventSubscription; + private string ContainerId; + + public DockerRuntime( + DockerClient dockerClient, + ServerContext context, + ServerConfigurationMapper mapper, + DockerEventService dockerEventService, + DockerImageService imageService + ) + { + DockerClient = dockerClient; + Context = context; + Mapper = mapper; + DockerEventService = dockerEventService; + ImageService = imageService; + } + + public async Task InitializeAsync() + { + ContainerEventSubscription = await DockerEventService.SubscribeContainerAsync(OnContainerEvent); + } + + private async ValueTask OnContainerEvent(Message message) + { + // Only handle events for our own container + if (message.ID != ContainerId) + return; + + // Only handle die events + if (message.Action != "die") + return; + + int exitCode; + + if (message.Actor.Attributes.TryGetValue("exitCode", out var exitCodeStr)) + { + if (!int.TryParse(exitCodeStr, out exitCode)) + exitCode = 0; + } + else + exitCode = 0; + + + await ExitEventSource.InvokeAsync(exitCode); + } + + public async Task CheckExistsAsync() + { + try + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + await DockerClient.Containers.InspectContainerAsync( + containerName + ); + + return true; + } + catch (DockerContainerNotFoundException) + { + return false; + } + } + + public async Task CreateAsync(string path) + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + var parameters = Mapper.ToRuntimeParameters( + Context.Configuration, + path, + containerName + ); + + // Docker image + await Reporter.StatusAsync("Downloading docker image"); + + await ImageService.Download( + Context.Configuration.DockerImage, + async status => { await Reporter.StatusAsync(status); } + ); + + await Reporter.StatusAsync("Downloaded docker image"); + + // + + var response = await DockerClient.Containers.CreateContainerAsync(parameters); + ContainerId = response.ID; + + await Reporter.StatusAsync("Created container"); + } + + public async Task StartAsync() + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + await DockerClient.Containers.StartContainerAsync(containerName, new()); + } + + public Task UpdateAsync() + { + return Task.CompletedTask; + } + + public async Task KillAsync() + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + await DockerClient.Containers.KillContainerAsync(containerName, new()); + } + + public async Task DestroyAsync() + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + try + { + var container = await DockerClient.Containers.InspectContainerAsync(containerName); + + if (container.State.Running) + await DockerClient.Containers.KillContainerAsync(containerName, new()); + + await DockerClient.Containers.RemoveContainerAsync(containerName, new() + { + Force = true + }); + } + catch (DockerContainerNotFoundException) + { + // Ignored + } + } + + public async Task SubscribeExited(Func callback) + => await ExitEventSource.SubscribeAsync(callback); + + public async Task RestoreAsync() + { + try + { + var containerName = string.Format(DockerConstants.RuntimeNameTemplate, Context.Configuration.Id); + + var container = await DockerClient.Containers.InspectContainerAsync(containerName); + ContainerId = container.ID; + } + catch (DockerContainerNotFoundException) + { + // Ignore + } + } + + public async ValueTask DisposeAsync() + { + await ContainerEventSubscription.DisposeAsync(); + } +} \ No newline at end of file diff --git a/MoonlightServers.Daemon/ServerSystem/Docker/DockerStatistics.cs b/MoonlightServers.Daemon/ServerSystem/Docker/DockerStatistics.cs new file mode 100644 index 0000000..a38f9ff --- /dev/null +++ b/MoonlightServers.Daemon/ServerSystem/Docker/DockerStatistics.cs @@ -0,0 +1,25 @@ +using MoonlightServers.Daemon.ServerSystem.Interfaces; +using MoonlightServers.Daemon.ServerSystem.Models; + +namespace MoonlightServers.Daemon.ServerSystem.Docker; + +public class DockerStatistics : IStatistics +{ + public Task InitializeAsync() + => Task.CompletedTask; + + public Task AttachRuntimeAsync() + => Task.CompletedTask; + + public Task AttachInstallationAsync() + => Task.CompletedTask; + + public Task ClearCacheAsync() + => Task.CompletedTask; + + public Task> GetCacheAsync() + => Task.FromResult>([]); + + public ValueTask DisposeAsync() + => ValueTask.CompletedTask; +} \ No newline at end of file diff --git a/MoonlightServers.Daemon/ServerSystem/FileSystems/RawInstallationFs.cs b/MoonlightServers.Daemon/ServerSystem/FileSystems/RawInstallationFs.cs index f5ea780..a7a5cdb 100644 --- a/MoonlightServers.Daemon/ServerSystem/FileSystems/RawInstallationFs.cs +++ b/MoonlightServers.Daemon/ServerSystem/FileSystems/RawInstallationFs.cs @@ -12,7 +12,7 @@ public class RawInstallationFs : IFileSystem BaseDirectory = Path.Combine( Directory.GetCurrentDirectory(), "storage", - "volumes", + "install", context.Configuration.Id.ToString() ); } diff --git a/MoonlightServers.Daemon/ServerSystem/Handlers/ShutdownHandler.cs b/MoonlightServers.Daemon/ServerSystem/Handlers/ShutdownHandler.cs index 76ec2dc..58ac6dd 100644 --- a/MoonlightServers.Daemon/ServerSystem/Handlers/ShutdownHandler.cs +++ b/MoonlightServers.Daemon/ServerSystem/Handlers/ShutdownHandler.cs @@ -17,7 +17,7 @@ public class ShutdownHandler : IServerStateHandler public async Task ExecuteAsync(StateMachine.Transition transition) { // Filter (we only want to handle exists from the runtime, so we filter out the installing state) - if (transition is + if (transition is not { Destination: ServerState.Offline, Source: not ServerState.Installing, diff --git a/MoonlightServers.Daemon/ServerSystem/Handlers/StartupHandler.cs b/MoonlightServers.Daemon/ServerSystem/Handlers/StartupHandler.cs index b5e0846..e66f16d 100644 --- a/MoonlightServers.Daemon/ServerSystem/Handlers/StartupHandler.cs +++ b/MoonlightServers.Daemon/ServerSystem/Handlers/StartupHandler.cs @@ -79,7 +79,7 @@ public class StartupHandler : IServerStateHandler await Server.Runtime.StartAsync(); } - private async Task OnRuntimeExited(int exitCode) + private async ValueTask OnRuntimeExited(int exitCode) { // TODO: Notify the crash handler component of the exit code diff --git a/MoonlightServers.Daemon/ServerSystem/Implementations/RegexOnlineDetector.cs b/MoonlightServers.Daemon/ServerSystem/Implementations/RegexOnlineDetector.cs index 0f9a238..085faad 100644 --- a/MoonlightServers.Daemon/ServerSystem/Implementations/RegexOnlineDetector.cs +++ b/MoonlightServers.Daemon/ServerSystem/Implementations/RegexOnlineDetector.cs @@ -7,14 +7,12 @@ namespace MoonlightServers.Daemon.ServerSystem.Implementations; public class RegexOnlineDetector : IOnlineDetector { private readonly ServerContext Context; - private readonly ILogger Logger; private Regex? Expression; - public RegexOnlineDetector(ServerContext context, ILogger logger) + public RegexOnlineDetector(ServerContext context) { Context = context; - Logger = logger; } public Task InitializeAsync() @@ -25,14 +23,7 @@ public class RegexOnlineDetector : IOnlineDetector if(string.IsNullOrEmpty(Context.Configuration.OnlineDetection)) return Task.CompletedTask; - try - { - Expression = new Regex(Context.Configuration.OnlineDetection, RegexOptions.Compiled); - } - catch (Exception e) - { - Logger.LogError(e, "An error occured while creating regex. Check the regex expression"); - } + Expression = new Regex(Context.Configuration.OnlineDetection, RegexOptions.Compiled); return Task.CompletedTask; } diff --git a/MoonlightServers.Daemon/ServerSystem/Implementations/ServerReporter.cs b/MoonlightServers.Daemon/ServerSystem/Implementations/ServerReporter.cs index 7e3d63b..281e301 100644 --- a/MoonlightServers.Daemon/ServerSystem/Implementations/ServerReporter.cs +++ b/MoonlightServers.Daemon/ServerSystem/Implementations/ServerReporter.cs @@ -1,11 +1,11 @@ using MoonlightServers.Daemon.ServerSystem.Interfaces; +using MoonlightServers.Daemon.ServerSystem.Models; namespace MoonlightServers.Daemon.ServerSystem.Implementations; public class ServerReporter : IReporter { - private readonly IConsole Console; - private readonly ILogger Logger; + private readonly ServerContext Context; private const string StatusTemplate = "\x1b[1;38;2;200;90;200mM\x1b[1;38;2;204;110;230mo\x1b[1;38;2;170;130;245mo\x1b[1;38;2;140;150;255mn\x1b[1;38;2;110;180;255ml\x1b[1;38;2;100;200;255mi\x1b[1;38;2;100;220;255mg\x1b[1;38;2;120;235;255mh\x1b[1;38;2;140;250;255mt\x1b[0m \x1b[3;38;2;200;200;200m{0}\x1b[0m\n\r"; @@ -13,10 +13,9 @@ public class ServerReporter : IReporter private const string ErrorTemplate = "\x1b[1;38;2;200;90;200mM\x1b[1;38;2;204;110;230mo\x1b[1;38;2;170;130;245mo\x1b[1;38;2;140;150;255mn\x1b[1;38;2;110;180;255ml\x1b[1;38;2;100;200;255mi\x1b[1;38;2;100;220;255mg\x1b[1;38;2;120;235;255mh\x1b[1;38;2;140;250;255mt\x1b[0m \x1b[1;38;2;255;0;0m{0}\x1b[0m\n\r"; - public ServerReporter(IConsole console, ILogger logger) + public ServerReporter(ServerContext context) { - Console = console; - Logger = logger; + Context = context; } public Task InitializeAsync() @@ -24,18 +23,18 @@ public class ServerReporter : IReporter public async Task StatusAsync(string message) { - Logger.LogInformation("Status: {message}", message); + Context.Logger.LogInformation("Status: {message}", message); - await Console.WriteStdOutAsync( + await Context.Server.Console.WriteStdOutAsync( string.Format(StatusTemplate, message) ); } public async Task ErrorAsync(string message) { - Logger.LogError("Error: {message}", message); + Context.Logger.LogError("Error: {message}", message); - await Console.WriteStdOutAsync( + await Context.Server.Console.WriteStdOutAsync( string.Format(ErrorTemplate, message) ); } diff --git a/MoonlightServers.Daemon/ServerSystem/Interfaces/IRuntime.cs b/MoonlightServers.Daemon/ServerSystem/Interfaces/IRuntime.cs index 3a27b2d..d6a5f7a 100644 --- a/MoonlightServers.Daemon/ServerSystem/Interfaces/IRuntime.cs +++ b/MoonlightServers.Daemon/ServerSystem/Interfaces/IRuntime.cs @@ -44,7 +44,7 @@ public interface IRuntime : IServerComponent /// /// Callback gets invoked whenever the runtime exites /// Subscription disposable to unsubscribe from the event - public Task SubscribeExited(Func callback); + public Task SubscribeExited(Func callback); /// /// Connects an existing runtime to this abstraction in order to restore it. diff --git a/MoonlightServers.Daemon/ServerSystem/Models/ServerContext.cs b/MoonlightServers.Daemon/ServerSystem/Models/ServerContext.cs index e62597a..188c8ac 100644 --- a/MoonlightServers.Daemon/ServerSystem/Models/ServerContext.cs +++ b/MoonlightServers.Daemon/ServerSystem/Models/ServerContext.cs @@ -1,4 +1,5 @@ using MoonlightServers.Daemon.Models.Cache; +using MoonlightServers.Daemon.ServerSystem.Interfaces; namespace MoonlightServers.Daemon.ServerSystem.Models; @@ -8,4 +9,5 @@ public class ServerContext public int Identifier { get; set; } public AsyncServiceScope ServiceScope { get; set; } public Server Server { get; set; } + public ILogger Logger { get; set; } } \ No newline at end of file diff --git a/MoonlightServers.Daemon/ServerSystem/Server.cs b/MoonlightServers.Daemon/ServerSystem/Server.cs index 92b39d3..6e8b5c2 100644 --- a/MoonlightServers.Daemon/ServerSystem/Server.cs +++ b/MoonlightServers.Daemon/ServerSystem/Server.cs @@ -136,32 +136,6 @@ public partial class Server : IAsyncDisposable }); } - private async Task HandleSaveAsync(Func callback) - { - try - { - await callback.Invoke(); - } - catch (Exception e) - { - Logger.LogError(e, "An error occured while handling"); - - await StateMachine.FireAsync(ServerTrigger.Fail); - } - } - - private async Task HandleIgnoredAsync(Func callback) - { - try - { - await callback.Invoke(); - } - catch (Exception e) - { - Logger.LogError(e, "An error occured while handling"); - } - } - public async Task InitializeAsync() { foreach (var component in AllComponents) diff --git a/MoonlightServers.Daemon/ServerSystem/ServerFactory.cs b/MoonlightServers.Daemon/ServerSystem/ServerFactory.cs index 1dc86cd..4f24ee5 100644 --- a/MoonlightServers.Daemon/ServerSystem/ServerFactory.cs +++ b/MoonlightServers.Daemon/ServerSystem/ServerFactory.cs @@ -1,6 +1,7 @@ using MoonlightServers.Daemon.Models.Cache; using MoonlightServers.Daemon.ServerSystem.Docker; using MoonlightServers.Daemon.ServerSystem.FileSystems; +using MoonlightServers.Daemon.ServerSystem.Handlers; using MoonlightServers.Daemon.ServerSystem.Implementations; using MoonlightServers.Daemon.ServerSystem.Interfaces; using MoonlightServers.Daemon.ServerSystem.Models; @@ -16,7 +17,7 @@ public class ServerFactory ServiceProvider = serviceProvider; } - public async Task Create(ServerConfiguration configuration) + public async Task CreateAsync(ServerConfiguration configuration) { var scope = ServiceProvider.CreateAsyncScope(); @@ -28,6 +29,7 @@ public class ServerFactory context.Identifier = configuration.Id; context.Configuration = configuration; context.ServiceScope = scope; + context.Logger = logger; // Define all required components @@ -43,12 +45,21 @@ public class ServerFactory // Resolve the components - console = ActivatorUtilities.CreateInstance(scope.ServiceProvider, logger); - reporter = ActivatorUtilities.CreateInstance(scope.ServiceProvider, console, logger); - runtimeFs = ActivatorUtilities.CreateInstance(scope.ServiceProvider, logger, reporter); - installFs = ActivatorUtilities.CreateInstance(scope.ServiceProvider, logger, reporter); - installation = ActivatorUtilities.CreateInstance(scope.ServiceProvider, logger, reporter); - onlineDetector = ActivatorUtilities.CreateInstance(scope.ServiceProvider, logger, reporter); + console = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + reporter = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + runtimeFs = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + installFs = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + installation = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + onlineDetector = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + restorer = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + runtime = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + statistics = ActivatorUtilities.CreateInstance(scope.ServiceProvider); + + // Resolve handlers + var handlers = new List(); + + handlers.Add(ActivatorUtilities.CreateInstance(scope.ServiceProvider)); + handlers.Add(ActivatorUtilities.CreateInstance(scope.ServiceProvider)); // TODO: Add a plugin hook for dynamically resolving components and checking if any is unset @@ -67,7 +78,7 @@ public class ServerFactory runtime, statistics, // And now all the handlers - [] + handlers.ToArray() ); context.Server = server; diff --git a/MoonlightServers.Daemon/Startup.cs b/MoonlightServers.Daemon/Startup.cs index 7cfeedd..657ab6f 100644 --- a/MoonlightServers.Daemon/Startup.cs +++ b/MoonlightServers.Daemon/Startup.cs @@ -11,6 +11,16 @@ using MoonCore.Logging; using MoonlightServers.Daemon.Configuration; using MoonlightServers.Daemon.Helpers; using MoonlightServers.Daemon.Http.Hubs; +using MoonlightServers.Daemon.Mappers; +using MoonlightServers.Daemon.Models.Cache; +using MoonlightServers.Daemon.ServerSystem; +using MoonlightServers.Daemon.ServerSystem.Docker; +using MoonlightServers.Daemon.ServerSystem.Enums; +using MoonlightServers.Daemon.ServerSystem.FileSystems; +using MoonlightServers.Daemon.ServerSystem.Handlers; +using MoonlightServers.Daemon.ServerSystem.Implementations; +using MoonlightServers.Daemon.ServerSystem.Models; +using MoonlightServers.Daemon.Services; namespace MoonlightServers.Daemon; @@ -60,6 +70,64 @@ public class Startup await MapBase(); await MapHubs(); + Task.Run(async () => + { + try + { + var serverConfig = new ServerConfiguration() + { + Id = 69, + Allocations = + [ + new ServerConfiguration.AllocationConfiguration() + { + IpAddress = "0.0.0.0", + Port = 25565 + } + ], + Cpu = 400, + Disk = 10240, + Memory = 4096, + OnlineDetection = "\\! For help, type ", + StartupCommand = + "java -Xms128M -Xmx{{SERVER_MEMORY}}M -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}", + DockerImage = "ghcr.io/nexocrew-hq/moonlightdockerimages:java21", + StopCommand = "stop", + UseVirtualDisk = false, + Bandwidth = 0, + Variables = new Dictionary() + { + { "SERVER_JARFILE", "server.jar" } + } + }; + + var factory = WebApplication.Services.GetRequiredService(); + + Console.Write("Press enter to create and init server"); + Console.ReadLine(); + + var s = await factory.CreateAsync(serverConfig); + + await s.InitializeAsync(); + + s.StateMachine.OnTransitionCompleted(transition => + { + Console.WriteLine(transition.Destination); + }); + + Console.Write("Press enter to start server"); + Console.ReadLine(); + + await s.StateMachine.FireAsync(ServerTrigger.Start); + + Console.ReadLine(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + }); + await WebApplication.RunAsync(); } @@ -125,6 +193,10 @@ public class Startup ).CreateClient(); WebApplicationBuilder.Services.AddSingleton(dockerClient); + WebApplicationBuilder.Services.AddScoped(); + + WebApplicationBuilder.Services.AddSingleton(); + WebApplicationBuilder.Services.AddHostedService(sp => sp.GetRequiredService()); return Task.CompletedTask; } @@ -245,6 +317,10 @@ public class Startup private Task RegisterServers() { + WebApplicationBuilder.Services.AddScoped(); + WebApplicationBuilder.Services.AddSingleton(); + WebApplicationBuilder.Services.AddSingleton(); + return Task.CompletedTask; }