diff --git a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs index 38942f7..49cdd28 100644 --- a/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs +++ b/Agent/Phantom.Agent.Services/Instances/InstanceManagerActor.cs @@ -6,6 +6,7 @@ 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; @@ -48,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); } @@ -64,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; @@ -129,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) { - return InstanceActionResult.Concrete(ticket.Error); + 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; } } diff --git a/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs b/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs index c89b893..8e1c439 100644 --- a/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs +++ b/Agent/Phantom.Agent.Services/Rpc/ControllerMessageHandlerActor.cs @@ -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)); } diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs b/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs new file mode 100644 index 0000000..4b57fda --- /dev/null +++ b/Common/Phantom.Common.Data/Replies/InstanceActionFailure.cs @@ -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." + }; + } +} diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs b/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs deleted file mode 100644 index 2cd08b5..0000000 --- a/Common/Phantom.Common.Data/Replies/InstanceActionGeneralResult.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Phantom.Common.Data.Replies; - -public enum InstanceActionGeneralResult : byte { - None, - AgentDoesNotExist, - AgentShuttingDown, - AgentIsNotResponding, - InstanceDoesNotExist -} diff --git a/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs b/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs deleted file mode 100644 index 2ac7b9c..0000000 --- a/Common/Phantom.Common.Data/Replies/InstanceActionResult.cs +++ /dev/null @@ -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); - } -} diff --git a/Common/Phantom.Common.Data/Result.cs b/Common/Phantom.Common.Data/Result.cs index c448812..5fb88f8 100644 --- a/Common/Phantom.Common.Data/Result.cs +++ b/Common/Phantom.Common.Data/Result.cs @@ -29,6 +29,14 @@ public sealed partial class Result<TValue, TError> { 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); } diff --git a/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs b/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs index c93cb57..c3b9c3a 100644 --- a/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs +++ b/Common/Phantom.Common.Messages.Agent/AgentMessageRegistries.cs @@ -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); diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs index 8d4e69f..9472572 100644 --- a/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Agent/ToAgent/ConfigureInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs index 072cb1b..59f958b 100644 --- a/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Agent/ToAgent/LaunchInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs index 26fccef..7055e62 100644 --- a/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Agent/ToAgent/SendCommandToInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs b/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs index 55b1e20..5f74857 100644 --- a/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Agent/ToAgent/StopInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs index 8150fe1..a35cd78 100644 --- a/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Web/ToController/CreateOrUpdateInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs index deed50b..eebcdfa 100644 --- a/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Web/ToController/LaunchInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs index 490aee9..485cc6f 100644 --- a/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Web/ToController/SendCommandToInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs b/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs index 585c3e9..1f0a94a 100644 --- a/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs +++ b/Common/Phantom.Common.Messages.Web/ToController/StopInstanceMessage.cs @@ -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>>; diff --git a/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs b/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs index f1aa4b5..ba0b45c 100644 --- a/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs +++ b/Common/Phantom.Common.Messages.Web/WebMessageRegistries.cs @@ -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); diff --git a/Controller/Phantom.Controller.Services/Agents/AgentActor.cs b/Controller/Phantom.Controller.Services/Agents/AgentActor.cs index e7984af..fea3764 100644 --- a/Controller/Phantom.Controller.Services/Agents/AgentActor.cs +++ b/Controller/Phantom.Controller.Services/Agents/AgentActor.cs @@ -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)); } diff --git a/Controller/Phantom.Controller.Services/Agents/AgentManager.cs b/Controller/Phantom.Controller.Services/Agents/AgentManager.cs index abb37b8..874f6bf 100644 --- a/Controller/Phantom.Controller.Services/Agents/AgentManager.cs +++ b/Controller/Phantom.Controller.Services/Agents/AgentManager.cs @@ -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; } } diff --git a/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs b/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs index 1f5f22a..267ebce 100644 --- a/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs +++ b/Controller/Phantom.Controller.Services/Instances/InstanceActor.cs @@ -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); diff --git a/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs b/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs index 7f64630..0ce7093 100644 --- a/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs +++ b/Controller/Phantom.Controller.Services/Rpc/WebMessageHandlerActor.cs @@ -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)); } diff --git a/Web/Phantom.Web.Services/Instances/InstanceManager.cs b/Web/Phantom.Web.Services/Instances/InstanceManager.cs index 578a4ff..2794299 100644 --- a/Web/Phantom.Web.Services/Instances/InstanceManager.cs +++ b/Web/Phantom.Web.Services/Instances/InstanceManager.cs @@ -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); } } diff --git a/Web/Phantom.Web/Pages/InstanceDetail.razor b/Web/Phantom.Web/Pages/InstanceDetail.razor index c6ab320..b232938 100644 --- a/Web/Phantom.Web/Pages/InstanceDetail.razor +++ b/Web/Phantom.Web/Pages/InstanceDetail.razor @@ -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; diff --git a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor index 6ac26b6..8913d78 100644 --- a/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor +++ b/Web/Phantom.Web/Shared/InstanceAddOrEditForm.razor @@ -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)); } } diff --git a/Web/Phantom.Web/Shared/InstanceCommandInput.razor b/Web/Phantom.Web/Shared/InstanceCommandInput.razor index c6bd0ab..8fd6a4e 100644 --- a/Web/Phantom.Web/Shared/InstanceCommandInput.razor +++ b/Web/Phantom.Web/Shared/InstanceCommandInput.razor @@ -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); diff --git a/Web/Phantom.Web/Shared/InstanceStopDialog.razor b/Web/Phantom.Web/Shared/InstanceStopDialog.razor index 79df39f..f2ff23c 100644 --- a/Web/Phantom.Web/Shared/InstanceStopDialog.razor +++ b/Web/Phantom.Web/Shared/InstanceStopDialog.razor @@ -65,7 +65,7 @@ form.SubmitModel.StopSubmitting(); } else { - form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence)); + form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence)); } }