mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2024-11-25 07:42:58 +01:00
Compare commits
2 Commits
c99f5bc6bf
...
424dccb14e
Author | SHA1 | Date | |
---|---|---|---|
424dccb14e | |||
d03f532996 |
@ -6,13 +6,13 @@ using Phantom.Agent.Minecraft.Properties;
|
||||
using Phantom.Agent.Minecraft.Server;
|
||||
using Phantom.Agent.Rpc;
|
||||
using Phantom.Agent.Services.Backups;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
using Phantom.Utils.IO;
|
||||
using Phantom.Utils.Logging;
|
||||
using Phantom.Utils.Tasks;
|
||||
using Serilog;
|
||||
|
||||
namespace Phantom.Agent.Services.Instances;
|
||||
@ -49,10 +49,10 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
||||
|
||||
this.instanceServices = new InstanceServices(init.ControllerConnection, init.BackupManager, launchServices);
|
||||
|
||||
ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
|
||||
ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
||||
ReceiveAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendCommandToInstance);
|
||||
ReceiveAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
|
||||
ReceiveAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||
ReceiveAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendCommandToInstance);
|
||||
ReceiveAsync<ShutdownCommand>(Shutdown);
|
||||
}
|
||||
|
||||
@ -65,17 +65,17 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
||||
|
||||
public interface ICommand {}
|
||||
|
||||
public sealed record ConfigureInstanceCommand(Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool LaunchNow, bool AlwaysReportStatus) : ICommand, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
|
||||
public sealed record ConfigureInstanceCommand(Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool LaunchNow, bool AlwaysReportStatus) : ICommand, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record LaunchInstanceCommand(Guid InstanceGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
||||
public sealed record LaunchInstanceCommand(Guid InstanceGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record StopInstanceCommand(Guid InstanceGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
||||
public sealed record StopInstanceCommand(Guid InstanceGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
||||
public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record ShutdownCommand : ICommand;
|
||||
|
||||
private InstanceActionResult<ConfigureInstanceResult> ConfigureInstance(ConfigureInstanceCommand command) {
|
||||
private Result<ConfigureInstanceResult, InstanceActionFailure> ConfigureInstance(ConfigureInstanceCommand command) {
|
||||
var instanceGuid = command.InstanceGuid;
|
||||
var configuration = command.Configuration;
|
||||
|
||||
@ -130,64 +130,64 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
||||
LaunchInstance(new LaunchInstanceCommand(instanceGuid));
|
||||
}
|
||||
|
||||
return InstanceActionResult.Concrete(ConfigureInstanceResult.Success);
|
||||
return ConfigureInstanceResult.Success;
|
||||
}
|
||||
|
||||
private InstanceActionResult<LaunchInstanceResult> LaunchInstance(LaunchInstanceCommand command) {
|
||||
private Result<LaunchInstanceResult, InstanceActionFailure> LaunchInstance(LaunchInstanceCommand command) {
|
||||
var instanceGuid = command.InstanceGuid;
|
||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||
return InstanceActionResult.General<LaunchInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
||||
return InstanceActionFailure.InstanceDoesNotExist;
|
||||
}
|
||||
|
||||
var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
|
||||
if (ticket is Result<InstanceTicketManager.Ticket, LaunchInstanceResult>.Fail fail) {
|
||||
return InstanceActionResult.Concrete(fail.Error);
|
||||
if (!ticket) {
|
||||
return ticket.Error;
|
||||
}
|
||||
|
||||
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||
var status = instance.Status;
|
||||
if (status.IsRunning()) {
|
||||
return InstanceActionResult.Concrete(LaunchInstanceResult.InstanceAlreadyRunning);
|
||||
return LaunchInstanceResult.InstanceAlreadyRunning;
|
||||
}
|
||||
else if (status.IsLaunching()) {
|
||||
return InstanceActionResult.Concrete(LaunchInstanceResult.InstanceAlreadyLaunching);
|
||||
return LaunchInstanceResult.InstanceAlreadyLaunching;
|
||||
}
|
||||
}
|
||||
|
||||
instanceInfo.Actor.Tell(new InstanceActor.LaunchInstanceCommand(instanceInfo.Configuration, instanceInfo.Launcher, ticket.Value, IsRestarting: false));
|
||||
return InstanceActionResult.Concrete(LaunchInstanceResult.LaunchInitiated);
|
||||
return LaunchInstanceResult.LaunchInitiated;
|
||||
}
|
||||
|
||||
private InstanceActionResult<StopInstanceResult> StopInstance(StopInstanceCommand command) {
|
||||
private Result<StopInstanceResult, InstanceActionFailure> StopInstance(StopInstanceCommand command) {
|
||||
var instanceGuid = command.InstanceGuid;
|
||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||
return InstanceActionResult.General<StopInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
||||
return InstanceActionFailure.InstanceDoesNotExist;
|
||||
}
|
||||
|
||||
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||
var status = instance.Status;
|
||||
if (status.IsStopping()) {
|
||||
return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopping);
|
||||
return StopInstanceResult.InstanceAlreadyStopping;
|
||||
}
|
||||
else if (!status.CanStop()) {
|
||||
return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopped);
|
||||
return StopInstanceResult.InstanceAlreadyStopped;
|
||||
}
|
||||
}
|
||||
|
||||
instanceInfo.Actor.Tell(new InstanceActor.StopInstanceCommand(command.StopStrategy));
|
||||
return InstanceActionResult.Concrete(StopInstanceResult.StopInitiated);
|
||||
return StopInstanceResult.StopInitiated;
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<SendCommandToInstanceResult>> SendCommandToInstance(SendCommandToInstanceCommand command) {
|
||||
private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendCommandToInstance(SendCommandToInstanceCommand command) {
|
||||
var instanceGuid = command.InstanceGuid;
|
||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||
return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
||||
return InstanceActionFailure.InstanceDoesNotExist;
|
||||
}
|
||||
|
||||
try {
|
||||
return InstanceActionResult.Concrete(await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command), shutdownCancellationToken));
|
||||
return await instanceInfo.Actor.Request(new InstanceActor.SendCommandToInstanceCommand(command.Command), shutdownCancellationToken);
|
||||
} catch (OperationCanceledException) {
|
||||
return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.AgentShuttingDown);
|
||||
return InstanceActionFailure.AgentShuttingDown;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
using Phantom.Agent.Minecraft.Instance;
|
||||
using Phantom.Agent.Minecraft.Launcher;
|
||||
using Phantom.Agent.Minecraft.Server;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Utils.Tasks;
|
||||
|
||||
namespace Phantom.Agent.Services.Instances.State;
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Phantom.Agent.Services.Instances;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Messages.Agent;
|
||||
@ -32,10 +33,10 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
|
||||
|
||||
ReceiveAsync<RegisterAgentSuccessMessage>(HandleRegisterAgentSuccess);
|
||||
Receive<RegisterAgentFailureMessage>(HandleRegisterAgentFailure);
|
||||
ReceiveAndReplyLater<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(HandleConfigureInstance);
|
||||
ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
|
||||
ReceiveAndReplyLater<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(HandleConfigureInstance);
|
||||
ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
|
||||
Receive<ReplyMessage>(HandleReply);
|
||||
}
|
||||
|
||||
@ -74,23 +75,23 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<ConfigureInstanceResult>> HandleConfigureInstance(ConfigureInstanceMessage message, bool alwaysReportStatus) {
|
||||
private Task<Result<ConfigureInstanceResult, InstanceActionFailure>> HandleConfigureInstance(ConfigureInstanceMessage message, bool alwaysReportStatus) {
|
||||
return agent.InstanceManager.Request(new InstanceManagerActor.ConfigureInstanceCommand(message.InstanceGuid, message.Configuration, message.LaunchProperties, message.LaunchNow, alwaysReportStatus));
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<ConfigureInstanceResult>> HandleConfigureInstance(ConfigureInstanceMessage message) {
|
||||
private async Task<Result<ConfigureInstanceResult, InstanceActionFailure>> HandleConfigureInstance(ConfigureInstanceMessage message) {
|
||||
return await HandleConfigureInstance(message, alwaysReportStatus: false);
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message) {
|
||||
private async Task<Result<LaunchInstanceResult, InstanceActionFailure>> HandleLaunchInstance(LaunchInstanceMessage message) {
|
||||
return await agent.InstanceManager.Request(new InstanceManagerActor.LaunchInstanceCommand(message.InstanceGuid));
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<StopInstanceResult>> HandleStopInstance(StopInstanceMessage message) {
|
||||
private async Task<Result<StopInstanceResult, InstanceActionFailure>> HandleStopInstance(StopInstanceMessage message) {
|
||||
return await agent.InstanceManager.Request(new InstanceManagerActor.StopInstanceCommand(message.InstanceGuid, message.StopStrategy));
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<SendCommandToInstanceResult>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
|
||||
private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
|
||||
return await agent.InstanceManager.Request(new InstanceManagerActor.SendCommandToInstanceCommand(message.InstanceGuid, message.Command));
|
||||
}
|
||||
|
||||
|
20
Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs
Normal file
20
Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum InstanceActionFailure : byte {
|
||||
AgentDoesNotExist,
|
||||
AgentShuttingDown,
|
||||
AgentIsNotResponding,
|
||||
InstanceDoesNotExist
|
||||
}
|
||||
|
||||
public static class InstanceActionFailureExtensions {
|
||||
public static string ToSentence(this InstanceActionFailure failure) {
|
||||
return failure switch {
|
||||
InstanceActionFailure.AgentDoesNotExist => "Agent does not exist.",
|
||||
InstanceActionFailure.AgentShuttingDown => "Agent is shutting down.",
|
||||
InstanceActionFailure.AgentIsNotResponding => "Agent is not responding.",
|
||||
InstanceActionFailure.InstanceDoesNotExist => "Instance does not exist.",
|
||||
_ => "Unknown error."
|
||||
};
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
public enum InstanceActionGeneralResult : byte {
|
||||
None,
|
||||
AgentDoesNotExist,
|
||||
AgentShuttingDown,
|
||||
AgentIsNotResponding,
|
||||
InstanceDoesNotExist
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Replies;
|
||||
|
||||
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||
public sealed partial record InstanceActionResult<T>(
|
||||
[property: MemoryPackOrder(0)] InstanceActionGeneralResult GeneralResult,
|
||||
[property: MemoryPackOrder(1)] T? ConcreteResult
|
||||
) {
|
||||
public bool Is(T? concreteResult) {
|
||||
return GeneralResult == InstanceActionGeneralResult.None && EqualityComparer<T>.Default.Equals(ConcreteResult, concreteResult);
|
||||
}
|
||||
|
||||
public InstanceActionResult<T2> Map<T2>(Func<T, T2> mapper) {
|
||||
return new InstanceActionResult<T2>(GeneralResult, ConcreteResult is not null ? mapper(ConcreteResult) : default);
|
||||
}
|
||||
|
||||
public string ToSentence(Func<T, string> concreteResultToSentence) {
|
||||
return GeneralResult switch {
|
||||
InstanceActionGeneralResult.None => concreteResultToSentence(ConcreteResult!),
|
||||
InstanceActionGeneralResult.AgentDoesNotExist => "Agent does not exist.",
|
||||
InstanceActionGeneralResult.AgentShuttingDown => "Agent is shutting down.",
|
||||
InstanceActionGeneralResult.AgentIsNotResponding => "Agent is not responding.",
|
||||
InstanceActionGeneralResult.InstanceDoesNotExist => "Instance does not exist.",
|
||||
_ => "Unknown result."
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class InstanceActionResult {
|
||||
public static InstanceActionResult<T> General<T>(InstanceActionGeneralResult generalResult) {
|
||||
return new InstanceActionResult<T>(generalResult, default);
|
||||
}
|
||||
|
||||
public static InstanceActionResult<T> Concrete<T>(T? concreteResult) {
|
||||
return new InstanceActionResult<T>(InstanceActionGeneralResult.None, concreteResult);
|
||||
}
|
||||
|
||||
public static InstanceActionResult<T> DidNotReplyIfNull<T>(this InstanceActionResult<T>? result) {
|
||||
return result ?? General<T>(InstanceActionGeneralResult.AgentIsNotResponding);
|
||||
}
|
||||
}
|
99
Common/Phantom.Common.Data/Result.cs
Normal file
99
Common/Phantom.Common.Data/Result.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data;
|
||||
|
||||
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||
public sealed partial class Result<TValue, TError> {
|
||||
[MemoryPackOrder(0)]
|
||||
[MemoryPackInclude]
|
||||
private readonly bool hasValue;
|
||||
|
||||
[MemoryPackOrder(1)]
|
||||
[MemoryPackInclude]
|
||||
private readonly TValue? value;
|
||||
|
||||
[MemoryPackOrder(2)]
|
||||
[MemoryPackInclude]
|
||||
private readonly TError? error;
|
||||
|
||||
[MemoryPackIgnore]
|
||||
public TValue Value => hasValue ? value! : throw new InvalidOperationException("Attempted to get value from an error result.");
|
||||
|
||||
[MemoryPackIgnore]
|
||||
public TError Error => !hasValue ? error! : throw new InvalidOperationException("Attempted to get error from a success result.");
|
||||
|
||||
private Result(bool hasValue, TValue? value, TError? error) {
|
||||
this.hasValue = hasValue;
|
||||
this.value = value;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public bool Is(TValue expectedValue) {
|
||||
return hasValue && EqualityComparer<TValue>.Default.Equals(value, expectedValue);
|
||||
}
|
||||
|
||||
public TOutput Map<TOutput>(Func<TValue, TOutput> valueConverter, Func<TError, TOutput> errorConverter) {
|
||||
return hasValue ? valueConverter(value!) : errorConverter(error!);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TValue, TError>(TValue value) {
|
||||
return new Result<TValue, TError>(hasValue: true, value, default);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TValue, TError>(TError error) {
|
||||
return new Result<TValue, TError>(hasValue: false, default, error);
|
||||
}
|
||||
|
||||
public static implicit operator bool(Result<TValue, TError> result) {
|
||||
return result.hasValue;
|
||||
}
|
||||
}
|
||||
|
||||
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||
public sealed partial class Result<TError> {
|
||||
[MemoryPackOrder(0)]
|
||||
[MemoryPackInclude]
|
||||
private readonly bool hasValue;
|
||||
|
||||
[MemoryPackOrder(1)]
|
||||
[MemoryPackInclude]
|
||||
private readonly TError? error;
|
||||
|
||||
[MemoryPackIgnore]
|
||||
public TError Error => !hasValue ? error! : throw new InvalidOperationException("Attempted to get error from a success result.");
|
||||
|
||||
private Result(bool hasValue, TError? error) {
|
||||
this.hasValue = hasValue;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public bool TryGetError([MaybeNullWhen(false)] out TError error) {
|
||||
if (hasValue) {
|
||||
error = default;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
error = this.error!;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator Result<TError>([SuppressMessage("ReSharper", "UnusedParameter.Global")] Result.OkType _) {
|
||||
return new Result<TError>(hasValue: true, default);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TError>(TError error) {
|
||||
return new Result<TError>(hasValue: false, error);
|
||||
}
|
||||
|
||||
public static implicit operator bool(Result<TError> result) {
|
||||
return result.hasValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
public static OkType Ok { get; } = new ();
|
||||
|
||||
public readonly record struct OkType;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Messages.Agent.BiDirectional;
|
||||
using Phantom.Common.Messages.Agent.ToAgent;
|
||||
using Phantom.Common.Messages.Agent.ToController;
|
||||
@ -16,10 +17,10 @@ public static class AgentMessageRegistries {
|
||||
static AgentMessageRegistries() {
|
||||
ToAgent.Add<RegisterAgentSuccessMessage>(0);
|
||||
ToAgent.Add<RegisterAgentFailureMessage>(1);
|
||||
ToAgent.Add<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(2);
|
||||
ToAgent.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(3);
|
||||
ToAgent.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(4);
|
||||
ToAgent.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(5);
|
||||
ToAgent.Add<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(2);
|
||||
ToAgent.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(3);
|
||||
ToAgent.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(4);
|
||||
ToAgent.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(5);
|
||||
ToAgent.Add<ReplyMessage>(127);
|
||||
|
||||
ToController.Add<RegisterAgentMessage>(0);
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
@ -11,4 +12,4 @@ public sealed partial record ConfigureInstanceMessage(
|
||||
[property: MemoryPackOrder(1)] InstanceConfiguration Configuration,
|
||||
[property: MemoryPackOrder(2)] InstanceLaunchProperties LaunchProperties,
|
||||
[property: MemoryPackOrder(3)] bool LaunchNow = false
|
||||
) : IMessageToAgent, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
|
||||
) : IMessageToAgent, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
|
||||
@ -7,4 +8,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
||||
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||
public sealed partial record LaunchInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] Guid InstanceGuid
|
||||
) : IMessageToAgent, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
||||
) : IMessageToAgent, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
|
||||
@ -8,4 +9,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
||||
public sealed partial record SendCommandToInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(1)] string Command
|
||||
) : IMessageToAgent, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
||||
) : IMessageToAgent, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
@ -9,4 +10,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
||||
public sealed partial record StopInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(1)] MinecraftStopStrategy StopStrategy
|
||||
) : IMessageToAgent, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
||||
) : IMessageToAgent, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Data.Web.Instance;
|
||||
@ -11,4 +12,4 @@ public sealed partial record CreateOrUpdateInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
||||
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(2)] InstanceConfiguration Configuration
|
||||
) : IMessageToController, ICanReply<InstanceActionResult<CreateOrUpdateInstanceResult>>;
|
||||
) : IMessageToController, ICanReply<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
|
||||
@ -9,4 +10,4 @@ public sealed partial record LaunchInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||
[property: MemoryPackOrder(2)] Guid InstanceGuid
|
||||
) : IMessageToController, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
||||
) : IMessageToController, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
|
||||
@ -10,4 +11,4 @@ public sealed partial record SendCommandToInstanceMessage(
|
||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(3)] string Command
|
||||
) : IMessageToController, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
||||
) : IMessageToController, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Utils.Actor;
|
||||
@ -11,4 +12,4 @@ public sealed partial record StopInstanceMessage(
|
||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(3)] MinecraftStopStrategy StopStrategy
|
||||
) : IMessageToController, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
||||
) : IMessageToController, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||
|
@ -34,10 +34,10 @@ public static class WebMessageRegistries {
|
||||
ToController.Add<GetRolesMessage, ImmutableArray<RoleInfo>>(9);
|
||||
ToController.Add<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(10);
|
||||
ToController.Add<ChangeUserRolesMessage, ChangeUserRolesResult>(11);
|
||||
ToController.Add<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(12);
|
||||
ToController.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(13);
|
||||
ToController.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(14);
|
||||
ToController.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(15);
|
||||
ToController.Add<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(12);
|
||||
ToController.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(13);
|
||||
ToController.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(14);
|
||||
ToController.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(15);
|
||||
ToController.Add<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(16);
|
||||
ToController.Add<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(17);
|
||||
ToController.Add<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(18);
|
||||
|
@ -1,9 +1,9 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Web.Users;
|
||||
using Phantom.Controller.Database.Entities;
|
||||
using Phantom.Utils.Collections;
|
||||
using Phantom.Utils.Tasks;
|
||||
|
||||
namespace Phantom.Controller.Database.Repositories;
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Web.Users;
|
||||
using Phantom.Common.Data.Web.Users.AddUserErrors;
|
||||
using Phantom.Common.Data.Web.Users.PasswordRequirementViolations;
|
||||
using Phantom.Common.Data.Web.Users.UsernameRequirementViolations;
|
||||
using Phantom.Controller.Database.Entities;
|
||||
using Phantom.Utils.Collections;
|
||||
using Phantom.Utils.Tasks;
|
||||
|
||||
namespace Phantom.Controller.Database.Repositories;
|
||||
|
||||
|
@ -92,11 +92,11 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
Receive<NotifyIsAliveCommand>(NotifyIsAlive);
|
||||
Receive<UpdateStatsCommand>(UpdateStats);
|
||||
Receive<UpdateJavaRuntimesCommand>(UpdateJavaRuntimes);
|
||||
ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, InstanceActionResult<CreateOrUpdateInstanceResult>>(CreateOrUpdateInstance);
|
||||
ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstance);
|
||||
Receive<UpdateInstanceStatusCommand>(UpdateInstanceStatus);
|
||||
ReceiveAndReplyLater<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
|
||||
ReceiveAndReplyLater<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
|
||||
Receive<ReceiveInstanceDataCommand>(ReceiveInstanceData);
|
||||
}
|
||||
|
||||
@ -144,13 +144,13 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
}
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<TReply>> RequestInstance<TCommand, TReply>(Guid instanceGuid, TCommand command) where TCommand : InstanceActor.ICommand, ICanReply<InstanceActionResult<TReply>> {
|
||||
private Task<Result<TReply, InstanceActionFailure>> RequestInstance<TCommand, TReply>(Guid instanceGuid, TCommand command) where TCommand : InstanceActor.ICommand, ICanReply<Result<TReply, InstanceActionFailure>> {
|
||||
if (instanceActorByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||
return instance.Request(command, cancellationToken);
|
||||
}
|
||||
else {
|
||||
Logger.Warning("Could not deliver command {CommandType} to instance {InstanceGuid}, instance not found.", command.GetType().Name, instanceGuid);
|
||||
return Task.FromResult(InstanceActionResult.General<TReply>(InstanceActionGeneralResult.InstanceDoesNotExist));
|
||||
return Task.FromResult<Result<TReply, InstanceActionFailure>>(InstanceActionFailure.InstanceDoesNotExist);
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,15 +181,15 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
|
||||
public sealed record UpdateJavaRuntimesCommand(ImmutableArray<TaggedJavaRuntime> JavaRuntimes) : ICommand;
|
||||
|
||||
public sealed record CreateOrUpdateInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration) : ICommand, ICanReply<InstanceActionResult<CreateOrUpdateInstanceResult>>;
|
||||
public sealed record CreateOrUpdateInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration) : ICommand, ICanReply<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record UpdateInstanceStatusCommand(Guid InstanceGuid, IInstanceStatus Status) : ICommand;
|
||||
|
||||
public sealed record LaunchInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
||||
public sealed record LaunchInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record StopInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
||||
public sealed record StopInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
||||
public sealed record SendCommandToInstanceCommand(Guid InstanceGuid, Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record ReceiveInstanceDataCommand(Instance Instance) : ICommand, IJumpAhead;
|
||||
|
||||
@ -270,15 +270,15 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
controllerState.UpdateAgentJavaRuntimes(agentGuid, javaRuntimes);
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
|
||||
private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
|
||||
var instanceConfiguration = command.Configuration;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(instanceConfiguration.InstanceName)) {
|
||||
return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.InstanceNameMustNotBeEmpty));
|
||||
return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.InstanceNameMustNotBeEmpty);
|
||||
}
|
||||
|
||||
if (instanceConfiguration.MemoryAllocation <= RamAllocationUnits.Zero) {
|
||||
return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.InstanceMemoryMustNotBeZero));
|
||||
return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.InstanceMemoryMustNotBeZero);
|
||||
}
|
||||
|
||||
return minecraftVersions.GetServerExecutableInfo(instanceConfiguration.MinecraftVersion, cancellationToken)
|
||||
@ -286,9 +286,9 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
.Unwrap();
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
|
||||
private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
|
||||
if (serverExecutableInfo == null) {
|
||||
return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound));
|
||||
return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound);
|
||||
}
|
||||
|
||||
var instanceConfiguration = command.Configuration;
|
||||
@ -304,7 +304,7 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
.ContinueOnActor(CreateOrUpdateInstance2, configureInstanceCommand);
|
||||
}
|
||||
|
||||
private InstanceActionResult<CreateOrUpdateInstanceResult> CreateOrUpdateInstance2(InstanceActionResult<ConfigureInstanceResult> result, InstanceActor.ConfigureInstanceCommand command) {
|
||||
private Result<CreateOrUpdateInstanceResult, InstanceActionFailure> CreateOrUpdateInstance2(Result<ConfigureInstanceResult, InstanceActionFailure> result, InstanceActor.ConfigureInstanceCommand command) {
|
||||
var instanceGuid = command.InstanceGuid;
|
||||
var instanceName = command.Configuration.InstanceName;
|
||||
var isCreating = command.IsCreatingInstance;
|
||||
@ -312,33 +312,35 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
||||
if (result.Is(ConfigureInstanceResult.Success)) {
|
||||
string action = isCreating ? "Added" : "Edited";
|
||||
string relation = isCreating ? "to agent" : "in agent";
|
||||
|
||||
Logger.Information(action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\".", instanceName, instanceGuid, configuration.AgentName);
|
||||
|
||||
return CreateOrUpdateInstanceResult.Success;
|
||||
}
|
||||
else {
|
||||
string action = isCreating ? "adding" : "editing";
|
||||
string relation = isCreating ? "to agent" : "in agent";
|
||||
Logger.Information("Failed " + action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\". {ErrorMessage}", instanceName, instanceGuid, configuration.AgentName, result.ToSentence(ConfigureInstanceResultExtensions.ToSentence));
|
||||
string reason = result.Map(ConfigureInstanceResultExtensions.ToSentence, InstanceActionFailureExtensions.ToSentence);
|
||||
|
||||
Logger.Information("Failed " + action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\". {ErrorMessage}", instanceName, instanceGuid, configuration.AgentName, reason);
|
||||
|
||||
return CreateOrUpdateInstanceResult.UnknownError;
|
||||
}
|
||||
|
||||
return result.Map(static result => result switch {
|
||||
ConfigureInstanceResult.Success => CreateOrUpdateInstanceResult.Success,
|
||||
_ => CreateOrUpdateInstanceResult.UnknownError
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateInstanceStatus(UpdateInstanceStatusCommand command) {
|
||||
TellInstance(command.InstanceGuid, new InstanceActor.SetStatusCommand(command.Status));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(LaunchInstanceCommand command) {
|
||||
private Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(LaunchInstanceCommand command) {
|
||||
return RequestInstance<InstanceActor.LaunchInstanceCommand, LaunchInstanceResult>(command.InstanceGuid, new InstanceActor.LaunchInstanceCommand(command.AuditLogUserGuid));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<StopInstanceResult>> StopInstance(StopInstanceCommand command) {
|
||||
private Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(StopInstanceCommand command) {
|
||||
return RequestInstance<InstanceActor.StopInstanceCommand, StopInstanceResult>(command.InstanceGuid, new InstanceActor.StopInstanceCommand(command.AuditLogUserGuid, command.StopStrategy));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<SendCommandToInstanceResult>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
|
||||
private Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
|
||||
return RequestInstance<InstanceActor.SendCommandToInstanceCommand, SendCommandToInstanceResult>(command.InstanceGuid, new InstanceActor.SendCommandToInstanceCommand(command.AuditLogUserGuid, command.Command));
|
||||
}
|
||||
|
||||
|
@ -83,12 +83,7 @@ sealed class AgentManager {
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<InstanceActionResult<TReply>> DoInstanceAction<TCommand, TReply>(Guid agentGuid, TCommand command) where TCommand : class, AgentActor.ICommand, ICanReply<InstanceActionResult<TReply>> {
|
||||
if (agentsByGuid.TryGetValue(agentGuid, out var agent)) {
|
||||
return await agent.Request(command, cancellationToken);
|
||||
}
|
||||
else {
|
||||
return InstanceActionResult.General<TReply>(InstanceActionGeneralResult.AgentDoesNotExist);
|
||||
}
|
||||
public async Task<Result<TReply, InstanceActionFailure>> DoInstanceAction<TCommand, TReply>(Guid agentGuid, TCommand command) where TCommand : class, AgentActor.ICommand, ICanReply<Result<TReply, InstanceActionFailure>> {
|
||||
return agentsByGuid.TryGetValue(agentGuid, out var agent) ? await agent.Request(command, cancellationToken) : InstanceActionFailure.AgentDoesNotExist;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
using Phantom.Common.Data.Replies;
|
||||
using Phantom.Common.Data.Web.Instance;
|
||||
@ -39,10 +40,10 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
||||
this.databaseStorageActor = Context.ActorOf(InstanceDatabaseStorageActor.Factory(new InstanceDatabaseStorageActor.Init(instanceGuid, init.DbProvider, init.CancellationToken)), "DatabaseStorage");
|
||||
|
||||
Receive<SetStatusCommand>(SetStatus);
|
||||
ReceiveAsyncAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
|
||||
ReceiveAsyncAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
||||
ReceiveAsyncAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
|
||||
ReceiveAsyncAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
|
||||
ReceiveAsyncAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||
ReceiveAsyncAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
|
||||
}
|
||||
|
||||
private void NotifyInstanceUpdated() {
|
||||
@ -56,29 +57,29 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<TReply>> SendInstanceActionMessage<TMessage, TReply>(TMessage message) where TMessage : IMessageToAgent, ICanReply<InstanceActionResult<TReply>> {
|
||||
var reply = await agentConnection.Send<TMessage, InstanceActionResult<TReply>>(message, TimeSpan.FromSeconds(10), cancellationToken);
|
||||
return reply.DidNotReplyIfNull();
|
||||
private async Task<Result<TReply, InstanceActionFailure>> SendInstanceActionMessage<TMessage, TReply>(TMessage message) where TMessage : IMessageToAgent, ICanReply<Result<TReply, InstanceActionFailure>> {
|
||||
var reply = await agentConnection.Send<TMessage, Result<TReply, InstanceActionFailure>>(message, TimeSpan.FromSeconds(10), cancellationToken);
|
||||
return reply ?? InstanceActionFailure.AgentIsNotResponding;
|
||||
}
|
||||
|
||||
public interface ICommand {}
|
||||
|
||||
public sealed record SetStatusCommand(IInstanceStatus Status) : ICommand;
|
||||
|
||||
public sealed record ConfigureInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool IsCreatingInstance) : ICommand, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
|
||||
public sealed record ConfigureInstanceCommand(Guid AuditLogUserGuid, Guid InstanceGuid, InstanceConfiguration Configuration, InstanceLaunchProperties LaunchProperties, bool IsCreatingInstance) : ICommand, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record LaunchInstanceCommand(Guid AuditLogUserGuid) : ICommand, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
||||
public sealed record LaunchInstanceCommand(Guid AuditLogUserGuid) : ICommand, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record StopInstanceCommand(Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
||||
public sealed record StopInstanceCommand(Guid AuditLogUserGuid, MinecraftStopStrategy StopStrategy) : ICommand, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
public sealed record SendCommandToInstanceCommand(Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
||||
public sealed record SendCommandToInstanceCommand(Guid AuditLogUserGuid, string Command) : ICommand, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||
|
||||
private void SetStatus(SetStatusCommand command) {
|
||||
status = command.Status;
|
||||
NotifyInstanceUpdated();
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<ConfigureInstanceResult>> ConfigureInstance(ConfigureInstanceCommand command) {
|
||||
private async Task<Result<ConfigureInstanceResult, InstanceActionFailure>> ConfigureInstance(ConfigureInstanceCommand command) {
|
||||
var message = new ConfigureInstanceMessage(command.InstanceGuid, command.Configuration, command.LaunchProperties);
|
||||
var result = await SendInstanceActionMessage<ConfigureInstanceMessage, ConfigureInstanceResult>(message);
|
||||
|
||||
@ -98,7 +99,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(LaunchInstanceCommand command) {
|
||||
private async Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(LaunchInstanceCommand command) {
|
||||
var message = new LaunchInstanceMessage(instanceGuid);
|
||||
var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(message);
|
||||
|
||||
@ -110,7 +111,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<StopInstanceResult>> StopInstance(StopInstanceCommand command) {
|
||||
private async Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(StopInstanceCommand command) {
|
||||
var message = new StopInstanceMessage(instanceGuid, command.StopStrategy);
|
||||
var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(message);
|
||||
|
||||
@ -122,7 +123,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<InstanceActionResult<SendCommandToInstanceResult>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
|
||||
private async Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendMinecraftCommand(SendCommandToInstanceCommand command) {
|
||||
var message = new SendCommandToInstanceMessage(instanceGuid, command.Command);
|
||||
var result = await SendInstanceActionMessage<SendCommandToInstanceMessage, SendCommandToInstanceResult>(message);
|
||||
|
||||
|
@ -80,10 +80,10 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
|
||||
ReceiveAndReplyLater<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(HandleGetUserRoles);
|
||||
ReceiveAndReplyLater<ChangeUserRolesMessage, ChangeUserRolesResult>(HandleChangeUserRoles);
|
||||
ReceiveAndReplyLater<DeleteUserMessage, DeleteUserResult>(HandleDeleteUser);
|
||||
ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(HandleCreateOrUpdateInstance);
|
||||
ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
|
||||
ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(HandleCreateOrUpdateInstance);
|
||||
ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
|
||||
ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
|
||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
|
||||
ReceiveAndReplyLater<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(HandleGetMinecraftVersions);
|
||||
ReceiveAndReply<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(HandleGetAgentJavaRuntimes);
|
||||
ReceiveAndReplyLater<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(HandleGetAuditLog);
|
||||
@ -139,19 +139,19 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
|
||||
return userManager.DeleteByGuid(message.LoggedInUserGuid, message.SubjectUserGuid);
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
|
||||
private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
|
||||
return agentManager.DoInstanceAction<AgentActor.CreateOrUpdateInstanceCommand, CreateOrUpdateInstanceResult>(message.Configuration.AgentGuid, new AgentActor.CreateOrUpdateInstanceCommand(message.LoggedInUserGuid, message.InstanceGuid, message.Configuration));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message) {
|
||||
private Task<Result<LaunchInstanceResult, InstanceActionFailure>> HandleLaunchInstance(LaunchInstanceMessage message) {
|
||||
return agentManager.DoInstanceAction<AgentActor.LaunchInstanceCommand, LaunchInstanceResult>(message.AgentGuid, new AgentActor.LaunchInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<StopInstanceResult>> HandleStopInstance(StopInstanceMessage message) {
|
||||
private Task<Result<StopInstanceResult, InstanceActionFailure>> HandleStopInstance(StopInstanceMessage message) {
|
||||
return agentManager.DoInstanceAction<AgentActor.StopInstanceCommand, StopInstanceResult>(message.AgentGuid, new AgentActor.StopInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid, message.StopStrategy));
|
||||
}
|
||||
|
||||
private Task<InstanceActionResult<SendCommandToInstanceResult>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
|
||||
private Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> HandleSendCommandToInstance(SendCommandToInstanceMessage message) {
|
||||
return agentManager.DoInstanceAction<AgentActor.SendCommandToInstanceCommand, SendCommandToInstanceResult>(message.AgentGuid, new AgentActor.SendCommandToInstanceCommand(message.InstanceGuid, message.LoggedInUserGuid, message.Command));
|
||||
}
|
||||
|
||||
|
@ -54,9 +54,8 @@ sealed class UserManager {
|
||||
}
|
||||
}
|
||||
else {
|
||||
var result = userRepository.SetUserPassword(user, password);
|
||||
if (!result) {
|
||||
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(result.Error);
|
||||
if (userRepository.SetUserPassword(user, password).TryGetError(out var error)) {
|
||||
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(error);
|
||||
}
|
||||
|
||||
auditLogWriter.AdministratorUserModified(user);
|
||||
|
@ -1,69 +0,0 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Phantom.Utils.Tasks;
|
||||
|
||||
public abstract record Result<TValue, TError> {
|
||||
private Result() {}
|
||||
|
||||
public abstract TValue Value { get; init; }
|
||||
public abstract TError Error { get; init; }
|
||||
|
||||
public static implicit operator Result<TValue, TError>(TValue value) {
|
||||
return new Ok(value);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TValue, TError>(TError error) {
|
||||
return new Fail(error);
|
||||
}
|
||||
|
||||
public static implicit operator bool(Result<TValue, TError> result) {
|
||||
return result is Ok;
|
||||
}
|
||||
|
||||
public sealed record Ok(TValue Value) : Result<TValue, TError> {
|
||||
public override TError Error {
|
||||
get => throw new InvalidOperationException("Attempted to get error from Ok result.");
|
||||
init {}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record Fail(TError Error) : Result<TValue, TError> {
|
||||
public override TValue Value {
|
||||
get => throw new InvalidOperationException("Attempted to get value from Fail result.");
|
||||
init {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract record Result<TError> {
|
||||
private Result() {}
|
||||
|
||||
public abstract TError Error { get; init; }
|
||||
|
||||
public static implicit operator Result<TError>(TError error) {
|
||||
return new Fail(error);
|
||||
}
|
||||
|
||||
public static implicit operator Result<TError>([SuppressMessage("ReSharper", "UnusedParameter.Global")] Result.OkType _) {
|
||||
return new Ok();
|
||||
}
|
||||
|
||||
public static implicit operator bool(Result<TError> result) {
|
||||
return result is Ok;
|
||||
}
|
||||
|
||||
public sealed record Ok : Result<TError> {
|
||||
public override TError Error {
|
||||
get => throw new InvalidOperationException("Attempted to get error from Ok result.");
|
||||
init {}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record Fail(TError Error) : Result<TError>;
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
public static OkType Ok { get; } = new ();
|
||||
|
||||
public readonly record struct OkType;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Immutable;
|
||||
using Phantom.Common.Data;
|
||||
using Phantom.Common.Data.Instance;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
using Phantom.Common.Data.Replies;
|
||||
@ -34,23 +35,23 @@ public sealed class InstanceManager {
|
||||
return instances.Value.GetValueOrDefault(instanceGuid);
|
||||
}
|
||||
|
||||
public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(Guid loggedInUserGuid, Guid instanceGuid, InstanceConfiguration configuration, CancellationToken cancellationToken) {
|
||||
public Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance(Guid loggedInUserGuid, Guid instanceGuid, InstanceConfiguration configuration, CancellationToken cancellationToken) {
|
||||
var message = new CreateOrUpdateInstanceMessage(loggedInUserGuid, instanceGuid, configuration);
|
||||
return controllerConnection.Send<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(message, cancellationToken);
|
||||
return controllerConnection.Send<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(message, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, CancellationToken cancellationToken) {
|
||||
public Task<Result<LaunchInstanceResult, InstanceActionFailure>> LaunchInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, CancellationToken cancellationToken) {
|
||||
var message = new LaunchInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid);
|
||||
return controllerConnection.Send<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(message, cancellationToken);
|
||||
return controllerConnection.Send<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(message, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<InstanceActionResult<StopInstanceResult>> StopInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, MinecraftStopStrategy stopStrategy, CancellationToken cancellationToken) {
|
||||
public Task<Result<StopInstanceResult, InstanceActionFailure>> StopInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, MinecraftStopStrategy stopStrategy, CancellationToken cancellationToken) {
|
||||
var message = new StopInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid, stopStrategy);
|
||||
return controllerConnection.Send<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(message, cancellationToken);
|
||||
return controllerConnection.Send<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(message, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<InstanceActionResult<SendCommandToInstanceResult>> SendCommandToInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, string command, CancellationToken cancellationToken) {
|
||||
public Task<Result<SendCommandToInstanceResult, InstanceActionFailure>> SendCommandToInstance(Guid loggedInUserGuid, Guid agentGuid, Guid instanceGuid, string command, CancellationToken cancellationToken) {
|
||||
var message = new SendCommandToInstanceMessage(loggedInUserGuid, agentGuid, instanceGuid, command);
|
||||
return controllerConnection.Send<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(message, cancellationToken);
|
||||
return controllerConnection.Send<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(message, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ else {
|
||||
|
||||
var result = await InstanceManager.LaunchInstance(loggedInUserGuid.Value, Instance.Configuration.AgentGuid, InstanceGuid, CancellationToken);
|
||||
if (!result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
||||
lastError = result.ToSentence(Messages.ToSentence);
|
||||
lastError = result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence);
|
||||
}
|
||||
} finally {
|
||||
isLaunchingInstance = false;
|
||||
|
@ -1,14 +1,14 @@
|
||||
@page "/setup"
|
||||
@using Phantom.Utils.Tasks
|
||||
@using Phantom.Common.Data
|
||||
@using Phantom.Common.Data.Web.Users
|
||||
@using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
|
||||
@using Phantom.Common.Messages.Web.ToController
|
||||
@using Phantom.Utils.Cryptography
|
||||
@using Phantom.Web.Services
|
||||
@using Phantom.Web.Services.Authentication
|
||||
@using Phantom.Web.Services.Rpc
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Phantom.Utils.Cryptography
|
||||
@using System.Security.Cryptography
|
||||
@using Phantom.Common.Messages.Web.ToController
|
||||
@using Phantom.Common.Data.Web.Users
|
||||
@using Phantom.Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults
|
||||
@attribute [AllowAnonymous]
|
||||
@inject ApplicationProperties ApplicationProperties
|
||||
@inject UserLoginManager LoginManager
|
||||
@ -65,8 +65,9 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (await CreateOrUpdateAdministrator() is Result<string>.Fail fail) {
|
||||
form.SubmitModel.StopSubmitting(fail.Error);
|
||||
var createOrUpdateAdministratorResult = await CreateOrUpdateAdministrator();
|
||||
if (createOrUpdateAdministratorResult.TryGetError(out var error)) {
|
||||
form.SubmitModel.StopSubmitting(error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using System.Diagnostics.CodeAnalysis
|
||||
@using Phantom.Common.Data.Minecraft
|
||||
@using Phantom.Common.Data.Replies
|
||||
@using Phantom.Common.Data.Web.Agent
|
||||
@using Phantom.Common.Data.Web.Instance
|
||||
@using Phantom.Common.Data.Web.Minecraft
|
||||
@ -347,7 +348,7 @@
|
||||
await Navigation.NavigateTo("instances/" + instanceGuid);
|
||||
}
|
||||
else {
|
||||
form.SubmitModel.StopSubmitting(result.ToSentence(CreateOrUpdateInstanceResultExtensions.ToSentence));
|
||||
form.SubmitModel.StopSubmitting(result.Map(CreateOrUpdateInstanceResultExtensions.ToSentence, InstanceActionFailureExtensions.ToSentence));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@
|
||||
form.SubmitModel.StopSubmitting();
|
||||
}
|
||||
else {
|
||||
form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence));
|
||||
form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence));
|
||||
}
|
||||
|
||||
await commandInputElement.FocusAsync(preventScroll: true);
|
||||
|
@ -65,7 +65,7 @@
|
||||
form.SubmitModel.StopSubmitting();
|
||||
}
|
||||
else {
|
||||
form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence));
|
||||
form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence));
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user