mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2024-11-25 16:42:54 +01:00
Compare commits
2 Commits
d9c187994b
...
e796a364f4
Author | SHA1 | Date | |
---|---|---|---|
e796a364f4 | |||
901dcbf721 |
@ -17,5 +17,6 @@ public sealed partial record AgentWithStats(
|
|||||||
[property: MemoryPackOrder(9)] DateTimeOffset? LastPing,
|
[property: MemoryPackOrder(9)] DateTimeOffset? LastPing,
|
||||||
[property: MemoryPackOrder(10)] bool IsOnline
|
[property: MemoryPackOrder(10)] bool IsOnline
|
||||||
) {
|
) {
|
||||||
|
[MemoryPackIgnore]
|
||||||
public RamAllocationUnits? AvailableMemory => MaxMemory - Stats?.RunningInstanceMemory;
|
public RamAllocationUnits? AvailableMemory => MaxMemory - Stats?.RunningInstanceMemory;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
namespace Phantom.Common.Data.Web.Instance;
|
||||||
|
|
||||||
|
public enum CreateOrUpdateInstanceResult : byte {
|
||||||
|
UnknownError,
|
||||||
|
Success,
|
||||||
|
InstanceNameMustNotBeEmpty,
|
||||||
|
InstanceMemoryMustNotBeZero,
|
||||||
|
MinecraftVersionDownloadInfoNotFound,
|
||||||
|
AgentNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CreateOrUpdateInstanceResultExtensions {
|
||||||
|
public static string ToSentence(this CreateOrUpdateInstanceResult reason) {
|
||||||
|
return reason switch {
|
||||||
|
CreateOrUpdateInstanceResult.Success => "Success.",
|
||||||
|
CreateOrUpdateInstanceResult.InstanceNameMustNotBeEmpty => "Instance name must not be empty.",
|
||||||
|
CreateOrUpdateInstanceResult.InstanceMemoryMustNotBeZero => "Memory must not be 0 MB.",
|
||||||
|
CreateOrUpdateInstanceResult.MinecraftVersionDownloadInfoNotFound => "Could not find download information for the selected Minecraft version.",
|
||||||
|
CreateOrUpdateInstanceResult.AgentNotFound => "Agent not found.",
|
||||||
|
_ => "Unknown error."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
namespace Phantom.Common.Data.Minecraft;
|
using MemoryPack;
|
||||||
|
|
||||||
public sealed record MinecraftVersion(
|
namespace Phantom.Common.Data.Minecraft;
|
||||||
string Id,
|
|
||||||
MinecraftVersionType Type,
|
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||||
string MetadataUrl
|
public sealed partial record MinecraftVersion(
|
||||||
|
[property: MemoryPackOrder(0)] string Id,
|
||||||
|
[property: MemoryPackOrder(1)] MinecraftVersionType Type,
|
||||||
|
[property: MemoryPackOrder(2)] string MetadataUrl
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using Phantom.Common.Data.Replies;
|
using System.Collections.Immutable;
|
||||||
|
using Phantom.Common.Data.Java;
|
||||||
|
using Phantom.Common.Data.Minecraft;
|
||||||
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Common.Data.Web.Instance;
|
using Phantom.Common.Data.Web.Instance;
|
||||||
using Phantom.Common.Data.Web.Users;
|
using Phantom.Common.Data.Web.Users;
|
||||||
using Phantom.Common.Messages.Web.BiDirectional;
|
using Phantom.Common.Messages.Web.BiDirectional;
|
||||||
@ -12,5 +15,8 @@ public interface IMessageToControllerListener {
|
|||||||
Task<LogInSuccess?> HandleLogIn(LogInMessage message);
|
Task<LogInSuccess?> HandleLogIn(LogInMessage message);
|
||||||
Task<CreateOrUpdateAdministratorUserResult> HandleCreateOrUpdateAdministratorUser(CreateOrUpdateAdministratorUserMessage message);
|
Task<CreateOrUpdateAdministratorUserResult> HandleCreateOrUpdateAdministratorUser(CreateOrUpdateAdministratorUserMessage message);
|
||||||
Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message);
|
Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message);
|
||||||
|
Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message);
|
||||||
|
Task<ImmutableArray<MinecraftVersion>> HandleGetMinecraftVersions(GetMinecraftVersionsMessage message);
|
||||||
|
Task<ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>> HandleGetAgentJavaRuntimes(GetAgentJavaRuntimes message);
|
||||||
Task<NoReply> HandleReply(ReplyMessage message);
|
Task<NoReply> HandleReply(ReplyMessage message);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data.Java;
|
||||||
|
|
||||||
|
namespace Phantom.Common.Messages.Web.ToController;
|
||||||
|
|
||||||
|
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||||
|
public sealed partial record GetAgentJavaRuntimes : IMessageToController<ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>> {
|
||||||
|
public Task<ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>> Accept(IMessageToControllerListener listener) {
|
||||||
|
return listener.HandleGetAgentJavaRuntimes(this);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data.Minecraft;
|
||||||
|
|
||||||
|
namespace Phantom.Common.Messages.Web.ToController;
|
||||||
|
|
||||||
|
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||||
|
public sealed partial record GetMinecraftVersionsMessage : IMessageToController<ImmutableArray<MinecraftVersion>> {
|
||||||
|
public Task<ImmutableArray<MinecraftVersion>> Accept(IMessageToControllerListener listener) {
|
||||||
|
return listener.HandleGetMinecraftVersions(this);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
using MemoryPack;
|
||||||
|
using Phantom.Common.Data.Replies;
|
||||||
|
|
||||||
|
namespace Phantom.Common.Messages.Web.ToController;
|
||||||
|
|
||||||
|
[MemoryPackable(GenerateType.VersionTolerant)]
|
||||||
|
public sealed partial record LaunchInstanceMessage(
|
||||||
|
[property: MemoryPackOrder(0)] Guid LoggedInUserGuid,
|
||||||
|
[property: MemoryPackOrder(1)] Guid InstanceGuid
|
||||||
|
) : IMessageToController<InstanceActionResult<LaunchInstanceResult>> {
|
||||||
|
public Task<InstanceActionResult<LaunchInstanceResult>> Accept(IMessageToControllerListener listener) {
|
||||||
|
return listener.HandleLaunchInstance(this);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,7 @@
|
|||||||
using Phantom.Common.Data.Replies;
|
using System.Collections.Immutable;
|
||||||
|
using Phantom.Common.Data.Java;
|
||||||
|
using Phantom.Common.Data.Minecraft;
|
||||||
|
using Phantom.Common.Data.Replies;
|
||||||
using Phantom.Common.Data.Web.Instance;
|
using Phantom.Common.Data.Web.Instance;
|
||||||
using Phantom.Common.Data.Web.Users;
|
using Phantom.Common.Data.Web.Users;
|
||||||
using Phantom.Common.Logging;
|
using Phantom.Common.Logging;
|
||||||
@ -20,6 +23,9 @@ public static class WebMessageRegistries {
|
|||||||
ToController.Add<LogInMessage, LogInSuccess?>(1);
|
ToController.Add<LogInMessage, LogInSuccess?>(1);
|
||||||
ToController.Add<CreateOrUpdateAdministratorUserMessage, CreateOrUpdateAdministratorUserResult>(2);
|
ToController.Add<CreateOrUpdateAdministratorUserMessage, CreateOrUpdateAdministratorUserResult>(2);
|
||||||
ToController.Add<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(3);
|
ToController.Add<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(3);
|
||||||
|
ToController.Add<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(4);
|
||||||
|
ToController.Add<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(5);
|
||||||
|
ToController.Add<GetAgentJavaRuntimes, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(6);
|
||||||
ToController.Add<ReplyMessage>(127);
|
ToController.Add<ReplyMessage>(127);
|
||||||
|
|
||||||
ToWeb.Add<RegisterWebResultMessage>(0);
|
ToWeb.Add<RegisterWebResultMessage>(0);
|
||||||
|
@ -60,7 +60,7 @@ public sealed class ControllerServices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WebMessageListener CreateWebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection) {
|
public WebMessageListener CreateWebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection) {
|
||||||
return new WebMessageListener(connection, webAuthToken, UserManager, UserLoginManager, AgentManager, InstanceManager, TaskManager);
|
return new WebMessageListener(connection, webAuthToken, UserManager, UserLoginManager, AgentManager, AgentJavaRuntimesManager, InstanceManager, MinecraftVersions, TaskManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Initialize() {
|
public async Task Initialize() {
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
namespace Phantom.Controller.Services.Instances;
|
|
||||||
|
|
||||||
public enum AddOrEditInstanceResult : byte {
|
|
||||||
UnknownError,
|
|
||||||
Success,
|
|
||||||
InstanceNameMustNotBeEmpty,
|
|
||||||
InstanceMemoryMustNotBeZero,
|
|
||||||
MinecraftVersionDownloadInfoNotFound,
|
|
||||||
AgentNotFound
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AddOrEditInstanceResultExtensions {
|
|
||||||
public static string ToSentence(this AddOrEditInstanceResult reason) {
|
|
||||||
return reason switch {
|
|
||||||
AddOrEditInstanceResult.Success => "Success.",
|
|
||||||
AddOrEditInstanceResult.InstanceNameMustNotBeEmpty => "Instance name must not be empty.",
|
|
||||||
AddOrEditInstanceResult.InstanceMemoryMustNotBeZero => "Memory must not be 0 MB.",
|
|
||||||
AddOrEditInstanceResult.MinecraftVersionDownloadInfoNotFound => "Could not find download information for the selected Minecraft version.",
|
|
||||||
AddOrEditInstanceResult.AgentNotFound => "Agent not found.",
|
|
||||||
_ => "Unknown error."
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -63,7 +63,7 @@ sealed class InstanceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[SuppressMessage("ReSharper", "ConvertIfStatementToConditionalTernaryExpression")]
|
[SuppressMessage("ReSharper", "ConvertIfStatementToConditionalTernaryExpression")]
|
||||||
public async Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(InstanceConfiguration configuration, Guid auditLogUserGuid) {
|
public async Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(Guid auditLogUserGuid, InstanceConfiguration configuration) {
|
||||||
var agent = agentManager.GetAgent(configuration.AgentGuid);
|
var agent = agentManager.GetAgent(configuration.AgentGuid);
|
||||||
if (agent == null) {
|
if (agent == null) {
|
||||||
return InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.AgentNotFound);
|
return InstanceActionResult.Concrete(CreateOrUpdateInstanceResult.AgentNotFound);
|
||||||
@ -176,34 +176,38 @@ sealed class InstanceManager {
|
|||||||
return instances.ByGuid.TryGetValue(instanceGuid, out var instance) ? await SendInstanceActionMessage<TMessage, TReply>(instance, message) : InstanceActionResult.General<TReply>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
return instances.ByGuid.TryGetValue(instanceGuid, out var instance) ? await SendInstanceActionMessage<TMessage, TReply>(instance, message) : InstanceActionResult.General<TReply>(InstanceActionGeneralResult.InstanceDoesNotExist);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(Guid instanceGuid) {
|
public async Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(Guid auditLogUserGuid, Guid instanceGuid) {
|
||||||
var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(instanceGuid, new LaunchInstanceMessage(instanceGuid));
|
var result = await SendInstanceActionMessage<LaunchInstanceMessage, LaunchInstanceResult>(instanceGuid, new LaunchInstanceMessage(instanceGuid));
|
||||||
if (result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
if (result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
||||||
await SetInstanceShouldLaunchAutomatically(instanceGuid, true);
|
await HandleInstanceManuallyLaunchedOrStopped(instanceGuid, true, auditLogUserGuid, auditLogRepository => auditLogRepository.AddInstanceLaunchedEvent(instanceGuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<InstanceActionResult<StopInstanceResult>> StopInstance(Guid instanceGuid, MinecraftStopStrategy stopStrategy) {
|
public async Task<InstanceActionResult<StopInstanceResult>> StopInstance(Guid auditLogUserGuid, Guid instanceGuid, MinecraftStopStrategy stopStrategy) {
|
||||||
var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(instanceGuid, new StopInstanceMessage(instanceGuid, stopStrategy));
|
var result = await SendInstanceActionMessage<StopInstanceMessage, StopInstanceResult>(instanceGuid, new StopInstanceMessage(instanceGuid, stopStrategy));
|
||||||
if (result.Is(StopInstanceResult.StopInitiated)) {
|
if (result.Is(StopInstanceResult.StopInitiated)) {
|
||||||
await SetInstanceShouldLaunchAutomatically(instanceGuid, false);
|
await HandleInstanceManuallyLaunchedOrStopped(instanceGuid, false, auditLogUserGuid, auditLogRepository => auditLogRepository.AddInstanceLaunchedEvent(instanceGuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SetInstanceShouldLaunchAutomatically(Guid instanceGuid, bool shouldLaunchAutomatically) {
|
private async Task HandleInstanceManuallyLaunchedOrStopped(Guid instanceGuid, bool wasLaunched, Guid auditLogUserGuid, Action<AuditLogRepository> addAuditEvent) {
|
||||||
await modifyInstancesSemaphore.WaitAsync(cancellationToken);
|
await modifyInstancesSemaphore.WaitAsync(cancellationToken);
|
||||||
try {
|
try {
|
||||||
instances.ByGuid.TryReplace(instanceGuid, instance => instance with { LaunchAutomatically = shouldLaunchAutomatically });
|
instances.ByGuid.TryReplace(instanceGuid, instance => instance with { LaunchAutomatically = wasLaunched });
|
||||||
|
|
||||||
await using var ctx = dbProvider.Eager();
|
await using var db = dbProvider.Lazy();
|
||||||
var entity = await ctx.Instances.FindAsync(new object[] { instanceGuid }, cancellationToken);
|
var entity = await db.Ctx.Instances.FindAsync(new object[] { instanceGuid }, cancellationToken);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
entity.LaunchAutomatically = shouldLaunchAutomatically;
|
entity.LaunchAutomatically = wasLaunched;
|
||||||
await ctx.SaveChangesAsync(cancellationToken);
|
|
||||||
|
var auditLogRepository = new AuditLogRepository(db, auditLogUserGuid);
|
||||||
|
addAuditEvent(auditLogRepository);
|
||||||
|
|
||||||
|
await db.Ctx.SaveChangesAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
modifyInstancesSemaphore.Release();
|
modifyInstancesSemaphore.Release();
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Phantom.Common.Data;
|
using Phantom.Common.Data;
|
||||||
|
using Phantom.Common.Data.Java;
|
||||||
|
using Phantom.Common.Data.Minecraft;
|
||||||
using Phantom.Common.Data.Replies;
|
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;
|
||||||
@ -9,6 +11,7 @@ using Phantom.Common.Messages.Web;
|
|||||||
using Phantom.Common.Messages.Web.BiDirectional;
|
using Phantom.Common.Messages.Web.BiDirectional;
|
||||||
using Phantom.Common.Messages.Web.ToController;
|
using Phantom.Common.Messages.Web.ToController;
|
||||||
using Phantom.Common.Messages.Web.ToWeb;
|
using Phantom.Common.Messages.Web.ToWeb;
|
||||||
|
using Phantom.Controller.Minecraft;
|
||||||
using Phantom.Controller.Rpc;
|
using Phantom.Controller.Rpc;
|
||||||
using Phantom.Controller.Services.Agents;
|
using Phantom.Controller.Services.Agents;
|
||||||
using Phantom.Controller.Services.Instances;
|
using Phantom.Controller.Services.Instances;
|
||||||
@ -27,16 +30,20 @@ public sealed class WebMessageListener : IMessageToControllerListener {
|
|||||||
private readonly UserManager userManager;
|
private readonly UserManager userManager;
|
||||||
private readonly UserLoginManager userLoginManager;
|
private readonly UserLoginManager userLoginManager;
|
||||||
private readonly AgentManager agentManager;
|
private readonly AgentManager agentManager;
|
||||||
|
private readonly AgentJavaRuntimesManager agentJavaRuntimesManager;
|
||||||
private readonly InstanceManager instanceManager;
|
private readonly InstanceManager instanceManager;
|
||||||
|
private readonly MinecraftVersions minecraftVersions;
|
||||||
private readonly TaskManager taskManager;
|
private readonly TaskManager taskManager;
|
||||||
|
|
||||||
internal WebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection, AuthToken authToken, UserManager userManager, UserLoginManager userLoginManager, AgentManager agentManager, InstanceManager instanceManager, TaskManager taskManager) {
|
internal WebMessageListener(RpcConnectionToClient<IMessageToWebListener> connection, AuthToken authToken, UserManager userManager, UserLoginManager userLoginManager, AgentManager agentManager, AgentJavaRuntimesManager agentJavaRuntimesManager, InstanceManager instanceManager, MinecraftVersions minecraftVersions, TaskManager taskManager) {
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
this.authToken = authToken;
|
this.authToken = authToken;
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
this.userLoginManager = userLoginManager;
|
this.userLoginManager = userLoginManager;
|
||||||
this.agentManager = agentManager;
|
this.agentManager = agentManager;
|
||||||
|
this.agentJavaRuntimesManager = agentJavaRuntimesManager;
|
||||||
this.instanceManager = instanceManager;
|
this.instanceManager = instanceManager;
|
||||||
|
this.minecraftVersions = minecraftVersions;
|
||||||
this.taskManager = taskManager;
|
this.taskManager = taskManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +79,19 @@ public sealed class WebMessageListener : IMessageToControllerListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
|
public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> HandleCreateOrUpdateInstance(CreateOrUpdateInstanceMessage message) {
|
||||||
return instanceManager.CreateOrUpdateInstance(message.Configuration, message.LoggedInUserGuid);
|
return instanceManager.CreateOrUpdateInstance( message.LoggedInUserGuid, message.Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<InstanceActionResult<LaunchInstanceResult>> HandleLaunchInstance(LaunchInstanceMessage message) {
|
||||||
|
return instanceManager.LaunchInstance(message.LoggedInUserGuid, message.InstanceGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ImmutableArray<MinecraftVersion>> HandleGetMinecraftVersions(GetMinecraftVersionsMessage message) {
|
||||||
|
return minecraftVersions.GetVersions(CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>> HandleGetAgentJavaRuntimes(GetAgentJavaRuntimes message) {
|
||||||
|
return Task.FromResult(agentJavaRuntimesManager.All);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<LogInSuccess?> HandleLogIn(LogInMessage message) {
|
public Task<LogInSuccess?> HandleLogIn(LogInMessage message) {
|
||||||
|
@ -10,11 +10,11 @@ public sealed class AgentManager {
|
|||||||
|
|
||||||
public EventSubscribers<ImmutableArray<AgentWithStats>> AgentsChanged => agents.Subs;
|
public EventSubscribers<ImmutableArray<AgentWithStats>> AgentsChanged => agents.Subs;
|
||||||
|
|
||||||
public ImmutableDictionary<Guid, AgentWithStats> ToDictionaryByGuid() {
|
|
||||||
return agents.Value.ToImmutableDictionary(static agent => agent.Guid);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RefreshAgents(ImmutableArray<AgentWithStats> newAgents) {
|
internal void RefreshAgents(ImmutableArray<AgentWithStats> newAgents) {
|
||||||
agents.SetTo(newAgents);
|
agents.SetTo(newAgents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImmutableDictionary<Guid, AgentWithStats> ToDictionaryByGuid() {
|
||||||
|
return agents.Value.ToImmutableDictionary(static agent => agent.Guid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@ using Phantom.Common.Data.Web.Users;
|
|||||||
|
|
||||||
namespace Phantom.Web.Services.Authentication;
|
namespace Phantom.Web.Services.Authentication;
|
||||||
|
|
||||||
sealed record UserInfo(Guid UserGuid, string Username, PermissionSet Permissions) {
|
public sealed record UserInfo(Guid UserGuid, string Username, PermissionSet Permissions) {
|
||||||
private const string AuthenticationType = "Phantom";
|
private const string AuthenticationType = "Phantom";
|
||||||
|
|
||||||
public ClaimsPrincipal AsClaimsPrincipal {
|
internal ClaimsPrincipal AsClaimsPrincipal {
|
||||||
get {
|
get {
|
||||||
var identity = new ClaimsIdentity(AuthenticationType);
|
var identity = new ClaimsIdentity(AuthenticationType);
|
||||||
|
|
||||||
@ -18,6 +18,6 @@ sealed record UserInfo(Guid UserGuid, string Username, PermissionSet Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Guid? TryGetGuid(ClaimsPrincipal principal) {
|
public static Guid? TryGetGuid(ClaimsPrincipal principal) {
|
||||||
return principal.FindFirstValue(ClaimTypes.NameIdentifier) is {} guidStr && Guid.TryParse(guidStr, out var guid) ? guid : null;
|
return principal.Identity is { IsAuthenticated: true, AuthenticationType: AuthenticationType } && principal.FindFirstValue(ClaimTypes.NameIdentifier) is {} guidStr && Guid.TryParse(guidStr, out var guid) ? guid : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,21 +9,33 @@ using Phantom.Web.Services.Rpc;
|
|||||||
|
|
||||||
namespace Phantom.Web.Services.Instances;
|
namespace Phantom.Web.Services.Instances;
|
||||||
|
|
||||||
|
using InstanceDictionary = ImmutableDictionary<Guid, Instance>;
|
||||||
|
|
||||||
public sealed class InstanceManager {
|
public sealed class InstanceManager {
|
||||||
private readonly ControllerConnection controllerConnection;
|
private readonly ControllerConnection controllerConnection;
|
||||||
private readonly SimpleObservableState<ImmutableArray<Instance>> instances = new (PhantomLogger.Create<InstanceManager>("Instances"), ImmutableArray<Instance>.Empty);
|
private readonly SimpleObservableState<InstanceDictionary> instances = new (PhantomLogger.Create<InstanceManager>("Instances"), InstanceDictionary.Empty);
|
||||||
|
|
||||||
public InstanceManager(ControllerConnection controllerConnection) {
|
public InstanceManager(ControllerConnection controllerConnection) {
|
||||||
this.controllerConnection = controllerConnection;
|
this.controllerConnection = controllerConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventSubscribers<ImmutableArray<Instance>> InstancesChanged => instances.Subs;
|
public EventSubscribers<InstanceDictionary> InstancesChanged => instances.Subs;
|
||||||
|
|
||||||
internal void RefreshInstances(ImmutableArray<Instance> newInstances) {
|
internal void RefreshInstances(ImmutableArray<Instance> newInstances) {
|
||||||
instances.SetTo(newInstances);
|
instances.SetTo(newInstances.ToImmutableDictionary(static instance => instance.Configuration.InstanceGuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(InstanceConfiguration configuration) {
|
public Instance? GetByGuid(Guid instanceGuid) {
|
||||||
return controllerConnection.Send<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(new CreateOrUpdateInstanceMessage(configuration), TimeSpan.FromSeconds(30));
|
return instances.Value.GetValueOrDefault(instanceGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<InstanceActionResult<CreateOrUpdateInstanceResult>> CreateOrUpdateInstance(Guid loggedInUserGuid, InstanceConfiguration configuration) {
|
||||||
|
var message = new CreateOrUpdateInstanceMessage(loggedInUserGuid, configuration);
|
||||||
|
return controllerConnection.Send<CreateOrUpdateInstanceMessage, InstanceActionResult<CreateOrUpdateInstanceResult>>(message, TimeSpan.FromSeconds(30));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<InstanceActionResult<LaunchInstanceResult>> LaunchInstance(Guid loggedInUserGuid, Guid instanceGuid) {
|
||||||
|
var message = new LaunchInstanceMessage(loggedInUserGuid, instanceGuid);
|
||||||
|
return controllerConnection.Send<LaunchInstanceMessage, InstanceActionResult<LaunchInstanceResult>>(message, TimeSpan.FromSeconds(30));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public sealed class ControllerConnection {
|
|||||||
return connection.Send(message);
|
return connection.Send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TReply> Send<TMessage, TReply>(TMessage message, TimeSpan timeout) where TMessage : IMessageToController<TReply> {
|
public Task<TReply> Send<TMessage, TReply>(TMessage message, TimeSpan waitForReplyTime, CancellationToken waitForReplyCancellationToken = default) where TMessage : IMessageToController<TReply> {
|
||||||
return connection.Send<TMessage, TReply>(message, timeout, CancellationToken.None);
|
return connection.Send<TMessage, TReply>(message, waitForReplyTime, waitForReplyCancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using Phantom.Common.Data.Web.Users;
|
|||||||
using Phantom.Common.Logging;
|
using Phantom.Common.Logging;
|
||||||
using Phantom.Web.Services.Authorization;
|
using Phantom.Web.Services.Authorization;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
using UserInfo = Phantom.Web.Services.Authentication.UserInfo;
|
||||||
|
|
||||||
namespace Phantom.Web.Base;
|
namespace Phantom.Web.Base;
|
||||||
|
|
||||||
@ -16,6 +17,11 @@ public abstract class PhantomComponent : ComponentBase {
|
|||||||
[Inject]
|
[Inject]
|
||||||
public PermissionManager PermissionManager { get; set; } = null!;
|
public PermissionManager PermissionManager { get; set; } = null!;
|
||||||
|
|
||||||
|
public async Task<Guid?> GetUserGuid() {
|
||||||
|
var authenticationState = await AuthenticationStateTask;
|
||||||
|
return UserInfo.TryGetGuid(authenticationState.User);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<bool> CheckPermission(Permission permission) {
|
protected async Task<bool> CheckPermission(Permission permission) {
|
||||||
var authenticationState = await AuthenticationStateTask;
|
var authenticationState = await AuthenticationStateTask;
|
||||||
return PermissionManager.CheckPermission(authenticationState.User, permission);
|
return PermissionManager.CheckPermission(authenticationState.User, permission);
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
@page "/instances/{InstanceGuid:guid}"
|
@page "/instances/{InstanceGuid:guid}"
|
||||||
@attribute [Authorize(Permission.ViewInstancesPolicy)]
|
@attribute [Authorize(Permission.ViewInstancesPolicy)]
|
||||||
@inherits PhantomComponent
|
@inherits PhantomComponent
|
||||||
@using Phantom.Web.Services.Instances
|
@using Phantom.Common.Data.Instance
|
||||||
@using Phantom.Common.Data.Web.Users
|
|
||||||
@using Phantom.Common.Data.Replies
|
@using Phantom.Common.Data.Replies
|
||||||
|
@using Phantom.Common.Data.Web.Instance
|
||||||
|
@using Phantom.Common.Data.Web.Users
|
||||||
|
@using Phantom.Web.Services.Instances
|
||||||
@implements IDisposable
|
@implements IDisposable
|
||||||
@inject InstanceManager InstanceManager
|
@inject InstanceManager InstanceManager
|
||||||
@inject AuditLog AuditLog
|
|
||||||
|
|
||||||
@if (Instance == null) {
|
@if (Instance == null) {
|
||||||
<h1>Instance Not Found</h1>
|
<h1>Instance Not Found</h1>
|
||||||
@ -45,7 +46,7 @@ else {
|
|||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Guid InstanceGuid { get; set; }
|
public Guid InstanceGuid { get; init; }
|
||||||
|
|
||||||
private string? lastError = null;
|
private string? lastError = null;
|
||||||
private bool isLaunchingInstance = false;
|
private bool isLaunchingInstance = false;
|
||||||
@ -63,6 +64,11 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task LaunchInstance() {
|
private async Task LaunchInstance() {
|
||||||
|
var loggedInUserGuid = await GetUserGuid();
|
||||||
|
if (loggedInUserGuid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
isLaunchingInstance = true;
|
isLaunchingInstance = true;
|
||||||
lastError = null;
|
lastError = null;
|
||||||
|
|
||||||
@ -72,11 +78,8 @@ else {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await InstanceManager.LaunchInstance(InstanceGuid);
|
var result = await InstanceManager.LaunchInstance(loggedInUserGuid.Value, InstanceGuid);
|
||||||
if (result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
if (!result.Is(LaunchInstanceResult.LaunchInitiated)) {
|
||||||
await AuditLog.AddInstanceLaunchedEvent(InstanceGuid);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
lastError = result.ToSentence(Messages.ToSentence);
|
lastError = result.ToSentence(Messages.ToSentence);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -18,12 +18,12 @@ else {
|
|||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Guid InstanceGuid { get; set; }
|
public Guid InstanceGuid { get; init; }
|
||||||
|
|
||||||
private InstanceConfiguration? InstanceConfiguration { get; set; }
|
private InstanceConfiguration? InstanceConfiguration { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
InstanceConfiguration = InstanceManager.GetInstanceConfiguration(InstanceGuid);
|
InstanceConfiguration = InstanceManager.GetByGuid(InstanceGuid)?.Configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,8 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
InstanceManager.InstancesChanged.Subscribe(this, instances => {
|
InstanceManager.InstancesChanged.Subscribe(this, instances => {
|
||||||
this.instances = instances.OrderBy(instance => agentNames.TryGetValue(instance.Configuration.AgentGuid, out var agentName) ? agentName : string.Empty)
|
this.instances = instances.Values
|
||||||
|
.OrderBy(instance => agentNames.TryGetValue(instance.Configuration.AgentGuid, out var agentName) ? agentName : string.Empty)
|
||||||
.ThenBy(static instance => instance.Configuration.InstanceName)
|
.ThenBy(static instance => instance.Configuration.InstanceName)
|
||||||
.ToImmutableArray();
|
.ToImmutableArray();
|
||||||
InvokeAsync(StateHasChanged);
|
InvokeAsync(StateHasChanged);
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Result<string>> CreateOrUpdateAdministrator() {
|
private async Task<Result<string>> CreateOrUpdateAdministrator() {
|
||||||
var reply = await ControllerConnection.Send<CreateOrUpdateAdministratorUser, CreateOrUpdateAdministratorUserResult>(new CreateOrUpdateAdministratorUser(form.Username, form.Password), Timeout.InfiniteTimeSpan);
|
var reply = await ControllerConnection.Send<CreateOrUpdateAdministratorUserMessage, CreateOrUpdateAdministratorUserResult>(new CreateOrUpdateAdministratorUserMessage(form.Username, form.Password), Timeout.InfiniteTimeSpan);
|
||||||
return reply switch {
|
return reply switch {
|
||||||
Success => Result.Ok<string>(),
|
Success => Result.Ok<string>(),
|
||||||
CreationFailed fail => fail.Error.ToSentences("\n"),
|
CreationFailed fail => fail.Error.ToSentences("\n"),
|
||||||
|
@ -1,27 +1,31 @@
|
|||||||
@using Phantom.Web.Components.Utils
|
@using Phantom.Web.Components.Utils
|
||||||
@using Phantom.Common.Data.Minecraft
|
|
||||||
@using Phantom.Common.Data.Web.Minecraft
|
|
||||||
@using Phantom.Common.Data.Instance
|
|
||||||
@using Phantom.Common.Data.Java
|
|
||||||
@using System.Collections.Immutable
|
@using System.Collections.Immutable
|
||||||
@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.Web.Agent
|
||||||
|
@using Phantom.Common.Data.Web.Instance
|
||||||
|
@using Phantom.Common.Data.Web.Minecraft
|
||||||
|
@using Phantom.Common.Messages.Web.ToController
|
||||||
|
@using Phantom.Common.Data.Instance
|
||||||
|
@using Phantom.Common.Data.Java
|
||||||
@using Phantom.Common.Data
|
@using Phantom.Common.Data
|
||||||
@using Phantom.Web.Services
|
@using Phantom.Web.Services
|
||||||
|
@using Phantom.Web.Services.Agents
|
||||||
@using Phantom.Web.Services.Instances
|
@using Phantom.Web.Services.Instances
|
||||||
|
@using Phantom.Web.Services.Rpc
|
||||||
|
@inherits PhantomComponent
|
||||||
@inject INavigation Nav
|
@inject INavigation Nav
|
||||||
@inject MinecraftVersions MinecraftVersions
|
@inject ControllerConnection ControllerConnection
|
||||||
@inject AgentManager AgentManager
|
@inject AgentManager AgentManager
|
||||||
@inject AgentJavaRuntimesManager AgentJavaRuntimesManager
|
|
||||||
@inject InstanceManager InstanceManager
|
@inject InstanceManager InstanceManager
|
||||||
@inject AuditLog AuditLog
|
|
||||||
|
|
||||||
<Form Model="form" OnSubmit="AddOrEditInstance">
|
<Form Model="form" OnSubmit="AddOrEditInstance">
|
||||||
@{ var selectedAgent = form.SelectedAgent; }
|
@{ var selectedAgent = form.SelectedAgent; }
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xl-7 mb-3">
|
<div class="col-xl-7 mb-3">
|
||||||
@{
|
@{
|
||||||
static RenderFragment GetAgentOption(Agent agent) {
|
static RenderFragment GetAgentOption(AgentWithStats agent) {
|
||||||
return @<option value="@agent.Guid">
|
return @<option value="@agent.Guid">
|
||||||
@agent.Name
|
@agent.Name
|
||||||
•
|
•
|
||||||
@ -34,14 +38,14 @@
|
|||||||
@if (EditedInstanceConfiguration == null) {
|
@if (EditedInstanceConfiguration == null) {
|
||||||
<FormSelectInput Id="instance-agent" Label="Agent" @bind-Value="form.SelectedAgentGuid">
|
<FormSelectInput Id="instance-agent" Label="Agent" @bind-Value="form.SelectedAgentGuid">
|
||||||
<option value="" selected>Select which agent will run the instance...</option>
|
<option value="" selected>Select which agent will run the instance...</option>
|
||||||
@foreach (var agent in form.AgentsByGuid.Values.Where(static agent => agent.IsOnline).OrderBy(static agent => agent.Name)) {
|
@foreach (var agent in allAgentsByGuid.Values.Where(static agent => agent.IsOnline).OrderBy(static agent => agent.Name)) {
|
||||||
@GetAgentOption(agent)
|
@GetAgentOption(agent)
|
||||||
}
|
}
|
||||||
</FormSelectInput>
|
</FormSelectInput>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
<FormSelectInput Id="instance-agent" Label="Agent" @bind-Value="form.SelectedAgentGuid" disabled="true">
|
<FormSelectInput Id="instance-agent" Label="Agent" @bind-Value="form.SelectedAgentGuid" disabled="true">
|
||||||
@if (form.SelectedAgentGuid is {} guid && form.AgentsByGuid.TryGetValue(guid, out var agent)) {
|
@if (form.SelectedAgentGuid is {} guid && allAgentsByGuid.TryGetValue(guid, out var agent)) {
|
||||||
@GetAgentOption(agent)
|
@GetAgentOption(agent)
|
||||||
}
|
}
|
||||||
</FormSelectInput>
|
</FormSelectInput>
|
||||||
@ -160,23 +164,25 @@
|
|||||||
@code {
|
@code {
|
||||||
|
|
||||||
[Parameter, EditorRequired]
|
[Parameter, EditorRequired]
|
||||||
public InstanceConfiguration? EditedInstanceConfiguration { get; set; }
|
public InstanceConfiguration? EditedInstanceConfiguration { get; init; }
|
||||||
|
|
||||||
private ConfigureInstanceFormModel form = null!;
|
private ConfigureInstanceFormModel form = null!;
|
||||||
|
|
||||||
|
private ImmutableDictionary<Guid, AgentWithStats> allAgentsByGuid = ImmutableDictionary<Guid, AgentWithStats>.Empty;
|
||||||
|
private ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>> allAgentJavaRuntimes = ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>.Empty;
|
||||||
|
|
||||||
private MinecraftVersionType minecraftVersionType = MinecraftVersionType.Release;
|
private MinecraftVersionType minecraftVersionType = MinecraftVersionType.Release;
|
||||||
|
private ImmutableArray<MinecraftVersion> allMinecraftVersions = ImmutableArray<MinecraftVersion>.Empty;
|
||||||
private ImmutableArray<MinecraftVersion> availableMinecraftVersions = ImmutableArray<MinecraftVersion>.Empty;
|
private ImmutableArray<MinecraftVersion> availableMinecraftVersions = ImmutableArray<MinecraftVersion>.Empty;
|
||||||
|
|
||||||
private bool IsSubmittable => form.SelectedAgentGuid != null && !form.EditContext.GetValidationMessages(form.EditContext.Field(nameof(ConfigureInstanceFormModel.SelectedAgentGuid))).Any();
|
private bool IsSubmittable => form.SelectedAgentGuid != null && !form.EditContext.GetValidationMessages(form.EditContext.Field(nameof(ConfigureInstanceFormModel.SelectedAgentGuid))).Any();
|
||||||
|
|
||||||
private sealed class ConfigureInstanceFormModel : FormModel {
|
private sealed class ConfigureInstanceFormModel : FormModel {
|
||||||
public ImmutableDictionary<Guid, Agent> AgentsByGuid { get; }
|
private readonly InstanceAddOrEditForm page;
|
||||||
private readonly ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>> javaRuntimesByAgentGuid;
|
|
||||||
private readonly RamAllocationUnits? editedInstanceRamAllocation;
|
private readonly RamAllocationUnits? editedInstanceRamAllocation;
|
||||||
|
|
||||||
public ConfigureInstanceFormModel(AgentManager agentManager, AgentJavaRuntimesManager agentJavaRuntimesManager, RamAllocationUnits? editedInstanceRamAllocation) {
|
public ConfigureInstanceFormModel(InstanceAddOrEditForm page, RamAllocationUnits? editedInstanceRamAllocation) {
|
||||||
this.AgentsByGuid = agentManager.GetAgents().ToImmutableDictionary();
|
this.page = page;
|
||||||
this.javaRuntimesByAgentGuid = agentJavaRuntimesManager.All;
|
|
||||||
this.editedInstanceRamAllocation = editedInstanceRamAllocation;
|
this.editedInstanceRamAllocation = editedInstanceRamAllocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,14 +196,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryGetAgent(Guid? agentGuid, [NotNullWhen(true)] out Agent? agent) {
|
private bool TryGetAgent(Guid? agentGuid, [NotNullWhen(true)] out AgentWithStats? agent) {
|
||||||
return TryGet(AgentsByGuid, agentGuid, out agent);
|
return TryGet(page.allAgentsByGuid, agentGuid, out agent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Agent? SelectedAgent => TryGetAgent(SelectedAgentGuid, out var agent) ? agent : null;
|
public AgentWithStats? SelectedAgent => TryGetAgent(SelectedAgentGuid, out var agent) ? agent : null;
|
||||||
|
|
||||||
public ImmutableArray<TaggedJavaRuntime> JavaRuntimesForSelectedAgent => TryGet(javaRuntimesByAgentGuid, SelectedAgentGuid, out var javaRuntimes) ? javaRuntimes : ImmutableArray<TaggedJavaRuntime>.Empty;
|
public ImmutableArray<TaggedJavaRuntime> JavaRuntimesForSelectedAgent => TryGet(page.allAgentJavaRuntimes, SelectedAgentGuid, out var javaRuntimes) ? javaRuntimes : ImmutableArray<TaggedJavaRuntime>.Empty;
|
||||||
|
|
||||||
public ushort MaximumMemoryUnits => SelectedAgent?.MaxMemory.RawValue ?? 0;
|
public ushort MaximumMemoryUnits => SelectedAgent?.MaxMemory.RawValue ?? 0;
|
||||||
public ushort AvailableMemoryUnits => Math.Min((SelectedAgent?.AvailableMemory + editedInstanceRamAllocation)?.RawValue ?? MaximumMemoryUnits, MaximumMemoryUnits);
|
public ushort AvailableMemoryUnits => Math.Min((SelectedAgent?.AvailableMemory + editedInstanceRamAllocation)?.RawValue ?? MaximumMemoryUnits, MaximumMemoryUnits);
|
||||||
private ushort selectedMemoryUnits = 4;
|
private ushort selectedMemoryUnits = 4;
|
||||||
@ -263,8 +269,17 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override void OnInitialized() {
|
||||||
form = new ConfigureInstanceFormModel(AgentManager, AgentJavaRuntimesManager, EditedInstanceConfiguration?.MemoryAllocation);
|
form = new ConfigureInstanceFormModel(this, EditedInstanceConfiguration?.MemoryAllocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task OnInitializedAsync() {
|
||||||
|
var agentJavaRuntimesTask = ControllerConnection.Send<GetAgentJavaRuntimes, ImmutableDictionary<Guid, ImmutableArray<TaggedJavaRuntime>>>(new GetAgentJavaRuntimes(), TimeSpan.FromSeconds(30));
|
||||||
|
var minecraftVersionsTask = ControllerConnection.Send<GetMinecraftVersionsMessage, ImmutableArray<MinecraftVersion>>(new GetMinecraftVersionsMessage(), TimeSpan.FromSeconds(30));
|
||||||
|
|
||||||
|
allAgentsByGuid = AgentManager.ToDictionaryByGuid();
|
||||||
|
allAgentJavaRuntimes = await agentJavaRuntimesTask;
|
||||||
|
allMinecraftVersions = await minecraftVersionsTask;
|
||||||
|
|
||||||
if (EditedInstanceConfiguration != null) {
|
if (EditedInstanceConfiguration != null) {
|
||||||
form.SelectedAgentGuid = EditedInstanceConfiguration.AgentGuid;
|
form.SelectedAgentGuid = EditedInstanceConfiguration.AgentGuid;
|
||||||
form.InstanceName = EditedInstanceConfiguration.InstanceName;
|
form.InstanceName = EditedInstanceConfiguration.InstanceName;
|
||||||
@ -275,28 +290,21 @@
|
|||||||
form.MemoryUnits = EditedInstanceConfiguration.MemoryAllocation.RawValue;
|
form.MemoryUnits = EditedInstanceConfiguration.MemoryAllocation.RawValue;
|
||||||
form.JavaRuntimeGuid = EditedInstanceConfiguration.JavaRuntimeGuid;
|
form.JavaRuntimeGuid = EditedInstanceConfiguration.JavaRuntimeGuid;
|
||||||
form.JvmArguments = JvmArgumentsHelper.Join(EditedInstanceConfiguration.JvmArguments);
|
form.JvmArguments = JvmArgumentsHelper.Join(EditedInstanceConfiguration.JvmArguments);
|
||||||
|
|
||||||
|
minecraftVersionType = allMinecraftVersions.FirstOrDefault(version => version.Id == EditedInstanceConfiguration.MinecraftVersion)?.Type ?? minecraftVersionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.MemoryUnits));
|
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.MemoryUnits));
|
||||||
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.JavaRuntimeGuid));
|
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.JavaRuntimeGuid));
|
||||||
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.ServerPort));
|
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.ServerPort));
|
||||||
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.RconPort));
|
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.SelectedAgentGuid), revalidated: nameof(ConfigureInstanceFormModel.RconPort));
|
||||||
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.ServerPort), revalidated: nameof(ConfigureInstanceFormModel.RconPort));
|
form.EditContext.RevalidateWhenFieldChanges(tracked: nameof(ConfigureInstanceFormModel.ServerPort), revalidated: nameof(ConfigureInstanceFormModel.RconPort));
|
||||||
|
|
||||||
|
SetMinecraftVersionType(minecraftVersionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
private void SetMinecraftVersionType(MinecraftVersionType type) {
|
||||||
if (EditedInstanceConfiguration != null) {
|
|
||||||
var allMinecraftVersions = await MinecraftVersions.GetVersions(CancellationToken.None);
|
|
||||||
minecraftVersionType = allMinecraftVersions.FirstOrDefault(version => version.Id == EditedInstanceConfiguration.MinecraftVersion)?.Type ?? minecraftVersionType;
|
|
||||||
}
|
|
||||||
|
|
||||||
await SetMinecraftVersionType(minecraftVersionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetMinecraftVersionType(MinecraftVersionType type) {
|
|
||||||
minecraftVersionType = type;
|
minecraftVersionType = type;
|
||||||
|
|
||||||
var allMinecraftVersions = await MinecraftVersions.GetVersions(CancellationToken.None);
|
|
||||||
availableMinecraftVersions = allMinecraftVersions.Where(version => version.Type == type).ToImmutableArray();
|
availableMinecraftVersions = allMinecraftVersions.Where(version => version.Type == type).ToImmutableArray();
|
||||||
|
|
||||||
if (!availableMinecraftVersions.IsEmpty && !availableMinecraftVersions.Any(version => version.Id == form.MinecraftVersion)) {
|
if (!availableMinecraftVersions.IsEmpty && !availableMinecraftVersions.Any(version => version.Id == form.MinecraftVersion)) {
|
||||||
@ -305,6 +313,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task AddOrEditInstance(EditContext context) {
|
private async Task AddOrEditInstance(EditContext context) {
|
||||||
|
var loggedInUserGuid = await GetUserGuid();
|
||||||
|
if (loggedInUserGuid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var selectedAgent = form.SelectedAgent;
|
var selectedAgent = form.SelectedAgent;
|
||||||
if (selectedAgent == null) {
|
if (selectedAgent == null) {
|
||||||
return;
|
return;
|
||||||
@ -325,14 +338,13 @@
|
|||||||
JvmArgumentsHelper.Split(form.JvmArguments)
|
JvmArgumentsHelper.Split(form.JvmArguments)
|
||||||
);
|
);
|
||||||
|
|
||||||
var result = await InstanceManager.AddOrEditInstance(instance);
|
var result = await InstanceManager.CreateOrUpdateInstance(loggedInUserGuid.Value, instance);
|
||||||
if (result.Is(AddOrEditInstanceResult.Success)) {
|
if (result.Is(CreateOrUpdateInstanceResult.Success)) {
|
||||||
await (EditedInstanceConfiguration == null ? AuditLog.AddInstanceCreatedEvent(instance.InstanceGuid) : AuditLog.AddInstanceEditedEvent(instance.InstanceGuid));
|
await Nav.NavigateTo("instances/" + instance.InstanceGuid);
|
||||||
Nav.NavigateTo("instances/" + instance.InstanceGuid);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
form.SubmitModel.StopSubmitting(result.ToSentence(AddOrEditInstanceResultExtensions.ToSentence));
|
form.SubmitModel.StopSubmitting(result.ToSentence(CreateOrUpdateInstanceResultExtensions.ToSentence));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user