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