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.Minecraft.Server;
|
||||||
using Phantom.Agent.Rpc;
|
using Phantom.Agent.Rpc;
|
||||||
using Phantom.Agent.Services.Backups;
|
using Phantom.Agent.Services.Backups;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Common.Data.Minecraft;
|
using Phantom.Common.Data.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
using Phantom.Utils.IO;
|
using Phantom.Utils.IO;
|
||||||
using Phantom.Utils.Logging;
|
using Phantom.Utils.Logging;
|
||||||
using Phantom.Utils.Tasks;
|
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
namespace Phantom.Agent.Services.Instances;
|
namespace Phantom.Agent.Services.Instances;
|
||||||
@ -49,10 +49,10 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
|||||||
|
|
||||||
this.instanceServices = new InstanceServices(init.ControllerConnection, init.BackupManager, launchServices);
|
this.instanceServices = new InstanceServices(init.ControllerConnection, init.BackupManager, launchServices);
|
||||||
|
|
||||||
ReceiveAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
|
ReceiveAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
|
||||||
ReceiveAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
ReceiveAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||||
ReceiveAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
ReceiveAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendCommandToInstance);
|
ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendCommandToInstance);
|
||||||
ReceiveAsync<ShutdownCommand>(Shutdown);
|
ReceiveAsync<ShutdownCommand>(Shutdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,17 +65,17 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
|||||||
|
|
||||||
public interface 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;
|
public sealed record ShutdownCommand : ICommand;
|
||||||
|
|
||||||
private InstanceActionResult<ConfigureInstanceResult> ConfigureInstance(ConfigureInstanceCommand command) {
|
private Result<ConfigureInstanceResult, InstanceActionFailure> ConfigureInstance(ConfigureInstanceCommand command) {
|
||||||
var instanceGuid = command.InstanceGuid;
|
var instanceGuid = command.InstanceGuid;
|
||||||
var configuration = command.Configuration;
|
var configuration = command.Configuration;
|
||||||
|
|
||||||
@ -130,64 +130,64 @@ sealed class InstanceManagerActor : ReceiveActor<InstanceManagerActor.ICommand>
|
|||||||
LaunchInstance(new LaunchInstanceCommand(instanceGuid));
|
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;
|
var instanceGuid = command.InstanceGuid;
|
||||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||||
return InstanceActionResult.General<LaunchInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
return InstanceActionFailure.InstanceDoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
|
var ticket = instanceTicketManager.Reserve(instanceInfo.Configuration);
|
||||||
if (ticket is Result<InstanceTicketManager.Ticket, LaunchInstanceResult>.Fail fail) {
|
if (!ticket) {
|
||||||
return InstanceActionResult.Concrete(fail.Error);
|
return ticket.Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||||
var status = instance.Status;
|
var status = instance.Status;
|
||||||
if (status.IsRunning()) {
|
if (status.IsRunning()) {
|
||||||
return InstanceActionResult.Concrete(LaunchInstanceResult.InstanceAlreadyRunning);
|
return LaunchInstanceResult.InstanceAlreadyRunning;
|
||||||
}
|
}
|
||||||
else if (status.IsLaunching()) {
|
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));
|
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;
|
var instanceGuid = command.InstanceGuid;
|
||||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||||
return InstanceActionResult.General<StopInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
return InstanceActionFailure.InstanceDoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
if (agentState.InstancesByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||||
var status = instance.Status;
|
var status = instance.Status;
|
||||||
if (status.IsStopping()) {
|
if (status.IsStopping()) {
|
||||||
return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopping);
|
return StopInstanceResult.InstanceAlreadyStopping;
|
||||||
}
|
}
|
||||||
else if (!status.CanStop()) {
|
else if (!status.CanStop()) {
|
||||||
return InstanceActionResult.Concrete(StopInstanceResult.InstanceAlreadyStopped);
|
return StopInstanceResult.InstanceAlreadyStopped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceInfo.Actor.Tell(new InstanceActor.StopInstanceCommand(command.StopStrategy));
|
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;
|
var instanceGuid = command.InstanceGuid;
|
||||||
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
if (!instances.TryGetValue(instanceGuid, out var instanceInfo)) {
|
||||||
return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
return InstanceActionFailure.InstanceDoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (OperationCanceledException) {
|
||||||
return InstanceActionResult.General<SendCommandToInstanceResult>(InstanceActionGeneralResult.AgentShuttingDown);
|
return InstanceActionFailure.AgentShuttingDown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using Phantom.Agent.Minecraft.Instance;
|
using Phantom.Agent.Minecraft.Instance;
|
||||||
using Phantom.Agent.Minecraft.Launcher;
|
using Phantom.Agent.Minecraft.Launcher;
|
||||||
using Phantom.Agent.Minecraft.Server;
|
using Phantom.Agent.Minecraft.Server;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Utils.Tasks;
|
|
||||||
|
|
||||||
namespace Phantom.Agent.Services.Instances.State;
|
namespace Phantom.Agent.Services.Instances.State;
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Phantom.Agent.Services.Instances;
|
using Phantom.Agent.Services.Instances;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Common.Messages.Agent;
|
using Phantom.Common.Messages.Agent;
|
||||||
@ -32,10 +33,10 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
|
|||||||
|
|
||||||
ReceiveAsync<RegisterAgentSuccessMessage>(HandleRegisterAgentSuccess);
|
ReceiveAsync<RegisterAgentSuccessMessage>(HandleRegisterAgentSuccess);
|
||||||
Receive<RegisterAgentFailureMessage>(HandleRegisterAgentFailure);
|
Receive<RegisterAgentFailureMessage>(HandleRegisterAgentFailure);
|
||||||
ReceiveAndReplyLater<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(HandleConfigureInstance);
|
ReceiveAndReplyLater<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(HandleConfigureInstance);
|
||||||
ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
|
ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
|
||||||
ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
|
ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
|
||||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
|
ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
|
||||||
Receive<ReplyMessage>(HandleReply);
|
Receive<ReplyMessage>(HandleReply);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,23 +75,23 @@ public sealed class ControllerMessageHandlerActor : ReceiveActor<IMessageToAgent
|
|||||||
Environment.Exit(1);
|
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));
|
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);
|
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));
|
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));
|
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));
|
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.BiDirectional;
|
||||||
using Phantom.Common.Messages.Agent.ToAgent;
|
using Phantom.Common.Messages.Agent.ToAgent;
|
||||||
using Phantom.Common.Messages.Agent.ToController;
|
using Phantom.Common.Messages.Agent.ToController;
|
||||||
@ -16,10 +17,10 @@ public static class AgentMessageRegistries {
|
|||||||
static AgentMessageRegistries() {
|
static AgentMessageRegistries() {
|
||||||
ToAgent.Add<RegisterAgentSuccessMessage>(0);
|
ToAgent.Add<RegisterAgentSuccessMessage>(0);
|
||||||
ToAgent.Add<RegisterAgentFailureMessage>(1);
|
ToAgent.Add<RegisterAgentFailureMessage>(1);
|
||||||
ToAgent.Add<ConfigureInstanceMessage, InstanceActionResult<ConfigureInstanceResult>>(2);
|
ToAgent.Add<ConfigureInstanceMessage, Result<ConfigureInstanceResult, InstanceActionFailure>>(2);
|
||||||
ToAgent.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(3);
|
ToAgent.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(3);
|
||||||
ToAgent.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(4);
|
ToAgent.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(4);
|
||||||
ToAgent.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(5);
|
ToAgent.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(5);
|
||||||
ToAgent.Add<ReplyMessage>(127);
|
ToAgent.Add<ReplyMessage>(127);
|
||||||
|
|
||||||
ToController.Add<RegisterAgentMessage>(0);
|
ToController.Add<RegisterAgentMessage>(0);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
@ -11,4 +12,4 @@ public sealed partial record ConfigureInstanceMessage(
|
|||||||
[property: MemoryPackOrder(1)] InstanceConfiguration Configuration,
|
[property: MemoryPackOrder(1)] InstanceConfiguration Configuration,
|
||||||
[property: MemoryPackOrder(2)] InstanceLaunchProperties LaunchProperties,
|
[property: MemoryPackOrder(2)] InstanceLaunchProperties LaunchProperties,
|
||||||
[property: MemoryPackOrder(3)] bool LaunchNow = false
|
[property: MemoryPackOrder(3)] bool LaunchNow = false
|
||||||
) : IMessageToAgent, ICanReply<InstanceActionResult<ConfigureInstanceResult>>;
|
) : IMessageToAgent, ICanReply<Result<ConfigureInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
|
|
||||||
@ -7,4 +8,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
|||||||
[MemoryPackable(GenerateType.VersionTolerant)]
|
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||||
public sealed partial record LaunchInstanceMessage(
|
public sealed partial record LaunchInstanceMessage(
|
||||||
[property: MemoryPackOrder(0)] Guid InstanceGuid
|
[property: MemoryPackOrder(0)] Guid InstanceGuid
|
||||||
) : IMessageToAgent, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
) : IMessageToAgent, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
|
|
||||||
@ -8,4 +9,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
|||||||
public sealed partial record SendCommandToInstanceMessage(
|
public sealed partial record SendCommandToInstanceMessage(
|
||||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||||
[property: MemoryPackOrder(1)] string Command
|
[property: MemoryPackOrder(1)] string Command
|
||||||
) : IMessageToAgent, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
) : IMessageToAgent, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Minecraft;
|
using Phantom.Common.Data.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
@ -9,4 +10,4 @@ namespace Phantom.Common.Messages.Agent.ToAgent;
|
|||||||
public sealed partial record StopInstanceMessage(
|
public sealed partial record StopInstanceMessage(
|
||||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||||
[property: MemoryPackOrder(1)] MinecraftStopStrategy StopStrategy
|
[property: MemoryPackOrder(1)] MinecraftStopStrategy StopStrategy
|
||||||
) : IMessageToAgent, ICanReply<InstanceActionResult<StopInstanceResult>>;
|
) : IMessageToAgent, ICanReply<Result<StopInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Common.Data.Web.Instance;
|
using Phantom.Common.Data.Web.Instance;
|
||||||
@ -11,4 +12,4 @@ public sealed partial record CreateOrUpdateInstanceMessage(
|
|||||||
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
||||||
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
||||||
[property: MemoryPackOrder(2)] InstanceConfiguration Configuration
|
[property: MemoryPackOrder(2)] InstanceConfiguration Configuration
|
||||||
) : IMessageToController, ICanReply<InstanceActionResult<CreateOrUpdateInstanceResult>>;
|
) : IMessageToController, ICanReply<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
|
|
||||||
@ -9,4 +10,4 @@ public sealed partial record LaunchInstanceMessage(
|
|||||||
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
||||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||||
[property: MemoryPackOrder(2)] Guid InstanceGuid
|
[property: MemoryPackOrder(2)] Guid InstanceGuid
|
||||||
) : IMessageToController, ICanReply<InstanceActionResult<LaunchInstanceResult>>;
|
) : IMessageToController, ICanReply<Result<LaunchInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
|
|
||||||
@ -10,4 +11,4 @@ public sealed partial record SendCommandToInstanceMessage(
|
|||||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||||
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
||||||
[property: MemoryPackOrder(3)] string Command
|
[property: MemoryPackOrder(3)] string Command
|
||||||
) : IMessageToController, ICanReply<InstanceActionResult<SendCommandToInstanceResult>>;
|
) : IMessageToController, ICanReply<Result<SendCommandToInstanceResult, InstanceActionFailure>>;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MemoryPack;
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Minecraft;
|
using Phantom.Common.Data.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Utils.Actor;
|
using Phantom.Utils.Actor;
|
||||||
@ -11,4 +12,4 @@ public sealed partial record StopInstanceMessage(
|
|||||||
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
[property: MemoryPackOrder(1)] Guid AgentGuid,
|
||||||
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
[property: MemoryPackOrder(2)] Guid InstanceGuid,
|
||||||
[property: MemoryPackOrder(3)] MinecraftStopStrategy StopStrategy
|
[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<GetRolesMessage, ImmutableArray<RoleInfo>>(9);
|
||||||
ToController.Add<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(10);
|
ToController.Add<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(10);
|
||||||
ToController.Add<ChangeUserRolesMessage, ChangeUserRolesResult>(11);
|
ToController.Add<ChangeUserRolesMessage, ChangeUserRolesResult>(11);
|
||||||
ToController.Add<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(12);
|
ToController.Add<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(12);
|
||||||
ToController.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(13);
|
ToController.Add<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(13);
|
||||||
ToController.Add<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(14);
|
ToController.Add<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(14);
|
||||||
ToController.Add<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(15);
|
ToController.Add<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(15);
|
||||||
ToController.Add<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(16);
|
ToController.Add<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(16);
|
||||||
ToController.Add<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(17);
|
ToController.Add<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(17);
|
||||||
ToController.Add<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(18);
|
ToController.Add<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(18);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Web.Users;
|
using Phantom.Common.Data.Web.Users;
|
||||||
using Phantom.Controller.Database.Entities;
|
using Phantom.Controller.Database.Entities;
|
||||||
using Phantom.Utils.Collections;
|
using Phantom.Utils.Collections;
|
||||||
using Phantom.Utils.Tasks;
|
|
||||||
|
|
||||||
namespace Phantom.Controller.Database.Repositories;
|
namespace Phantom.Controller.Database.Repositories;
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Web.Users;
|
using Phantom.Common.Data.Web.Users;
|
||||||
using Phantom.Common.Data.Web.Users.AddUserErrors;
|
using Phantom.Common.Data.Web.Users.AddUserErrors;
|
||||||
using Phantom.Common.Data.Web.Users.PasswordRequirementViolations;
|
using Phantom.Common.Data.Web.Users.PasswordRequirementViolations;
|
||||||
using Phantom.Common.Data.Web.Users.UsernameRequirementViolations;
|
using Phantom.Common.Data.Web.Users.UsernameRequirementViolations;
|
||||||
using Phantom.Controller.Database.Entities;
|
using Phantom.Controller.Database.Entities;
|
||||||
using Phantom.Utils.Collections;
|
using Phantom.Utils.Collections;
|
||||||
using Phantom.Utils.Tasks;
|
|
||||||
|
|
||||||
namespace Phantom.Controller.Database.Repositories;
|
namespace Phantom.Controller.Database.Repositories;
|
||||||
|
|
||||||
|
@ -92,11 +92,11 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
|||||||
Receive<NotifyIsAliveCommand>(NotifyIsAlive);
|
Receive<NotifyIsAliveCommand>(NotifyIsAlive);
|
||||||
Receive<UpdateStatsCommand>(UpdateStats);
|
Receive<UpdateStatsCommand>(UpdateStats);
|
||||||
Receive<UpdateJavaRuntimesCommand>(UpdateJavaRuntimes);
|
Receive<UpdateJavaRuntimesCommand>(UpdateJavaRuntimes);
|
||||||
ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, InstanceActionResult<CreateOrUpdateInstanceResult>>(CreateOrUpdateInstance);
|
ReceiveAndReplyLater<CreateOrUpdateInstanceCommand, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstance);
|
||||||
Receive<UpdateInstanceStatusCommand>(UpdateInstanceStatus);
|
Receive<UpdateInstanceStatusCommand>(UpdateInstanceStatus);
|
||||||
ReceiveAndReplyLater<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
ReceiveAndReplyLater<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||||
ReceiveAndReplyLater<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
ReceiveAndReplyLater<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||||
ReceiveAndReplyLater<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
|
ReceiveAndReplyLater<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
|
||||||
Receive<ReceiveInstanceDataCommand>(ReceiveInstanceData);
|
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)) {
|
if (instanceActorByGuid.TryGetValue(instanceGuid, out var instance)) {
|
||||||
return instance.Request(command, cancellationToken);
|
return instance.Request(command, cancellationToken);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Logger.Warning("Could not deliver command {CommandType} to instance {InstanceGuid}, instance not found.", command.GetType().Name, instanceGuid);
|
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 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 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;
|
public sealed record ReceiveInstanceDataCommand(Instance Instance) : ICommand, IJumpAhead;
|
||||||
|
|
||||||
@ -270,15 +270,15 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
|||||||
controllerState.UpdateAgentJavaRuntimes(agentGuid, javaRuntimes);
|
controllerState.UpdateAgentJavaRuntimes(agentGuid, javaRuntimes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
|
private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance(CreateOrUpdateInstanceCommand command) {
|
||||||
var instanceConfiguration = command.Configuration;
|
var instanceConfiguration = command.Configuration;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(instanceConfiguration.InstanceName)) {
|
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) {
|
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)
|
return minecraftVersions.GetServerExecutableInfo(instanceConfiguration.MinecraftVersion, cancellationToken)
|
||||||
@ -286,9 +286,9 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
|||||||
.Unwrap();
|
.Unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
|
private Task<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>> CreateOrUpdateInstance1(FileDownloadInfo? serverExecutableInfo, CreateOrUpdateInstanceCommand command) {
|
||||||
if (serverExecutableInfo == null) {
|
if (serverExecutableInfo == null) {
|
||||||
return Task.FromResult(InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound));
|
return Task.FromResult<Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
var instanceConfiguration = command.Configuration;
|
var instanceConfiguration = command.Configuration;
|
||||||
@ -304,7 +304,7 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
|||||||
.ContinueOnActor(CreateOrUpdateInstance2, configureInstanceCommand);
|
.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 instanceGuid = command.InstanceGuid;
|
||||||
var instanceName = command.Configuration.InstanceName;
|
var instanceName = command.Configuration.InstanceName;
|
||||||
var isCreating = command.IsCreatingInstance;
|
var isCreating = command.IsCreatingInstance;
|
||||||
@ -312,33 +312,35 @@ sealed class AgentActor : ReceiveActor<AgentActor.ICommand> {
|
|||||||
if (result.Is(ConfigureInstanceResult.Success)) {
|
if (result.Is(ConfigureInstanceResult.Success)) {
|
||||||
string action = isCreating ? "Added" : "Edited";
|
string action = isCreating ? "Added" : "Edited";
|
||||||
string relation = isCreating ? "to agent" : "in agent";
|
string relation = isCreating ? "to agent" : "in agent";
|
||||||
|
|
||||||
Logger.Information(action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\".", instanceName, instanceGuid, configuration.AgentName);
|
Logger.Information(action + " instance \"{InstanceName}\" (GUID {InstanceGuid}) " + relation + " \"{AgentName}\".", instanceName, instanceGuid, configuration.AgentName);
|
||||||
|
|
||||||
|
return CreateOrUpdateInstanceResult.Success;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
string action = isCreating ? "adding" : "editing";
|
string action = isCreating ? "adding" : "editing";
|
||||||
string relation = isCreating ? "to agent" : "in agent";
|
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) {
|
private void UpdateInstanceStatus(UpdateInstanceStatusCommand command) {
|
||||||
TellInstance(command.InstanceGuid, new InstanceActor.SetStatusCommand(command.Status));
|
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));
|
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));
|
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));
|
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>> {
|
public async Task<Result<TReply, InstanceActionFailure>> DoInstanceAction<TCommand, TReply>(Guid agentGuid, TCommand command) where TCommand : class, AgentActor.ICommand, ICanReply<Result<TReply, InstanceActionFailure>> {
|
||||||
if (agentsByGuid.TryGetValue(agentGuid, out var agent)) {
|
return agentsByGuid.TryGetValue(agentGuid, out var agent) ? await agent.Request(command, cancellationToken) : InstanceActionFailure.AgentDoesNotExist;
|
||||||
return await agent.Request(command, cancellationToken);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return InstanceActionResult.General<TReply>(InstanceActionGeneralResult.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.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Common.Data.Web.Instance;
|
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");
|
this.databaseStorageActor = Context.ActorOf(InstanceDatabaseStorageActor.Factory(new InstanceDatabaseStorageActor.Init(instanceGuid, init.DbProvider, init.CancellationToken)), "DatabaseStorage");
|
||||||
|
|
||||||
Receive<SetStatusCommand>(SetStatus);
|
Receive<SetStatusCommand>(SetStatus);
|
||||||
ReceiveAsyncAndReply<ConfigureInstanceCommand, InstanceActionResult<ConfigureInstanceResult>>(ConfigureInstance);
|
ReceiveAsyncAndReply<ConfigureInstanceCommand, Result<ConfigureInstanceResult, InstanceActionFailure>>(ConfigureInstance);
|
||||||
ReceiveAsyncAndReply<LaunchInstanceCommand, InstanceActionResult<LaunchInstanceResult>>(LaunchInstance);
|
ReceiveAsyncAndReply<LaunchInstanceCommand, Result<LaunchInstanceResult, InstanceActionFailure>>(LaunchInstance);
|
||||||
ReceiveAsyncAndReply<StopInstanceCommand, InstanceActionResult<StopInstanceResult>>(StopInstance);
|
ReceiveAsyncAndReply<StopInstanceCommand, Result<StopInstanceResult, InstanceActionFailure>>(StopInstance);
|
||||||
ReceiveAsyncAndReply<SendCommandToInstanceCommand, InstanceActionResult<SendCommandToInstanceResult>>(SendMinecraftCommand);
|
ReceiveAsyncAndReply<SendCommandToInstanceCommand, Result<SendCommandToInstanceResult, InstanceActionFailure>>(SendMinecraftCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NotifyInstanceUpdated() {
|
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>> {
|
private async Task<Result<TReply, InstanceActionFailure>> SendInstanceActionMessage<TMessage, TReply>(TMessage message) where TMessage : IMessageToAgent, ICanReply<Result<TReply, InstanceActionFailure>> {
|
||||||
var reply = await agentConnection.Send<TMessage, InstanceActionResult<TReply>>(message, TimeSpan.FromSeconds(10), cancellationToken);
|
var reply = await agentConnection.Send<TMessage, Result<TReply, InstanceActionFailure>>(message, TimeSpan.FromSeconds(10), cancellationToken);
|
||||||
return reply.DidNotReplyIfNull();
|
return reply ?? InstanceActionFailure.AgentIsNotResponding;
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ICommand {}
|
public interface ICommand {}
|
||||||
|
|
||||||
public sealed record SetStatusCommand(IInstanceStatus Status) : 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) {
|
private void SetStatus(SetStatusCommand command) {
|
||||||
status = command.Status;
|
status = command.Status;
|
||||||
NotifyInstanceUpdated();
|
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 message = new ConfigureInstanceMessage(command.InstanceGuid, command.Configuration, command.LaunchProperties);
|
||||||
var result = await SendInstanceActionMessage<ConfigureInstanceMessage, ConfigureInstanceResult>(message);
|
var result = await SendInstanceActionMessage<ConfigureInstanceMessage, ConfigureInstanceResult>(message);
|
||||||
|
|
||||||
@ -98,7 +99,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
|||||||
return result;
|
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 message = new LaunchInstanceMessage(instanceGuid);
|
||||||
var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(message);
|
var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(message);
|
||||||
|
|
||||||
@ -110,7 +111,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
|||||||
return result;
|
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 message = new StopInstanceMessage(instanceGuid, command.StopStrategy);
|
||||||
var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(message);
|
var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(message);
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ sealed class InstanceActor : ReceiveActor<InstanceActor.ICommand> {
|
|||||||
return result;
|
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 message = new SendCommandToInstanceMessage(instanceGuid, command.Command);
|
||||||
var result = await SendInstanceActionMessage<SendCommandToInstanceMessage, SendCommandToInstanceResult>(message);
|
var result = await SendInstanceActionMessage<SendCommandToInstanceMessage, SendCommandToInstanceResult>(message);
|
||||||
|
|
||||||
|
@ -80,10 +80,10 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
|
|||||||
ReceiveAndReplyLater<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(HandleGetUserRoles);
|
ReceiveAndReplyLater<GetUserRolesMessage, ImmutableDictionary<Guid, ImmutableArray<Guid>>>(HandleGetUserRoles);
|
||||||
ReceiveAndReplyLater<ChangeUserRolesMessage, ChangeUserRolesResult>(HandleChangeUserRoles);
|
ReceiveAndReplyLater<ChangeUserRolesMessage, ChangeUserRolesResult>(HandleChangeUserRoles);
|
||||||
ReceiveAndReplyLater<DeleteUserMessage, DeleteUserResult>(HandleDeleteUser);
|
ReceiveAndReplyLater<DeleteUserMessage, DeleteUserResult>(HandleDeleteUser);
|
||||||
ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(HandleCreateOrUpdateInstance);
|
ReceiveAndReplyLater<CreateOrUpdateInstanceMessage, Result<CreateOrUpdateInstanceResult, InstanceActionFailure>>(HandleCreateOrUpdateInstance);
|
||||||
ReceiveAndReplyLater<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(HandleLaunchInstance);
|
ReceiveAndReplyLater<LaunchInstanceMessage, Result<LaunchInstanceResult, InstanceActionFailure>>(HandleLaunchInstance);
|
||||||
ReceiveAndReplyLater<StopInstanceMessage, InstanceActionResult<StopInstanceResult>>(HandleStopInstance);
|
ReceiveAndReplyLater<StopInstanceMessage, Result<StopInstanceResult, InstanceActionFailure>>(HandleStopInstance);
|
||||||
ReceiveAndReplyLater<SendCommandToInstanceMessage, InstanceActionResult<SendCommandToInstanceResult>>(HandleSendCommandToInstance);
|
ReceiveAndReplyLater<SendCommandToInstanceMessage, Result<SendCommandToInstanceResult, InstanceActionFailure>>(HandleSendCommandToInstance);
|
||||||
ReceiveAndReplyLater<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(HandleGetMinecraftVersions);
|
ReceiveAndReplyLater<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(HandleGetMinecraftVersions);
|
||||||
ReceiveAndReply<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(HandleGetAgentJavaRuntimes);
|
ReceiveAndReply<GetAgentJavaRuntimesMessage, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(HandleGetAgentJavaRuntimes);
|
||||||
ReceiveAndReplyLater<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(HandleGetAuditLog);
|
ReceiveAndReplyLater<GetAuditLogMessage, ImmutableArray<AuditLogItem>>(HandleGetAuditLog);
|
||||||
@ -139,19 +139,19 @@ sealed class WebMessageHandlerActor : ReceiveActor<IMessageToController> {
|
|||||||
return userManager.DeleteByGuid(message.LoggedInUserGuid, message.SubjectUserGuid);
|
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));
|
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));
|
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));
|
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));
|
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 {
|
else {
|
||||||
var result = userRepository.SetUserPassword(user, password);
|
if (userRepository.SetUserPassword(user, password).TryGetError(out var error)) {
|
||||||
if (!result) {
|
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(error);
|
||||||
return new Common.Data.Web.Users.CreateOrUpdateAdministratorUserResults.UpdatingFailed(result.Error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auditLogWriter.AdministratorUserModified(user);
|
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 System.Collections.Immutable;
|
||||||
|
using Phantom.Common.Data;
|
||||||
using Phantom.Common.Data.Instance;
|
using Phantom.Common.Data.Instance;
|
||||||
using Phantom.Common.Data.Minecraft;
|
using Phantom.Common.Data.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
using Phantom.Common.Data.Replies;
|
||||||
@ -34,23 +35,23 @@ public sealed class InstanceManager {
|
|||||||
return instances.Value.GetValueOrDefault(instanceGuid);
|
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);
|
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);
|
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);
|
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);
|
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);
|
var result = await InstanceManager.LaunchInstance(loggedInUserGuid.Value, Instance.Configuration.AgentGuid, InstanceGuid, CancellationToken);
|
||||||
if (!result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
if (!result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
||||||
lastError = result.ToSentence(Messages.ToSentence);
|
lastError = result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
isLaunchingInstance = false;
|
isLaunchingInstance = false;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
@page "/setup"
|
@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
|
||||||
@using Phantom.Web.Services.Authentication
|
@using Phantom.Web.Services.Authentication
|
||||||
@using Phantom.Web.Services.Rpc
|
@using Phantom.Web.Services.Rpc
|
||||||
@using System.ComponentModel.DataAnnotations
|
@using System.ComponentModel.DataAnnotations
|
||||||
@using Phantom.Utils.Cryptography
|
|
||||||
@using System.Security.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]
|
@attribute [AllowAnonymous]
|
||||||
@inject ApplicationProperties ApplicationProperties
|
@inject ApplicationProperties ApplicationProperties
|
||||||
@inject UserLoginManager LoginManager
|
@inject UserLoginManager LoginManager
|
||||||
@ -65,8 +65,9 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await CreateOrUpdateAdministrator() is Result<string>.Fail fail) {
|
var createOrUpdateAdministratorResult = await CreateOrUpdateAdministrator();
|
||||||
form.SubmitModel.StopSubmitting(fail.Error);
|
if (createOrUpdateAdministratorResult.TryGetError(out var error)) {
|
||||||
|
form.SubmitModel.StopSubmitting(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
@using System.ComponentModel.DataAnnotations
|
@using System.ComponentModel.DataAnnotations
|
||||||
@using System.Diagnostics.CodeAnalysis
|
@using System.Diagnostics.CodeAnalysis
|
||||||
@using Phantom.Common.Data.Minecraft
|
@using Phantom.Common.Data.Minecraft
|
||||||
|
@using Phantom.Common.Data.Replies
|
||||||
@using Phantom.Common.Data.Web.Agent
|
@using Phantom.Common.Data.Web.Agent
|
||||||
@using Phantom.Common.Data.Web.Instance
|
@using Phantom.Common.Data.Web.Instance
|
||||||
@using Phantom.Common.Data.Web.Minecraft
|
@using Phantom.Common.Data.Web.Minecraft
|
||||||
@ -347,7 +348,7 @@
|
|||||||
await Navigation.NavigateTo("instances/" + instanceGuid);
|
await Navigation.NavigateTo("instances/" + instanceGuid);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
form.SubmitModel.StopSubmitting(result.ToSentence(CreateOrUpdateInstanceResultExtensions.ToSentence));
|
form.SubmitModel.StopSubmitting(result.Map(CreateOrUpdateInstanceResultExtensions.ToSentence, InstanceActionFailureExtensions.ToSentence));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
form.SubmitModel.StopSubmitting();
|
form.SubmitModel.StopSubmitting();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
form.SubmitModel.StopSubmitting(result.ToSentence(Messages.ToSentence));
|
form.SubmitModel.StopSubmitting(result.Map(Messages.ToSentence, InstanceActionFailureExtensions.ToSentence));
|
||||||
}
|
}
|
||||||
|
|
||||||
await commandInputElement.FocusAsync(preventScroll: true);
|
await commandInputElement.FocusAsync(preventScroll: true);
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
form.SubmitModel.StopSubmitting();
|
form.SubmitModel.StopSubmitting();
|
||||||
}
|
}
|
||||||
else {
|
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