Implemented restorer, runtime and dummy statistics. Added service registering and fixed server factory. Moved logger to server context
This commit is contained in:
@@ -17,7 +17,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moonlight.ApiServer" Version="2.1.*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7"/>
|
||||
<PackageReference Include="Riok.Mapperly" Version="4.3.0-next.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -22,6 +22,7 @@ public class DockerConsole : IConsole
|
||||
{
|
||||
DockerClient = dockerClient;
|
||||
Context = context;
|
||||
Logger = Context.Logger;
|
||||
}
|
||||
|
||||
public Task InitializeAsync()
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
@@ -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<int> 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");
|
||||
}
|
||||
|
||||
@@ -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<bool> 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<bool> 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;
|
||||
}
|
||||
177
MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs
Normal file
177
MoonlightServers.Daemon/ServerSystem/Docker/DockerRuntime.cs
Normal file
@@ -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<int> 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<bool> 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<IAsyncDisposable> SubscribeExited(Func<int, ValueTask> 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();
|
||||
}
|
||||
}
|
||||
@@ -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<IEnumerable<StatisticsData>> GetCacheAsync()
|
||||
=> Task.FromResult<IEnumerable<StatisticsData>>([]);
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
=> ValueTask.CompletedTask;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class RawInstallationFs : IFileSystem
|
||||
BaseDirectory = Path.Combine(
|
||||
Directory.GetCurrentDirectory(),
|
||||
"storage",
|
||||
"volumes",
|
||||
"install",
|
||||
context.Configuration.Id.ToString()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ShutdownHandler : IServerStateHandler
|
||||
public async Task ExecuteAsync(StateMachine<ServerState, ServerTrigger>.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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ public interface IRuntime : IServerComponent
|
||||
/// </summary>
|
||||
/// <param name="callback">Callback gets invoked whenever the runtime exites</param>
|
||||
/// <returns>Subscription disposable to unsubscribe from the event</returns>
|
||||
public Task<IAsyncDisposable> SubscribeExited(Func<int, Task> callback);
|
||||
public Task<IAsyncDisposable> SubscribeExited(Func<int, ValueTask> callback);
|
||||
|
||||
/// <summary>
|
||||
/// Connects an existing runtime to this abstraction in order to restore it.
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -136,32 +136,6 @@ public partial class Server : IAsyncDisposable
|
||||
});
|
||||
}
|
||||
|
||||
private async Task HandleSaveAsync(Func<Task> 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<Task> 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)
|
||||
|
||||
@@ -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<Server> Create(ServerConfiguration configuration)
|
||||
public async Task<Server> 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<DockerConsole>(scope.ServiceProvider, logger);
|
||||
reporter = ActivatorUtilities.CreateInstance<ServerReporter>(scope.ServiceProvider, console, logger);
|
||||
runtimeFs = ActivatorUtilities.CreateInstance<RawRuntimeFs>(scope.ServiceProvider, logger, reporter);
|
||||
installFs = ActivatorUtilities.CreateInstance<RawInstallationFs>(scope.ServiceProvider, logger, reporter);
|
||||
installation = ActivatorUtilities.CreateInstance<DockerInstallation>(scope.ServiceProvider, logger, reporter);
|
||||
onlineDetector = ActivatorUtilities.CreateInstance<RegexOnlineDetector>(scope.ServiceProvider, logger, reporter);
|
||||
console = ActivatorUtilities.CreateInstance<DockerConsole>(scope.ServiceProvider);
|
||||
reporter = ActivatorUtilities.CreateInstance<ServerReporter>(scope.ServiceProvider);
|
||||
runtimeFs = ActivatorUtilities.CreateInstance<RawRuntimeFs>(scope.ServiceProvider);
|
||||
installFs = ActivatorUtilities.CreateInstance<RawInstallationFs>(scope.ServiceProvider);
|
||||
installation = ActivatorUtilities.CreateInstance<DockerInstallation>(scope.ServiceProvider);
|
||||
onlineDetector = ActivatorUtilities.CreateInstance<RegexOnlineDetector>(scope.ServiceProvider);
|
||||
restorer = ActivatorUtilities.CreateInstance<DockerRestorer>(scope.ServiceProvider);
|
||||
runtime = ActivatorUtilities.CreateInstance<DockerRuntime>(scope.ServiceProvider);
|
||||
statistics = ActivatorUtilities.CreateInstance<DockerStatistics>(scope.ServiceProvider);
|
||||
|
||||
// Resolve handlers
|
||||
var handlers = new List<IServerStateHandler>();
|
||||
|
||||
handlers.Add(ActivatorUtilities.CreateInstance<StartupHandler>(scope.ServiceProvider));
|
||||
handlers.Add(ActivatorUtilities.CreateInstance<ShutdownHandler>(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;
|
||||
|
||||
@@ -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<string, string>()
|
||||
{
|
||||
{ "SERVER_JARFILE", "server.jar" }
|
||||
}
|
||||
};
|
||||
|
||||
var factory = WebApplication.Services.GetRequiredService<ServerFactory>();
|
||||
|
||||
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<DockerImageService>();
|
||||
|
||||
WebApplicationBuilder.Services.AddSingleton<DockerEventService>();
|
||||
WebApplicationBuilder.Services.AddHostedService(sp => sp.GetRequiredService<DockerEventService>());
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -245,6 +317,10 @@ public class Startup
|
||||
|
||||
private Task RegisterServers()
|
||||
{
|
||||
WebApplicationBuilder.Services.AddScoped<ServerContext>();
|
||||
WebApplicationBuilder.Services.AddSingleton<ServerFactory>();
|
||||
WebApplicationBuilder.Services.AddSingleton<ServerConfigurationMapper>();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user