mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-07-31 02:59:01 +02:00
Migrate from MessagePack to MemoryPack for RPC serialization
This commit is contained in:
parent
ff5d31bf05
commit
24e08f1943
Agent/Phantom.Agent.Services/Instances
Common
Phantom.Common.Data
Agent
AllowedPorts.csInstance
Java
Minecraft
Phantom.Common.Data.csprojPortRange.csRamAllocationUnits.csPhantom.Common.Messages
Server
Phantom.Server.Services
Phantom.Server.Web/Shared
Utils/Phantom.Utils.Rpc
@ -33,7 +33,7 @@ sealed class Instance : IDisposable {
|
||||
private readonly LaunchServices launchServices;
|
||||
private readonly PortManager portManager;
|
||||
|
||||
private InstanceStatus currentStatus;
|
||||
private IInstanceStatus currentStatus;
|
||||
private IInstanceState currentState;
|
||||
private readonly SemaphoreSlim stateTransitioningActionSemaphore = new (1, 1);
|
||||
|
||||
@ -47,7 +47,7 @@ sealed class Instance : IDisposable {
|
||||
this.launchServices = launchServices;
|
||||
this.portManager = portManager;
|
||||
this.currentState = new InstanceNotRunningState();
|
||||
this.currentStatus = InstanceStatus.IsNotRunning;
|
||||
this.currentStatus = InstanceStatus.NotRunning;
|
||||
}
|
||||
|
||||
private async Task ReportLastStatus() {
|
||||
@ -137,7 +137,7 @@ sealed class Instance : IDisposable {
|
||||
public override ILogger Logger => instance.logger;
|
||||
public override string ShortName => instance.shortName;
|
||||
|
||||
public override void ReportStatus(InstanceStatus newStatus) {
|
||||
public override void ReportStatus(IInstanceStatus newStatus) {
|
||||
int myStatusUpdateCounter = Interlocked.Increment(ref statusUpdateCounter);
|
||||
|
||||
instance.launchServices.TaskManager.Run(async () => {
|
||||
|
@ -19,7 +19,7 @@ abstract class InstanceContext {
|
||||
Launcher = launcher;
|
||||
}
|
||||
|
||||
public abstract void ReportStatus(InstanceStatus newStatus);
|
||||
public abstract void ReportStatus(IInstanceStatus newStatus);
|
||||
public abstract void TransitionState(Func<IInstanceState> newState);
|
||||
|
||||
public void TransitionState(IInstanceState newState) {
|
||||
|
@ -33,7 +33,7 @@ sealed class InstanceLaunchingState : IInstanceState, IDisposable {
|
||||
|
||||
if (lastDownloadProgress != progress) {
|
||||
lastDownloadProgress = progress;
|
||||
context.ReportStatus(new InstanceStatus.Downloading(progress));
|
||||
context.ReportStatus(InstanceStatus.Downloading(progress));
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ sealed class InstanceLaunchingState : IInstanceState, IDisposable {
|
||||
throw new LaunchFailureException(InstanceLaunchFailReason.UnknownError, "Session failed to launch.");
|
||||
}
|
||||
|
||||
context.ReportStatus(InstanceStatus.IsLaunching);
|
||||
context.ReportStatus(InstanceStatus.Launching);
|
||||
return launchSuccess.Session;
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ sealed class InstanceLaunchingState : IInstanceState, IDisposable {
|
||||
context.TransitionState(() => {
|
||||
if (cancellationTokenSource.IsCancellationRequested) {
|
||||
context.PortManager.Release(context.Configuration);
|
||||
context.ReportStatus(InstanceStatus.IsNotRunning);
|
||||
context.ReportStatus(InstanceStatus.NotRunning);
|
||||
return new InstanceNotRunningState();
|
||||
}
|
||||
else {
|
||||
@ -72,10 +72,10 @@ sealed class InstanceLaunchingState : IInstanceState, IDisposable {
|
||||
private void OnLaunchFailure(Task task) {
|
||||
if (task.Exception is { InnerException: LaunchFailureException e }) {
|
||||
context.Logger.Error(e.LogMessage);
|
||||
context.ReportStatus(new InstanceStatus.Failed(e.Reason));
|
||||
context.ReportStatus(InstanceStatus.Failed(e.Reason));
|
||||
}
|
||||
else {
|
||||
context.ReportStatus(new InstanceStatus.Failed(InstanceLaunchFailReason.UnknownError));
|
||||
context.ReportStatus(InstanceStatus.Failed(InstanceLaunchFailReason.UnknownError));
|
||||
}
|
||||
|
||||
context.PortManager.Release(context.Configuration);
|
||||
|
@ -17,11 +17,11 @@ sealed class InstanceNotRunningState : IInstanceState {
|
||||
};
|
||||
|
||||
if (failReason != null) {
|
||||
context.ReportStatus(new InstanceStatus.Failed(failReason.Value));
|
||||
context.ReportStatus(InstanceStatus.Failed(failReason.Value));
|
||||
return (this, LaunchInstanceResult.LaunchInitiated);
|
||||
}
|
||||
|
||||
context.ReportStatus(InstanceStatus.IsLaunching);
|
||||
context.ReportStatus(InstanceStatus.Launching);
|
||||
return (new InstanceLaunchingState(context), LaunchInstanceResult.LaunchInitiated);
|
||||
}
|
||||
|
||||
|
@ -30,12 +30,12 @@ sealed class InstanceRunningState : IInstanceState {
|
||||
if (session.HasEnded) {
|
||||
if (sessionObjects.Dispose()) {
|
||||
context.Logger.Warning("Session ended immediately after it was started.");
|
||||
context.ReportStatus(new InstanceStatus.Failed(InstanceLaunchFailReason.UnknownError));
|
||||
context.ReportStatus(InstanceStatus.Failed(InstanceLaunchFailReason.UnknownError));
|
||||
context.LaunchServices.TaskManager.Run(() => context.TransitionState(new InstanceNotRunningState()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
context.ReportStatus(InstanceStatus.IsRunning);
|
||||
context.ReportStatus(InstanceStatus.Running);
|
||||
context.Logger.Information("Session started.");
|
||||
}
|
||||
}
|
||||
@ -52,12 +52,12 @@ sealed class InstanceRunningState : IInstanceState {
|
||||
|
||||
if (isStopping) {
|
||||
context.Logger.Information("Session ended.");
|
||||
context.ReportStatus(InstanceStatus.IsNotRunning);
|
||||
context.ReportStatus(InstanceStatus.NotRunning);
|
||||
context.TransitionState(new InstanceNotRunningState());
|
||||
}
|
||||
else {
|
||||
context.Logger.Information("Session ended unexpectedly, restarting...");
|
||||
context.ReportStatus(InstanceStatus.IsRestarting);
|
||||
context.ReportStatus(InstanceStatus.Restarting);
|
||||
context.TransitionState(new InstanceLaunchingState(context));
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ sealed class InstanceStoppingState : IInstanceState, IDisposable {
|
||||
|
||||
public void Initialize() {
|
||||
context.Logger.Information("Session stopping.");
|
||||
context.ReportStatus(InstanceStatus.IsStopping);
|
||||
context.ReportStatus(InstanceStatus.Stopping);
|
||||
context.LaunchServices.TaskManager.Run(DoStop);
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ sealed class InstanceStoppingState : IInstanceState, IDisposable {
|
||||
await DoWaitForSessionToEnd();
|
||||
} finally {
|
||||
context.Logger.Information("Session stopped.");
|
||||
context.ReportStatus(InstanceStatus.IsNotRunning);
|
||||
context.ReportStatus(InstanceStatus.NotRunning);
|
||||
context.TransitionState(new InstanceNotRunningState());
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,17 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Security.Cryptography;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Agent;
|
||||
|
||||
[MessagePackObject]
|
||||
[MemoryPackable]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public sealed class AgentAuthToken {
|
||||
public sealed partial class AgentAuthToken {
|
||||
internal const int Length = 12;
|
||||
|
||||
[Key(0)]
|
||||
public byte[] Bytes { get; }
|
||||
[MemoryPackOrder(0)]
|
||||
[MemoryPackInclude]
|
||||
private readonly byte[] bytes;
|
||||
|
||||
public AgentAuthToken(byte[]? bytes) {
|
||||
if (bytes == null) {
|
||||
@ -21,15 +22,15 @@ public sealed class AgentAuthToken {
|
||||
throw new ArgumentOutOfRangeException(nameof(bytes), "Invalid token length: " + bytes.Length + ". Token length must be exactly " + Length + " bytes.");
|
||||
}
|
||||
|
||||
this.Bytes = bytes;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
public bool FixedTimeEquals(AgentAuthToken providedAuthToken) {
|
||||
return CryptographicOperations.FixedTimeEquals(Bytes, providedAuthToken.Bytes);
|
||||
return CryptographicOperations.FixedTimeEquals(bytes, providedAuthToken.bytes);
|
||||
}
|
||||
|
||||
internal void WriteTo(Span<byte> span) {
|
||||
Bytes.CopyTo(span);
|
||||
bytes.CopyTo(span);
|
||||
}
|
||||
|
||||
public static AgentAuthToken Generate() {
|
||||
|
@ -1,14 +1,14 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Agent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record AgentInfo(
|
||||
[property: Key(0)] Guid Guid,
|
||||
[property: Key(1)] string Name,
|
||||
[property: Key(2)] ushort Version,
|
||||
[property: Key(3)] ushort MaxInstances,
|
||||
[property: Key(4)] RamAllocationUnits MaxMemory,
|
||||
[property: Key(5)] AllowedPorts AllowedServerPorts,
|
||||
[property: Key(6)] AllowedPorts AllowedRconPorts
|
||||
[MemoryPackable]
|
||||
public sealed partial record AgentInfo(
|
||||
[property: MemoryPackOrder(0)] Guid Guid,
|
||||
[property: MemoryPackOrder(1)] string Name,
|
||||
[property: MemoryPackOrder(2)] ushort Version,
|
||||
[property: MemoryPackOrder(3)] ushort MaxInstances,
|
||||
[property: MemoryPackOrder(4)] RamAllocationUnits MaxMemory,
|
||||
[property: MemoryPackOrder(5)] AllowedPorts AllowedServerPorts,
|
||||
[property: MemoryPackOrder(6)] AllowedPorts AllowedRconPorts
|
||||
);
|
||||
|
@ -1,29 +1,28 @@
|
||||
using System.Collections.Immutable;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data;
|
||||
|
||||
[MessagePackObject]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public sealed class AllowedPorts {
|
||||
[Key(0)]
|
||||
public ImmutableArray<PortRange> AllDefinitions { get; }
|
||||
[MemoryPackable]
|
||||
public sealed partial class AllowedPorts {
|
||||
[MemoryPackOrder(0)]
|
||||
[MemoryPackInclude]
|
||||
private readonly ImmutableArray<PortRange> allDefinitions;
|
||||
|
||||
public AllowedPorts(ImmutableArray<PortRange> allDefinitions) {
|
||||
private AllowedPorts(ImmutableArray<PortRange> allDefinitions) {
|
||||
// TODO normalize and deduplicate ranges
|
||||
this.AllDefinitions = allDefinitions.Sort(static (def1, def2) => def1.FirstPort - def2.FirstPort);
|
||||
this.allDefinitions = allDefinitions.Sort(static (def1, def2) => def1.FirstPort - def2.FirstPort);
|
||||
}
|
||||
|
||||
public bool Contains(ushort port) {
|
||||
return AllDefinitions.Any(definition => definition.Contains(port));
|
||||
return allDefinitions.Any(definition => definition.Contains(port));
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
var builder = new StringBuilder();
|
||||
|
||||
foreach (var definition in AllDefinitions) {
|
||||
foreach (var definition in allDefinitions) {
|
||||
definition.ToString(builder);
|
||||
builder.Append(',');
|
||||
}
|
||||
@ -35,53 +34,7 @@ public sealed class AllowedPorts {
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
[MessagePackObject]
|
||||
public readonly record struct PortRange(
|
||||
[property: Key(0)] ushort FirstPort,
|
||||
[property: Key(1)] ushort LastPort
|
||||
) {
|
||||
private PortRange(ushort port) : this(port, port) {}
|
||||
|
||||
internal bool Contains(ushort port) {
|
||||
return port >= FirstPort && port <= LastPort;
|
||||
}
|
||||
|
||||
internal void ToString(StringBuilder builder) {
|
||||
builder.Append(FirstPort);
|
||||
|
||||
if (LastPort != FirstPort) {
|
||||
builder.Append('-');
|
||||
builder.Append(LastPort);
|
||||
}
|
||||
}
|
||||
|
||||
internal static PortRange Parse(ReadOnlySpan<char> definition) {
|
||||
int separatorIndex = definition.IndexOf('-');
|
||||
if (separatorIndex == -1) {
|
||||
var port = ParsePort(definition.Trim());
|
||||
return new PortRange(port);
|
||||
}
|
||||
|
||||
var firstPort = ParsePort(definition[..separatorIndex].Trim());
|
||||
var lastPort = ParsePort(definition[(separatorIndex + 1)..].Trim());
|
||||
if (lastPort < firstPort) {
|
||||
throw new FormatException("Invalid port range '" + firstPort + "-" + lastPort + "'.");
|
||||
}
|
||||
else {
|
||||
return new PortRange(firstPort, lastPort);
|
||||
}
|
||||
}
|
||||
|
||||
private static ushort ParsePort(ReadOnlySpan<char> port) {
|
||||
try {
|
||||
return ushort.Parse(port);
|
||||
} catch (Exception) {
|
||||
throw new FormatException("Invalid port '" + port.ToString() + "'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static AllowedPorts FromString(ReadOnlySpan<char> definitions) {
|
||||
private static AllowedPorts FromString(ReadOnlySpan<char> definitions) {
|
||||
List<PortRange> parsedDefinitions = new ();
|
||||
|
||||
while (!definitions.IsEmpty) {
|
||||
|
67
Common/Phantom.Common.Data/Instance/IInstanceStatus.cs
Normal file
67
Common/Phantom.Common.Data/Instance/IInstanceStatus.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Instance;
|
||||
|
||||
[MemoryPackable]
|
||||
[MemoryPackUnion(0, typeof(InstanceIsOffline))]
|
||||
[MemoryPackUnion(1, typeof(InstanceIsInvalid))]
|
||||
[MemoryPackUnion(2, typeof(InstanceIsNotRunning))]
|
||||
[MemoryPackUnion(3, typeof(InstanceIsDownloading))]
|
||||
[MemoryPackUnion(4, typeof(InstanceIsLaunching))]
|
||||
[MemoryPackUnion(5, typeof(InstanceIsRunning))]
|
||||
[MemoryPackUnion(6, typeof(InstanceIsRestarting))]
|
||||
[MemoryPackUnion(7, typeof(InstanceIsStopping))]
|
||||
[MemoryPackUnion(8, typeof(InstanceIsFailed))]
|
||||
public partial interface IInstanceStatus {}
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsOffline : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsInvalid([property: MemoryPackOrder(0)] string Reason) : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsNotRunning : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsDownloading([property: MemoryPackOrder(0)] byte Progress) : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsLaunching : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsRunning : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsRestarting : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsStopping : IInstanceStatus;
|
||||
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceIsFailed([property: MemoryPackOrder(0)] InstanceLaunchFailReason Reason) : IInstanceStatus;
|
||||
|
||||
public static class InstanceStatus {
|
||||
public static readonly IInstanceStatus Offline = new InstanceIsOffline();
|
||||
public static readonly IInstanceStatus NotRunning = new InstanceIsNotRunning();
|
||||
public static readonly IInstanceStatus Launching = new InstanceIsLaunching();
|
||||
public static readonly IInstanceStatus Running = new InstanceIsRunning();
|
||||
public static readonly IInstanceStatus Restarting = new InstanceIsRestarting();
|
||||
public static readonly IInstanceStatus Stopping = new InstanceIsStopping();
|
||||
|
||||
public static IInstanceStatus Invalid(string reason) => new InstanceIsInvalid(reason);
|
||||
public static IInstanceStatus Downloading(byte progress) => new InstanceIsDownloading(progress);
|
||||
public static IInstanceStatus Failed(InstanceLaunchFailReason reason) => new InstanceIsFailed(reason);
|
||||
|
||||
public static bool CanLaunch(this IInstanceStatus status) {
|
||||
return status is InstanceIsNotRunning or InstanceIsFailed;
|
||||
}
|
||||
|
||||
public static bool CanStop(this IInstanceStatus status) {
|
||||
return status is InstanceIsDownloading or InstanceIsLaunching or InstanceIsRunning;
|
||||
}
|
||||
|
||||
public static bool CanSendCommand(this IInstanceStatus status) {
|
||||
return status is InstanceIsRunning;
|
||||
}
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
using System.Collections.Immutable;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
|
||||
namespace Phantom.Common.Data.Instance;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record InstanceConfiguration(
|
||||
[property: Key(0)] Guid AgentGuid,
|
||||
[property: Key(1)] Guid InstanceGuid,
|
||||
[property: Key(2)] string InstanceName,
|
||||
[property: Key(3)] ushort ServerPort,
|
||||
[property: Key(4)] ushort RconPort,
|
||||
[property: Key(5)] string MinecraftVersion,
|
||||
[property: Key(6)] MinecraftServerKind MinecraftServerKind,
|
||||
[property: Key(7)] RamAllocationUnits MemoryAllocation,
|
||||
[property: Key(8)] Guid JavaRuntimeGuid,
|
||||
[property: Key(9)] ImmutableArray<string> JvmArguments,
|
||||
[property: Key(10)] bool LaunchAutomatically
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceConfiguration(
|
||||
[property: MemoryPackOrder(0)] Guid AgentGuid,
|
||||
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(2)] string InstanceName,
|
||||
[property: MemoryPackOrder(3)] ushort ServerPort,
|
||||
[property: MemoryPackOrder(4)] ushort RconPort,
|
||||
[property: MemoryPackOrder(5)] string MinecraftVersion,
|
||||
[property: MemoryPackOrder(6)] MinecraftServerKind MinecraftServerKind,
|
||||
[property: MemoryPackOrder(7)] RamAllocationUnits MemoryAllocation,
|
||||
[property: MemoryPackOrder(8)] Guid JavaRuntimeGuid,
|
||||
[property: MemoryPackOrder(9)] ImmutableArray<string> JvmArguments,
|
||||
[property: MemoryPackOrder(10)] bool LaunchAutomatically
|
||||
);
|
||||
|
@ -1,68 +0,0 @@
|
||||
using MessagePack;
|
||||
|
||||
namespace Phantom.Common.Data.Instance;
|
||||
|
||||
[Union(0, typeof(Offline))]
|
||||
[Union(1, typeof(Invalid))]
|
||||
[Union(2, typeof(NotRunning))]
|
||||
[Union(3, typeof(Downloading))]
|
||||
[Union(4, typeof(Launching))]
|
||||
[Union(5, typeof(Running))]
|
||||
[Union(6, typeof(Restarting))]
|
||||
[Union(7, typeof(Stopping))]
|
||||
[Union(8, typeof(Failed))]
|
||||
public abstract record InstanceStatus {
|
||||
public static readonly InstanceStatus IsOffline = new Offline();
|
||||
public static readonly InstanceStatus IsNotRunning = new NotRunning();
|
||||
public static readonly InstanceStatus IsLaunching = new Launching();
|
||||
public static readonly InstanceStatus IsRunning = new Running();
|
||||
public static readonly InstanceStatus IsRestarting = new Restarting();
|
||||
public static readonly InstanceStatus IsStopping = new Stopping();
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Offline : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Invalid(
|
||||
[property: Key(0)] string Reason
|
||||
) : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record NotRunning : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Downloading(
|
||||
[property: Key(0)] byte Progress
|
||||
) : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Launching : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Running : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Restarting : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Stopping : InstanceStatus;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record Failed(
|
||||
[property: Key(0)] InstanceLaunchFailReason Reason
|
||||
) : InstanceStatus;
|
||||
}
|
||||
|
||||
public static class InstanceStatusExtensions {
|
||||
public static bool CanLaunch(this InstanceStatus status) {
|
||||
return status is InstanceStatus.NotRunning or InstanceStatus.Failed;
|
||||
}
|
||||
|
||||
public static bool CanStop(this InstanceStatus status) {
|
||||
return status is InstanceStatus.Downloading or InstanceStatus.Launching or InstanceStatus.Running;
|
||||
}
|
||||
|
||||
public static bool CanSendCommand(this InstanceStatus status) {
|
||||
return status is InstanceStatus.Running;
|
||||
}
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Java;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record JavaRuntime(
|
||||
[property: Key(0)] string MainVersion,
|
||||
[property: Key(1)] string FullVersion,
|
||||
[property: Key(2)] string DisplayName
|
||||
[MemoryPackable]
|
||||
public sealed partial record JavaRuntime(
|
||||
[property: MemoryPackOrder(0)] string MainVersion,
|
||||
[property: MemoryPackOrder(1)] string FullVersion,
|
||||
[property: MemoryPackOrder(2)] string DisplayName
|
||||
) : IComparable<JavaRuntime> {
|
||||
public int CompareTo(JavaRuntime? other) {
|
||||
if (ReferenceEquals(this, other)) {
|
||||
|
@ -1,9 +1,9 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Java;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record TaggedJavaRuntime(
|
||||
[property: Key(0)] Guid Guid,
|
||||
[property: Key(1)] JavaRuntime Runtime
|
||||
[MemoryPackable]
|
||||
public sealed partial record TaggedJavaRuntime(
|
||||
[property: MemoryPackOrder(0)] Guid Guid,
|
||||
[property: MemoryPackOrder(1)] JavaRuntime Runtime
|
||||
);
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data.Minecraft;
|
||||
|
||||
[MessagePackObject]
|
||||
public readonly record struct MinecraftStopStrategy(
|
||||
[property: Key(0)] ushort Seconds
|
||||
[MemoryPackable]
|
||||
public readonly partial record struct MinecraftStopStrategy(
|
||||
[property: MemoryPackOrder(0)] ushort Seconds
|
||||
) {
|
||||
public static MinecraftStopStrategy Instant => new (0);
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack.Annotations" />
|
||||
<PackageReference Include="MemoryPack" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
48
Common/Phantom.Common.Data/PortRange.cs
Normal file
48
Common/Phantom.Common.Data/PortRange.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using System.Text;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data;
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial record struct PortRange(
|
||||
[property: MemoryPackOrder(0)] ushort FirstPort,
|
||||
[property: MemoryPackOrder(1)] ushort LastPort
|
||||
) {
|
||||
internal bool Contains(ushort port) {
|
||||
return port >= FirstPort && port <= LastPort;
|
||||
}
|
||||
|
||||
internal void ToString(StringBuilder builder) {
|
||||
builder.Append(FirstPort);
|
||||
|
||||
if (LastPort != FirstPort) {
|
||||
builder.Append('-');
|
||||
builder.Append(LastPort);
|
||||
}
|
||||
}
|
||||
|
||||
internal static PortRange Parse(ReadOnlySpan<char> definition) {
|
||||
int separatorIndex = definition.IndexOf('-');
|
||||
if (separatorIndex == -1) {
|
||||
var port = ParsePort(definition.Trim());
|
||||
return new PortRange(port, port);
|
||||
}
|
||||
|
||||
var firstPort = ParsePort(definition[..separatorIndex].Trim());
|
||||
var lastPort = ParsePort(definition[(separatorIndex + 1)..].Trim());
|
||||
if (lastPort < firstPort) {
|
||||
throw new FormatException("Invalid port range '" + firstPort + "-" + lastPort + "'.");
|
||||
}
|
||||
else {
|
||||
return new PortRange(firstPort, lastPort);
|
||||
}
|
||||
}
|
||||
|
||||
private static ushort ParsePort(ReadOnlySpan<char> port) {
|
||||
try {
|
||||
return ushort.Parse(port);
|
||||
} catch (Exception) {
|
||||
throw new FormatException("Invalid port '" + port.ToString() + "'.");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a number of RAM allocation units, using the conversion factor of 256 MB per unit. Supports allocations up to 16 TB minus 256 MB (65535 units).
|
||||
/// </summary>
|
||||
[MessagePackObject]
|
||||
[MemoryPackable]
|
||||
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
|
||||
public readonly record struct RamAllocationUnits(
|
||||
[property: Key(0)] ushort RawValue
|
||||
public readonly partial record struct RamAllocationUnits(
|
||||
[property: MemoryPackOrder(0)] ushort RawValue
|
||||
) : IComparable<RamAllocationUnits> {
|
||||
[IgnoreMember]
|
||||
[MemoryPackIgnore]
|
||||
public uint InMegabytes => (uint) RawValue * MegabytesPerUnit;
|
||||
|
||||
public int CompareTo(RamAllocationUnits other) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Instance;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record ConfigureInstanceMessage(
|
||||
[property: Key(0)] uint SequenceId,
|
||||
[property: Key(1)] InstanceConfiguration Configuration
|
||||
[MemoryPackable]
|
||||
public sealed partial record ConfigureInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] uint SequenceId,
|
||||
[property: MemoryPackOrder(1)] InstanceConfiguration Configuration
|
||||
) : IMessageToAgent, IMessageWithReply {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleConfigureInstance(this);
|
||||
|
@ -1,11 +1,11 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record LaunchInstanceMessage(
|
||||
[property: Key(0)] uint SequenceId,
|
||||
[property: Key(1)] Guid InstanceGuid
|
||||
[MemoryPackable]
|
||||
public sealed partial record LaunchInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] uint SequenceId,
|
||||
[property: MemoryPackOrder(1)] Guid InstanceGuid
|
||||
) : IMessageToAgent, IMessageWithReply {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleLaunchInstance(this);
|
||||
|
@ -1,11 +1,11 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Replies;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record RegisterAgentFailureMessage(
|
||||
[property: Key(0)] RegisterAgentFailure FailureKind
|
||||
[MemoryPackable]
|
||||
public sealed partial record RegisterAgentFailureMessage(
|
||||
[property: MemoryPackOrder(0)] RegisterAgentFailure FailureKind
|
||||
) : IMessageToAgent {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleRegisterAgentFailureResult(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System.Collections.Immutable;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Instance;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record RegisterAgentSuccessMessage(
|
||||
[property: Key(0)] ImmutableArray<InstanceConfiguration> InitialInstances
|
||||
[MemoryPackable]
|
||||
public sealed partial record RegisterAgentSuccessMessage(
|
||||
[property: MemoryPackOrder(0)] ImmutableArray<InstanceConfiguration> InitialInstances
|
||||
) : IMessageToAgent {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleRegisterAgentSuccessResult(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record SendCommandToInstanceMessage(
|
||||
[property: Key(0)] uint SequenceId,
|
||||
[property: Key(1)] Guid InstanceGuid,
|
||||
[property: Key(2)] string Command
|
||||
[MemoryPackable]
|
||||
public sealed partial record SendCommandToInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] uint SequenceId,
|
||||
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(2)] string Command
|
||||
) : IMessageToAgent, IMessageWithReply {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleSendCommandToInstance(this);
|
||||
|
@ -1,13 +1,13 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Minecraft;
|
||||
|
||||
namespace Phantom.Common.Messages.ToAgent;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record StopInstanceMessage(
|
||||
[property: Key(0)] uint SequenceId,
|
||||
[property: Key(1)] Guid InstanceGuid,
|
||||
[property: Key(2)] MinecraftStopStrategy StopStrategy
|
||||
[MemoryPackable]
|
||||
public sealed partial record StopInstanceMessage(
|
||||
[property: MemoryPackOrder(0)] uint SequenceId,
|
||||
[property: MemoryPackOrder(1)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(2)] MinecraftStopStrategy StopStrategy
|
||||
) : IMessageToAgent, IMessageWithReply {
|
||||
public Task Accept(IMessageToAgentListener listener) {
|
||||
return listener.HandleStopInstance(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System.Collections.Immutable;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Java;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record AdvertiseJavaRuntimesMessage(
|
||||
[property: Key(0)] ImmutableArray<TaggedJavaRuntime> Runtimes
|
||||
[MemoryPackable]
|
||||
public sealed partial record AdvertiseJavaRuntimesMessage(
|
||||
[property: MemoryPackOrder(0)] ImmutableArray<TaggedJavaRuntime> Runtimes
|
||||
) : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleAdvertiseJavaRuntimes(this);
|
||||
|
@ -1,9 +1,9 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record AgentIsAliveMessage : IMessageToServer {
|
||||
[MemoryPackable]
|
||||
public sealed partial record AgentIsAliveMessage : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleAgentIsAlive(this);
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System.Collections.Immutable;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record InstanceOutputMessage(
|
||||
[property: Key(0)] Guid InstanceGuid,
|
||||
[property: Key(1)] ImmutableArray<string> Lines
|
||||
[MemoryPackable]
|
||||
public sealed partial record InstanceOutputMessage(
|
||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(1)] ImmutableArray<string> Lines
|
||||
) : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleInstanceOutput(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Agent;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record RegisterAgentMessage(
|
||||
[property: Key(0)] AgentAuthToken AuthToken,
|
||||
[property: Key(1)] AgentInfo AgentInfo
|
||||
[MemoryPackable]
|
||||
public sealed partial record RegisterAgentMessage(
|
||||
[property: MemoryPackOrder(0)] AgentAuthToken AuthToken,
|
||||
[property: MemoryPackOrder(1)] AgentInfo AgentInfo
|
||||
) : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleRegisterAgent(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
using Phantom.Common.Data.Instance;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record ReportInstanceStatusMessage(
|
||||
[property: Key(0)] Guid InstanceGuid,
|
||||
[property: Key(1)] InstanceStatus InstanceStatus
|
||||
[MemoryPackable]
|
||||
public sealed partial record ReportInstanceStatusMessage(
|
||||
[property: MemoryPackOrder(0)] Guid InstanceGuid,
|
||||
[property: MemoryPackOrder(1)] IInstanceStatus InstanceStatus
|
||||
) : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleReportInstanceStatus(this);
|
||||
|
@ -1,12 +1,12 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record SimpleReplyMessage(
|
||||
[property: Key(0)] uint SequenceId,
|
||||
[property: Key(1)] int EnumValue
|
||||
[MemoryPackable]
|
||||
public sealed partial record SimpleReplyMessage(
|
||||
[property: MemoryPackOrder(0)] uint SequenceId,
|
||||
[property: MemoryPackOrder(1)] int EnumValue
|
||||
) : IMessageToServer {
|
||||
public static SimpleReplyMessage FromEnum<TEnum>(uint sequenceId, TEnum enumValue) where TEnum : Enum {
|
||||
if (Unsafe.SizeOf<TEnum>() != Unsafe.SizeOf<int>()) {
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MessagePack;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Common.Messages.ToServer;
|
||||
|
||||
[MessagePackObject]
|
||||
public sealed record UnregisterAgentMessage(
|
||||
[property: Key(0)] Guid AgentGuid
|
||||
[MemoryPackable]
|
||||
public sealed partial record UnregisterAgentMessage(
|
||||
[property: MemoryPackOrder(0)] Guid AgentGuid
|
||||
) : IMessageToServer {
|
||||
public Task Accept(IMessageToServerListener listener) {
|
||||
return listener.HandleUnregisterAgent(this);
|
||||
|
@ -12,9 +12,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Update="MessagePack" Version="2.4.35" />
|
||||
<PackageReference Update="MessagePack.Annotations" Version="2.4.35" />
|
||||
<PackageReference Update="NetMQ" Version="4.0.1.10" />
|
||||
<PackageReference Update="MemoryPack" Version="1.4.1" />
|
||||
<PackageReference Update="NetMQ" Version="4.0.1.10" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -4,7 +4,7 @@ namespace Phantom.Server.Services.Instances;
|
||||
|
||||
public sealed record Instance(
|
||||
InstanceConfiguration Configuration,
|
||||
InstanceStatus Status
|
||||
IInstanceStatus Status
|
||||
) {
|
||||
internal Instance(InstanceConfiguration configuration) : this(configuration, InstanceStatus.IsOffline) {}
|
||||
internal Instance(InstanceConfiguration configuration) : this(configuration, InstanceStatus.Offline) {}
|
||||
}
|
||||
|
@ -113,11 +113,11 @@ public sealed class InstanceManager {
|
||||
return instances.ByGuid.TryGetValue(instanceGuid, out var instance) ? instance : null;
|
||||
}
|
||||
|
||||
internal void SetInstanceState(Guid instanceGuid, InstanceStatus instanceStatus) {
|
||||
internal void SetInstanceState(Guid instanceGuid, IInstanceStatus instanceStatus) {
|
||||
instances.ByGuid.TryReplace(instanceGuid, instance => instance with { Status = instanceStatus });
|
||||
}
|
||||
|
||||
internal void SetInstanceStatesForAgent(Guid agentGuid, InstanceStatus instanceStatus) {
|
||||
internal void SetInstanceStatesForAgent(Guid agentGuid, IInstanceStatus instanceStatus) {
|
||||
instances.ByGuid.ReplaceAllIf(instance => instance with { Status = instanceStatus }, instance => instance.Configuration.AgentGuid == agentGuid);
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ public sealed class MessageToServerListener : IMessageToServerListener {
|
||||
IsDisposed = true;
|
||||
|
||||
if (agentManager.UnregisterAgent(message.AgentGuid, connection)) {
|
||||
instanceManager.SetInstanceStatesForAgent(message.AgentGuid, InstanceStatus.IsOffline);
|
||||
instanceManager.SetInstanceStatesForAgent(message.AgentGuid, InstanceStatus.Offline);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
@ -1,43 +1,43 @@
|
||||
@using Phantom.Common.Data.Instance
|
||||
@switch (Status) {
|
||||
case InstanceStatus.Offline:
|
||||
case InstanceIsOffline:
|
||||
<text>Offline</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Invalid invalid:
|
||||
case InstanceIsInvalid invalid:
|
||||
<text>Invalid <sup title="@invalid.Reason">[?]</sup></text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.NotRunning:
|
||||
case InstanceIsNotRunning:
|
||||
<text>Not Running</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Downloading downloading:
|
||||
case InstanceIsDownloading downloading:
|
||||
<ProgressBar Value="@downloading.Progress" Maximum="100">
|
||||
Downloading Server (@downloading.Progress%)
|
||||
</ProgressBar>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Launching:
|
||||
case InstanceIsLaunching:
|
||||
<div class="spinner-border spinner-border-sm" role="status"></div>
|
||||
<text> Launching</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Running:
|
||||
case InstanceIsRunning:
|
||||
<text>Running</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Restarting:
|
||||
case InstanceIsRestarting:
|
||||
<div class="spinner-border spinner-border-sm" role="status"></div>
|
||||
<text> Restarting</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Stopping:
|
||||
case InstanceIsStopping:
|
||||
<div class="spinner-border spinner-border-sm" role="status"></div>
|
||||
<text> Stopping</text>
|
||||
break;
|
||||
|
||||
case InstanceStatus.Failed failed:
|
||||
case InstanceIsFailed failed:
|
||||
<text>Failed <sup title="@failed.Reason.ToSentence()">[?]</sup></text>
|
||||
break;
|
||||
}
|
||||
@ -45,6 +45,6 @@
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public InstanceStatus? Status { get; set; }
|
||||
public IInstanceStatus? Status { get; set; }
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Buffers;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Phantom.Utils.Runtime;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Phantom.Utils.Rpc.Message;
|
||||
|
||||
public sealed class MessageRegistry<TListener, TMessageBase> where TMessageBase : class, IMessage<TListener> {
|
||||
private const int DefaultBufferSize = 512;
|
||||
|
||||
private readonly ILogger logger;
|
||||
private readonly Dictionary<Type, ushort> typeToCodeMapping = new ();
|
||||
private readonly Dictionary<ushort, Type> codeToTypeMapping = new ();
|
||||
private readonly Dictionary<ushort, Func<ReadOnlyMemory<byte>, CancellationToken, TMessageBase>> codeToDeserializerMapping = new ();
|
||||
private readonly Dictionary<ushort, Func<ReadOnlyMemory<byte>, TMessageBase>> codeToDeserializerMapping = new ();
|
||||
|
||||
public MessageRegistry(ILogger logger) {
|
||||
this.logger = logger;
|
||||
@ -32,20 +36,25 @@ public sealed class MessageRegistry<TListener, TMessageBase> where TMessageBase
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Write<TMessage>(TMessage message, CancellationToken cancellationToken = default) where TMessage : TMessageBase {
|
||||
public ReadOnlySpan<byte> Write<TMessage>(TMessage message) where TMessage : TMessageBase {
|
||||
if (!typeToCodeMapping.TryGetValue(typeof(TMessage), out ushort code)) {
|
||||
logger.Error("Unknown message type {Type}.", typeof(TMessage));
|
||||
return default;
|
||||
}
|
||||
|
||||
var stream = new MemoryStream();
|
||||
var buffer = new ArrayBufferWriter<byte>(DefaultBufferSize);
|
||||
|
||||
try {
|
||||
MessageSerializer.WriteCode(stream, code);
|
||||
MessageSerializer.Serialize<TMessage, TListener>(stream, message, cancellationToken);
|
||||
return new ReadOnlySpan<byte>(stream.GetBuffer(), 0, (int) stream.Length);
|
||||
MessageSerializer.WriteCode(buffer, code);
|
||||
MessageSerializer.Serialize<TMessage, TListener>(buffer, message);
|
||||
|
||||
if (buffer.WrittenCount > DefaultBufferSize && logger.IsEnabled(LogEventLevel.Verbose)) {
|
||||
logger.Verbose("Serializing {Type} exceeded default buffer size: {WrittenSize} B > {DefaultBufferSize} B", typeof(TMessage).Name, buffer.WrittenCount, DefaultBufferSize);
|
||||
}
|
||||
|
||||
return buffer.WrittenSpan;
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Failed to serialize message {Type}.", typeof(TMessage));
|
||||
logger.Error(e, "Failed to serialize message {Type}.", typeof(TMessage).Name);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
@ -68,7 +77,7 @@ public sealed class MessageRegistry<TListener, TMessageBase> where TMessageBase
|
||||
|
||||
TMessageBase message;
|
||||
try {
|
||||
message = deserialize(memory, cancellationToken);
|
||||
message = deserialize(memory);
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Failed to deserialize message with code {Code}.", code);
|
||||
return;
|
||||
@ -78,7 +87,7 @@ public sealed class MessageRegistry<TListener, TMessageBase> where TMessageBase
|
||||
try {
|
||||
await message.Accept(listener);
|
||||
} catch (Exception e) {
|
||||
logger.Error(e, "Failed to handle message {Type}.", message.GetType());
|
||||
logger.Error(e, "Failed to handle message {Type}.", message.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,29 +1,24 @@
|
||||
using System.Buffers.Binary;
|
||||
using MessagePack;
|
||||
using MessagePack.Resolvers;
|
||||
using System.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using MemoryPack;
|
||||
|
||||
namespace Phantom.Utils.Rpc.Message;
|
||||
|
||||
static class MessageSerializer {
|
||||
private static readonly MessagePackSerializerOptions SerializerOptions =
|
||||
MessagePackSerializerOptions
|
||||
.Standard
|
||||
.WithResolver(CompositeResolver.Create(NativeGuidResolver.Instance, StandardResolver.Instance))
|
||||
.WithCompression(MessagePackCompression.None)
|
||||
.WithSecurity(MessagePackSecurity.UntrustedData.WithMaximumObjectGraphDepth(10));
|
||||
private static readonly MemoryPackSerializeOptions SerializerOptions = MemoryPackSerializeOptions.Utf8;
|
||||
|
||||
public static void Serialize<TMessage, TListener>(Stream stream, TMessage message, CancellationToken cancellationToken) where TMessage : IMessage<TListener> {
|
||||
MessagePackSerializer.Serialize(stream, message, SerializerOptions, cancellationToken);
|
||||
public static void Serialize<TMessage, TListener>(IBufferWriter<byte> destination, TMessage message) where TMessage : IMessage<TListener> {
|
||||
MemoryPackSerializer.Serialize(typeof(TMessage), destination, message, SerializerOptions);
|
||||
}
|
||||
|
||||
public static Func<ReadOnlyMemory<byte>, CancellationToken, TMessageBase> Deserialize<TMessage, TMessageBase, TListener>() where TMessageBase : IMessage<TListener> where TMessage : TMessageBase {
|
||||
return static (memory, cancellationToken) => MessagePackSerializer.Deserialize<TMessage>(memory, SerializerOptions, cancellationToken);
|
||||
public static Func<ReadOnlyMemory<byte>, TMessageBase> Deserialize<TMessage, TMessageBase, TListener>() where TMessageBase : IMessage<TListener> where TMessage : TMessageBase {
|
||||
return static memory => MemoryPackSerializer.Deserialize<TMessage>(memory.Span) ?? throw new NullReferenceException();
|
||||
}
|
||||
|
||||
public static void WriteCode(Stream stream, ushort value) {
|
||||
public static void WriteCode(IBufferWriter<byte> destination, ushort value) {
|
||||
Span<byte> buffer = stackalloc byte[2];
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(buffer, value);
|
||||
stream.Write(buffer);
|
||||
destination.Write(buffer);
|
||||
}
|
||||
|
||||
public static ushort ReadCode(ref ReadOnlyMemory<byte> memory) {
|
||||
|
@ -7,7 +7,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MessagePack" />
|
||||
<PackageReference Include="MemoryPack" />
|
||||
<PackageReference Include="NetMQ" />
|
||||
<PackageReference Include="Serilog" />
|
||||
</ItemGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user