Fixed event/observer issues
This commit is contained in:
@@ -9,7 +9,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
|
<PackageReference Include="Docker.DotNet" Version="3.125.15" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
|
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.2.0" />
|
||||||
<PackageReference Include="MoonCore" Version="1.9.3" />
|
<PackageReference Include="MoonCore" Version="1.9.4" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.3.6" />
|
<PackageReference Include="MoonCore.Extended" Version="1.3.6" />
|
||||||
<PackageReference Include="MoonCore.Unix" Version="1.0.8" />
|
<PackageReference Include="MoonCore.Unix" Version="1.0.8" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using System.Reactive.Linq;
|
using MoonCore.Observability;
|
||||||
using System.Reactive.Subjects;
|
|
||||||
using MoonlightServers.Daemon.Extensions;
|
using MoonlightServers.Daemon.Extensions;
|
||||||
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.ServerSystem;
|
using MoonlightServers.Daemon.ServerSystem;
|
||||||
using Stateless;
|
using Stateless;
|
||||||
|
|
||||||
@@ -8,19 +8,19 @@ namespace MoonlightServers.Daemon.ServerSys.Abstractions;
|
|||||||
|
|
||||||
public class Server : IAsyncDisposable
|
public class Server : IAsyncDisposable
|
||||||
{
|
{
|
||||||
public IConsole Console { get; private set; }
|
public IConsole Console { get; }
|
||||||
public IFileSystem FileSystem { get; private set; }
|
public IFileSystem FileSystem { get; }
|
||||||
public IInstaller Installer { get; private set; }
|
public IInstaller Installer { get; }
|
||||||
public IProvisioner Provisioner { get; private set; }
|
public IProvisioner Provisioner { get; }
|
||||||
public IRestorer Restorer { get; private set; }
|
public IRestorer Restorer { get; }
|
||||||
public IStatistics Statistics { get; private set; }
|
public IStatistics Statistics { get; }
|
||||||
public StateMachine<ServerState, ServerTrigger> StateMachine { get; private set; }
|
public StateMachine<ServerState, ServerTrigger> StateMachine { get; private set; }
|
||||||
public ServerContext Context { get; private set; }
|
public ServerContext Context { get; }
|
||||||
public IAsyncObservable<ServerState> OnState => OnStateSubject.ToAsyncObservable();
|
public IAsyncObservable<ServerState> OnState => OnStateSubject;
|
||||||
|
|
||||||
private readonly Subject<ServerState> OnStateSubject = new();
|
private readonly EventSubject<ServerState> OnStateSubject = new();
|
||||||
private readonly ILogger<Server> Logger;
|
private readonly ILogger<Server> Logger;
|
||||||
|
|
||||||
private IAsyncDisposable? ProvisionExitSubscription;
|
private IAsyncDisposable? ProvisionExitSubscription;
|
||||||
private IAsyncDisposable? InstallerExitSubscription;
|
private IAsyncDisposable? InstallerExitSubscription;
|
||||||
|
|
||||||
@@ -80,22 +80,22 @@ public class Server : IAsyncDisposable
|
|||||||
CreateStateMachine(restoredState);
|
CreateStateMachine(restoredState);
|
||||||
|
|
||||||
// Setup event handling
|
// Setup event handling
|
||||||
ProvisionExitSubscription = await Provisioner.OnExited.SubscribeAsync(async o =>
|
ProvisionExitSubscription = await Provisioner.OnExited.SubscribeEventAsync(async _ =>
|
||||||
{
|
await StateMachine.FireAsync(ServerTrigger.Exited)
|
||||||
await StateMachine.FireAsync(ServerTrigger.Exited);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
InstallerExitSubscription = await Installer.OnExited.SubscribeAsync(async o =>
|
InstallerExitSubscription = await Installer.OnExited.SubscribeEventAsync(async _ =>
|
||||||
{
|
await StateMachine.FireAsync(ServerTrigger.Exited)
|
||||||
await StateMachine.FireAsync(ServerTrigger.Exited);
|
);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateStateMachine(ServerState initialState)
|
private void CreateStateMachine(ServerState initialState)
|
||||||
{
|
{
|
||||||
StateMachine = new StateMachine<ServerState, ServerTrigger>(initialState, FiringMode.Queued);
|
StateMachine = new StateMachine<ServerState, ServerTrigger>(initialState, FiringMode.Queued);
|
||||||
|
|
||||||
StateMachine.OnTransitioned(transition => OnStateSubject.OnNext(transition.Destination));
|
StateMachine.OnTransitionedAsync(async transition
|
||||||
|
=> await OnStateSubject.OnNextAsync(transition.Destination)
|
||||||
|
);
|
||||||
|
|
||||||
// Configure basic state machine flow
|
// Configure basic state machine flow
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ public class Server : IAsyncDisposable
|
|||||||
StateMachine.Configure(ServerState.Installing)
|
StateMachine.Configure(ServerState.Installing)
|
||||||
.OnEntryAsync(HandleInstall)
|
.OnEntryAsync(HandleInstall)
|
||||||
.OnExitFromAsync(ServerTrigger.Exited, HandleInstallExit);
|
.OnExitFromAsync(ServerTrigger.Exited, HandleInstallExit);
|
||||||
|
|
||||||
StateMachine.Configure(ServerState.Online)
|
StateMachine.Configure(ServerState.Online)
|
||||||
.OnExitFromAsync(ServerTrigger.Exited, HandleRuntimeExit);
|
.OnExitFromAsync(ServerTrigger.Exited, HandleRuntimeExit);
|
||||||
|
|
||||||
@@ -187,9 +187,12 @@ public class Server : IAsyncDisposable
|
|||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError(e, "An error occured while starting the server");
|
Logger.LogError(e, "An error occured while starting the server");
|
||||||
|
await Console.WriteToMoonlight("Failed to start the server. More details can be found in the daemon logs");
|
||||||
|
|
||||||
|
await StateMachine.FireAsync(ServerTrigger.FailSafe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleStop()
|
private async Task HandleStop()
|
||||||
{
|
{
|
||||||
await Provisioner.Stop();
|
await Provisioner.Stop();
|
||||||
@@ -199,41 +202,51 @@ public class Server : IAsyncDisposable
|
|||||||
{
|
{
|
||||||
Logger.LogDebug("Deprovisioning");
|
Logger.LogDebug("Deprovisioning");
|
||||||
await Console.WriteToMoonlight("Deprovisioning");
|
await Console.WriteToMoonlight("Deprovisioning");
|
||||||
|
|
||||||
await Provisioner.Deprovision();
|
await Provisioner.Deprovision();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleInstall()
|
private async Task HandleInstall()
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Installing");
|
try
|
||||||
|
|
||||||
Logger.LogDebug("Setting up");
|
|
||||||
await Console.WriteToMoonlight("Setting up installation");
|
|
||||||
|
|
||||||
// TODO: Extract to service
|
|
||||||
|
|
||||||
Context.InstallConfiguration = new()
|
|
||||||
{
|
{
|
||||||
Shell = "/bin/ash",
|
Logger.LogDebug("Installing");
|
||||||
DockerImage = "ghcr.io/parkervcp/installers:alpine",
|
|
||||||
Script =
|
|
||||||
"#!/bin/ash\n# Paper Installation Script\n#\n# Server Files: /mnt/server\nPROJECT=paper\n\nif [ -n \"${DL_PATH}\" ]; then\n\techo -e \"Using supplied download url: ${DL_PATH}\"\n\tDOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's/{{/${/g' -e 's/}}/}/g')`\nelse\n\tVER_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r --arg VERSION $MINECRAFT_VERSION '.versions[] | contains($VERSION)' | grep -m1 true`\n\tLATEST_VERSION=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r '.versions' | jq -r '.[-1]'`\n\n\tif [ \"${VER_EXISTS}\" == \"true\" ]; then\n\t\techo -e \"Version is valid. Using version ${MINECRAFT_VERSION}\"\n\telse\n\t\techo -e \"Specified version not found. Defaulting to the latest ${PROJECT} version\"\n\t\tMINECRAFT_VERSION=${LATEST_VERSION}\n\tfi\n\n\tBUILD_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds[] | tostring | contains($BUILD)' | grep -m1 true`\n\tLATEST_BUILD=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION} | jq -r '.builds' | jq -r '.[-1]'`\n\n\tif [ \"${BUILD_EXISTS}\" == \"true\" ]; then\n\t\techo -e \"Build is valid for version ${MINECRAFT_VERSION}. Using build ${BUILD_NUMBER}\"\n\telse\n\t\techo -e \"Using the latest ${PROJECT} build for version ${MINECRAFT_VERSION}\"\n\t\tBUILD_NUMBER=${LATEST_BUILD}\n\tfi\n\n\tJAR_NAME=${PROJECT}-${MINECRAFT_VERSION}-${BUILD_NUMBER}.jar\n\n\techo \"Version being downloaded\"\n\techo -e \"MC Version: ${MINECRAFT_VERSION}\"\n\techo -e \"Build: ${BUILD_NUMBER}\"\n\techo -e \"JAR Name of Build: ${JAR_NAME}\"\n\tDOWNLOAD_URL=https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds/${BUILD_NUMBER}/downloads/${JAR_NAME}\nfi\n\ncd /mnt/server\n\necho -e \"Running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\n\nif [ -f ${SERVER_JARFILE} ]; then\n\tmv ${SERVER_JARFILE} ${SERVER_JARFILE}.old\nfi\n\ncurl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\n\nif [ ! -f server.properties ]; then\n echo -e \"Downloading MC server.properties\"\n curl -o server.properties https://raw.githubusercontent.com/parkervcp/eggs/master/minecraft/java/server.properties\nfi"
|
|
||||||
};
|
|
||||||
|
|
||||||
await Installer.Setup();
|
|
||||||
|
|
||||||
await Console.AttachToInstallation();
|
Logger.LogDebug("Setting up");
|
||||||
|
await Console.WriteToMoonlight("Setting up installation");
|
||||||
|
|
||||||
await Installer.Start();
|
// TODO: Extract to service
|
||||||
|
|
||||||
|
Context.InstallConfiguration = new()
|
||||||
|
{
|
||||||
|
Shell = "/bin/ash",
|
||||||
|
DockerImage = "ghcr.io/parkervcp/installers:alpine",
|
||||||
|
Script =
|
||||||
|
"#!/bin/ash\n# Paper Installation Script\n#\n# Server Files: /mnt/server\nPROJECT=paper\n\nif [ -n \"${DL_PATH}\" ]; then\n\techo -e \"Using supplied download url: ${DL_PATH}\"\n\tDOWNLOAD_URL=`eval echo $(echo ${DL_PATH} | sed -e 's/{{/${/g' -e 's/}}/}/g')`\nelse\n\tVER_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r --arg VERSION $MINECRAFT_VERSION '.versions[] | contains($VERSION)' | grep -m1 true`\n\tLATEST_VERSION=`curl -s https://api.papermc.io/v2/projects/${PROJECT} | jq -r '.versions' | jq -r '.[-1]'`\n\n\tif [ \"${VER_EXISTS}\" == \"true\" ]; then\n\t\techo -e \"Version is valid. Using version ${MINECRAFT_VERSION}\"\n\telse\n\t\techo -e \"Specified version not found. Defaulting to the latest ${PROJECT} version\"\n\t\tMINECRAFT_VERSION=${LATEST_VERSION}\n\tfi\n\n\tBUILD_EXISTS=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION} | jq -r --arg BUILD ${BUILD_NUMBER} '.builds[] | tostring | contains($BUILD)' | grep -m1 true`\n\tLATEST_BUILD=`curl -s https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION} | jq -r '.builds' | jq -r '.[-1]'`\n\n\tif [ \"${BUILD_EXISTS}\" == \"true\" ]; then\n\t\techo -e \"Build is valid for version ${MINECRAFT_VERSION}. Using build ${BUILD_NUMBER}\"\n\telse\n\t\techo -e \"Using the latest ${PROJECT} build for version ${MINECRAFT_VERSION}\"\n\t\tBUILD_NUMBER=${LATEST_BUILD}\n\tfi\n\n\tJAR_NAME=${PROJECT}-${MINECRAFT_VERSION}-${BUILD_NUMBER}.jar\n\n\techo \"Version being downloaded\"\n\techo -e \"MC Version: ${MINECRAFT_VERSION}\"\n\techo -e \"Build: ${BUILD_NUMBER}\"\n\techo -e \"JAR Name of Build: ${JAR_NAME}\"\n\tDOWNLOAD_URL=https://api.papermc.io/v2/projects/${PROJECT}/versions/${MINECRAFT_VERSION}/builds/${BUILD_NUMBER}/downloads/${JAR_NAME}\nfi\n\ncd /mnt/server\n\necho -e \"Running curl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\"\n\nif [ -f ${SERVER_JARFILE} ]; then\n\tmv ${SERVER_JARFILE} ${SERVER_JARFILE}.old\nfi\n\ncurl -o ${SERVER_JARFILE} ${DOWNLOAD_URL}\n\nif [ ! -f server.properties ]; then\n echo -e \"Downloading MC server.properties\"\n curl -o server.properties https://raw.githubusercontent.com/parkervcp/eggs/master/minecraft/java/server.properties\nfi"
|
||||||
|
};
|
||||||
|
|
||||||
|
await Installer.Setup();
|
||||||
|
|
||||||
|
await Console.AttachToInstallation();
|
||||||
|
|
||||||
|
await Installer.Start();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(e, "An error occured while starting installation");
|
||||||
|
await Console.WriteToMoonlight("An error occured while starting installation");
|
||||||
|
|
||||||
|
await StateMachine.FireAsync(ServerTrigger.FailSafe);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleInstallExit()
|
private async Task HandleInstallExit()
|
||||||
{
|
{
|
||||||
Logger.LogDebug("Installation done");
|
Logger.LogDebug("Installation done");
|
||||||
await Console.WriteToMoonlight("Cleaning up");
|
await Console.WriteToMoonlight("Cleaning up");
|
||||||
|
|
||||||
await Installer.Cleanup();
|
await Installer.Cleanup();
|
||||||
|
|
||||||
await Console.WriteToMoonlight("Installation completed");
|
await Console.WriteToMoonlight("Installation completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,17 +4,19 @@ using System.Text;
|
|||||||
using Docker.DotNet;
|
using Docker.DotNet;
|
||||||
using Docker.DotNet.Models;
|
using Docker.DotNet.Models;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using MoonCore.Observability;
|
||||||
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
||||||
|
|
||||||
namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
||||||
|
|
||||||
public class DockerConsole : IConsole
|
public class DockerConsole : IConsole
|
||||||
{
|
{
|
||||||
public IAsyncObservable<string> OnOutput => OnOutputSubject.ToAsyncObservable();
|
public IAsyncObservable<string> OnOutput => OnOutputSubject;
|
||||||
public IAsyncObservable<string> OnInput => OnInputSubject.ToAsyncObservable();
|
public IAsyncObservable<string> OnInput => OnInputSubject;
|
||||||
|
|
||||||
private readonly Subject<string> OnOutputSubject = new();
|
private readonly EventSubject<string> OnOutputSubject = new();
|
||||||
private readonly Subject<string> OnInputSubject = new();
|
private readonly EventSubject<string> OnInputSubject = new();
|
||||||
|
|
||||||
private readonly ConcurrentList<string> OutputCache = new();
|
private readonly ConcurrentList<string> OutputCache = new();
|
||||||
private readonly DockerClient DockerClient;
|
private readonly DockerClient DockerClient;
|
||||||
@@ -140,15 +142,14 @@ public class DockerConsole : IConsole
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task WriteToOutput(string content)
|
public async Task WriteToOutput(string content)
|
||||||
{
|
{
|
||||||
OutputCache.Add(content);
|
OutputCache.Add(content);
|
||||||
|
|
||||||
if (OutputCache.Count > 250) // TODO: Config
|
if (OutputCache.Count > 250) // TODO: Config
|
||||||
OutputCache.RemoveRange(0, 100);
|
OutputCache.RemoveRange(0, 100);
|
||||||
|
|
||||||
OnOutputSubject.OnNext(content);
|
await OnOutputSubject.OnNextAsync(content);
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteToInput(string content)
|
public async Task WriteToInput(string content)
|
||||||
@@ -164,6 +165,8 @@ public class DockerConsole : IConsole
|
|||||||
contentBuffer.Length,
|
contentBuffer.Length,
|
||||||
Cts.Token
|
Cts.Token
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await OnInputSubject.OnNextAsync(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task WriteToMoonlight(string content)
|
public async Task WriteToMoonlight(string content)
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ using System.Reactive.Linq;
|
|||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using Docker.DotNet;
|
using Docker.DotNet;
|
||||||
using Docker.DotNet.Models;
|
using Docker.DotNet.Models;
|
||||||
|
using MoonCore.Observability;
|
||||||
using MoonlightServers.Daemon.Configuration;
|
using MoonlightServers.Daemon.Configuration;
|
||||||
|
using MoonlightServers.Daemon.Extensions;
|
||||||
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.Mappers;
|
using MoonlightServers.Daemon.Mappers;
|
||||||
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
||||||
using MoonlightServers.Daemon.Services;
|
using MoonlightServers.Daemon.Services;
|
||||||
@@ -11,10 +14,10 @@ namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
|||||||
|
|
||||||
public class DockerInstaller : IInstaller
|
public class DockerInstaller : IInstaller
|
||||||
{
|
{
|
||||||
public IAsyncObservable<object> OnExited => OnExitedSubject.ToAsyncObservable();
|
public IAsyncObservable<object> OnExited => OnExitedSubject;
|
||||||
public bool IsRunning { get; private set; } = false;
|
public bool IsRunning { get; private set; } = false;
|
||||||
|
|
||||||
private readonly Subject<Message> OnExitedSubject = new();
|
private readonly EventSubject<Message> OnExitedSubject = new();
|
||||||
|
|
||||||
private readonly ILogger<DockerInstaller> Logger;
|
private readonly ILogger<DockerInstaller> Logger;
|
||||||
private readonly DockerEventService EventService;
|
private readonly DockerEventService EventService;
|
||||||
@@ -64,7 +67,7 @@ public class DockerInstaller : IInstaller
|
|||||||
|
|
||||||
ContainerEventSubscription = await EventService
|
ContainerEventSubscription = await EventService
|
||||||
.OnContainerEvent
|
.OnContainerEvent
|
||||||
.SubscribeAsync(HandleContainerEvent);
|
.SubscribeEventAsync(HandleContainerEvent);
|
||||||
|
|
||||||
// Check for any already existing runtime container to reclaim
|
// Check for any already existing runtime container to reclaim
|
||||||
Logger.LogDebug("Searching for orphan container to reclaim");
|
Logger.LogDebug("Searching for orphan container to reclaim");
|
||||||
@@ -82,19 +85,17 @@ public class DockerInstaller : IInstaller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask HandleContainerEvent(Message message)
|
private async ValueTask HandleContainerEvent(Message message)
|
||||||
{
|
{
|
||||||
// Only handle events for our own container
|
// Only handle events for our own container
|
||||||
if (message.ID != ContainerId)
|
if (message.ID != ContainerId)
|
||||||
return ValueTask.CompletedTask;
|
return;
|
||||||
|
|
||||||
// Only handle die events
|
// Only handle die events
|
||||||
if (message.Action != "die")
|
if (message.Action != "die")
|
||||||
return ValueTask.CompletedTask;
|
return;
|
||||||
|
|
||||||
OnExitedSubject.OnNext(message);
|
await OnExitedSubject.OnNextAsync(message);
|
||||||
|
|
||||||
return ValueTask.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Sync()
|
public Task Sync()
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ using System.Reactive.Linq;
|
|||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using Docker.DotNet;
|
using Docker.DotNet;
|
||||||
using Docker.DotNet.Models;
|
using Docker.DotNet.Models;
|
||||||
|
using MoonCore.Observability;
|
||||||
|
using MoonlightServers.Daemon.Extensions;
|
||||||
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.Mappers;
|
using MoonlightServers.Daemon.Mappers;
|
||||||
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
||||||
using MoonlightServers.Daemon.Services;
|
using MoonlightServers.Daemon.Services;
|
||||||
@@ -11,7 +14,7 @@ namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
|||||||
|
|
||||||
public class DockerProvisioner : IProvisioner
|
public class DockerProvisioner : IProvisioner
|
||||||
{
|
{
|
||||||
public IAsyncObservable<object> OnExited => OnExitedSubject.ToAsyncObservable();
|
public IAsyncObservable<object> OnExited => OnExitedSubject;
|
||||||
public bool IsProvisioned { get; private set; }
|
public bool IsProvisioned { get; private set; }
|
||||||
|
|
||||||
private readonly DockerClient DockerClient;
|
private readonly DockerClient DockerClient;
|
||||||
@@ -23,7 +26,7 @@ public class DockerProvisioner : IProvisioner
|
|||||||
private readonly ServerConfigurationMapper Mapper;
|
private readonly ServerConfigurationMapper Mapper;
|
||||||
private readonly IFileSystem FileSystem;
|
private readonly IFileSystem FileSystem;
|
||||||
|
|
||||||
private Subject<object> OnExitedSubject = new();
|
private EventSubject<object> OnExitedSubject = new();
|
||||||
|
|
||||||
private string? ContainerId;
|
private string? ContainerId;
|
||||||
private string ContainerName;
|
private string ContainerName;
|
||||||
@@ -56,7 +59,7 @@ public class DockerProvisioner : IProvisioner
|
|||||||
|
|
||||||
ContainerEventSubscription = await EventService
|
ContainerEventSubscription = await EventService
|
||||||
.OnContainerEvent
|
.OnContainerEvent
|
||||||
.SubscribeAsync(HandleContainerEvent);
|
.SubscribeEventAsync(HandleContainerEvent);
|
||||||
|
|
||||||
// Check for any already existing runtime container to reclaim
|
// Check for any already existing runtime container to reclaim
|
||||||
Logger.LogDebug("Searching for orphan container to reclaim");
|
Logger.LogDebug("Searching for orphan container to reclaim");
|
||||||
@@ -74,19 +77,17 @@ public class DockerProvisioner : IProvisioner
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask HandleContainerEvent(Message message)
|
private async ValueTask HandleContainerEvent(Message message)
|
||||||
{
|
{
|
||||||
// Only handle events for our own container
|
// Only handle events for our own container
|
||||||
if (message.ID != ContainerId)
|
if (message.ID != ContainerId)
|
||||||
return ValueTask.CompletedTask;
|
return;
|
||||||
|
|
||||||
// Only handle die events
|
// Only handle die events
|
||||||
if (message.Action != "die")
|
if (message.Action != "die")
|
||||||
return ValueTask.CompletedTask;
|
return;
|
||||||
|
|
||||||
OnExitedSubject.OnNext(message);
|
await OnExitedSubject.OnNextAsync(message);
|
||||||
|
|
||||||
return ValueTask.CompletedTask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Sync()
|
public Task Sync()
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using System.Reactive.Linq;
|
using MoonCore.Observability;
|
||||||
using System.Reactive.Subjects;
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
using MoonlightServers.Daemon.ServerSys.Abstractions;
|
||||||
|
|
||||||
namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
namespace MoonlightServers.Daemon.ServerSys.Implementations;
|
||||||
|
|
||||||
public class DockerStatistics : IStatistics
|
public class DockerStatistics : IStatistics
|
||||||
{
|
{
|
||||||
public IAsyncObservable<ServerStats> OnStats => OnStatsSubject.ToAsyncObservable();
|
public IAsyncObservable<ServerStats> OnStats => OnStatsSubject;
|
||||||
|
|
||||||
private readonly Subject<ServerStats> OnStatsSubject = new();
|
private readonly EventSubject<ServerStats> OnStatsSubject = new();
|
||||||
|
|
||||||
public Task Initialize()
|
public Task Initialize()
|
||||||
=> Task.CompletedTask;
|
=> Task.CompletedTask;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ using System.Reactive.Linq;
|
|||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using Docker.DotNet;
|
using Docker.DotNet;
|
||||||
using Docker.DotNet.Models;
|
using Docker.DotNet.Models;
|
||||||
|
using MoonCore.Observability;
|
||||||
|
using MoonlightServers.Daemon.Helpers;
|
||||||
|
|
||||||
namespace MoonlightServers.Daemon.Services;
|
namespace MoonlightServers.Daemon.Services;
|
||||||
|
|
||||||
@@ -11,13 +13,13 @@ public class DockerEventService : BackgroundService
|
|||||||
private readonly ILogger<DockerEventService> Logger;
|
private readonly ILogger<DockerEventService> Logger;
|
||||||
private readonly DockerClient DockerClient;
|
private readonly DockerClient DockerClient;
|
||||||
|
|
||||||
public IAsyncObservable<Message> OnContainerEvent => OnContainerSubject.ToAsyncObservable().ObserveOn(TaskPoolAsyncScheduler.Default);
|
public IAsyncObservable<Message> OnContainerEvent => OnContainerSubject;
|
||||||
public IAsyncObservable<Message> OnImageEvent => OnImageSubject.ToAsyncObservable().ObserveOn(TaskPoolAsyncScheduler.Default);
|
public IAsyncObservable<Message> OnImageEvent => OnImageSubject;
|
||||||
public IAsyncObservable<Message> OnNetworkEvent => OnNetworkSubject.ToAsyncObservable().ObserveOn(TaskPoolAsyncScheduler.Default);
|
public IAsyncObservable<Message> OnNetworkEvent => OnNetworkSubject;
|
||||||
|
|
||||||
private readonly Subject<Message> OnContainerSubject = new();
|
private readonly EventSubject<Message> OnContainerSubject = new();
|
||||||
private readonly Subject<Message> OnImageSubject = new();
|
private readonly EventSubject<Message> OnImageSubject = new();
|
||||||
private readonly Subject<Message> OnNetworkSubject = new();
|
private readonly EventSubject<Message> OnNetworkSubject = new();
|
||||||
|
|
||||||
public DockerEventService(
|
public DockerEventService(
|
||||||
ILogger<DockerEventService> logger,
|
ILogger<DockerEventService> logger,
|
||||||
@@ -38,22 +40,22 @@ public class DockerEventService : BackgroundService
|
|||||||
{
|
{
|
||||||
await DockerClient.System.MonitorEventsAsync(
|
await DockerClient.System.MonitorEventsAsync(
|
||||||
new ContainerEventsParameters(),
|
new ContainerEventsParameters(),
|
||||||
new Progress<Message>(message =>
|
new Progress<Message>(async message =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
switch (message.Type)
|
switch (message.Type)
|
||||||
{
|
{
|
||||||
case "container":
|
case "container":
|
||||||
OnContainerSubject.OnNext(message);
|
await OnContainerSubject.OnNextAsync(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "image":
|
case "image":
|
||||||
OnImageSubject.OnNext(message);
|
await OnImageSubject.OnNextAsync(message);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "network":
|
case "network":
|
||||||
OnNetworkSubject.OnNext(message);
|
await OnNetworkSubject.OnNextAsync(message);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ using MoonCore.Extended.Extensions;
|
|||||||
using MoonCore.Extensions;
|
using MoonCore.Extensions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
using MoonCore.Logging;
|
using MoonCore.Logging;
|
||||||
|
using MoonCore.Observability;
|
||||||
using MoonlightServers.Daemon.Configuration;
|
using MoonlightServers.Daemon.Configuration;
|
||||||
|
using MoonlightServers.Daemon.Extensions;
|
||||||
using MoonlightServers.Daemon.Helpers;
|
using MoonlightServers.Daemon.Helpers;
|
||||||
using MoonlightServers.Daemon.Http.Hubs;
|
using MoonlightServers.Daemon.Http.Hubs;
|
||||||
using MoonlightServers.Daemon.Mappers;
|
using MoonlightServers.Daemon.Mappers;
|
||||||
@@ -108,9 +110,13 @@ public class Startup
|
|||||||
var server = factory.CreateServer(config);
|
var server = factory.CreateServer(config);
|
||||||
|
|
||||||
await using var consoleSub = await server.Console.OnOutput
|
await using var consoleSub = await server.Console.OnOutput
|
||||||
.SubscribeAsync(Console.Write);
|
.SubscribeEventAsync(line =>
|
||||||
|
{
|
||||||
|
Console.Write(line);
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
});
|
||||||
|
|
||||||
await using var stateSub = await server.OnState.SubscribeAsync(state =>
|
await using var stateSub = await server.OnState.SubscribeEventAsync(state =>
|
||||||
{
|
{
|
||||||
Console.WriteLine($"State: {state}");
|
Console.WriteLine($"State: {state}");
|
||||||
return ValueTask.CompletedTask;
|
return ValueTask.CompletedTask;
|
||||||
|
|||||||
Reference in New Issue
Block a user