mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-09-30 23:02:48 +02:00
78 lines
3.1 KiB
C#
78 lines
3.1 KiB
C#
using System.Collections.Immutable;
|
|
using Phantom.Common.Data.Agent;
|
|
using Phantom.Common.Messages.Agent.Handshake;
|
|
using Phantom.Common.Messages.Agent.ToAgent;
|
|
using Phantom.Controller.Services.Agents;
|
|
using Phantom.Utils.Monads;
|
|
using Phantom.Utils.Rpc.Message;
|
|
using Phantom.Utils.Rpc.Runtime;
|
|
using Phantom.Utils.Rpc.Runtime.Server;
|
|
|
|
namespace Phantom.Controller.Services.Rpc;
|
|
|
|
public sealed class AgentClientHandshake : IRpcServerClientHandshake<AgentInfo> {
|
|
private const int MaxRegistrationBytes = 1024 * 1024 * 8;
|
|
|
|
private readonly AgentManager agentManager;
|
|
|
|
internal AgentClientHandshake(AgentManager agentManager) {
|
|
this.agentManager = agentManager;
|
|
}
|
|
|
|
public async Task<Either<AgentInfo, Exception>> Perform(bool isNewSession, RpcStream stream, CancellationToken cancellationToken) {
|
|
RegistrationResult registrationResult;
|
|
switch (await RegisterAgent(stream, cancellationToken)) {
|
|
case Left<RegistrationResult, Exception>(var result):
|
|
await stream.WriteByte(value: 1, cancellationToken);
|
|
registrationResult = result;
|
|
break;
|
|
|
|
case Right<RegistrationResult, Exception>(var exception):
|
|
await stream.WriteByte(value: 0, cancellationToken);
|
|
return Either.Right(exception);
|
|
|
|
default:
|
|
await stream.WriteByte(value: 0, cancellationToken);
|
|
return Either.Right<Exception>(new InvalidOperationException("Invalid result type."));
|
|
}
|
|
|
|
if (isNewSession) {
|
|
await stream.WriteUnsignedInt((uint) registrationResult.ConfigureInstanceMessages.Length, cancellationToken);
|
|
|
|
foreach (var configureInstanceMessage in registrationResult.ConfigureInstanceMessages) {
|
|
ReadOnlyMemory<byte> serializedMessage = MessageSerialization.Serialize(configureInstanceMessage);
|
|
await stream.WriteSignedInt(serializedMessage.Length, cancellationToken);
|
|
await stream.WriteBytes(serializedMessage, cancellationToken);
|
|
}
|
|
}
|
|
else {
|
|
await stream.WriteUnsignedInt(value: 0, cancellationToken);
|
|
}
|
|
|
|
await stream.Flush(cancellationToken);
|
|
|
|
return Either.Left(registrationResult.AgentInfo);
|
|
}
|
|
|
|
private async Task<Either<RegistrationResult, Exception>> RegisterAgent(RpcStream stream, CancellationToken cancellationToken) {
|
|
int serializedRegistrationLength = await stream.ReadSignedInt(cancellationToken);
|
|
if (serializedRegistrationLength is < 0 or > MaxRegistrationBytes) {
|
|
return Either.Right<Exception>(new InvalidOperationException("Registration must be between 0 and " + MaxRegistrationBytes + " bytes."));
|
|
}
|
|
|
|
var serializedRegistration = await stream.ReadBytes(serializedRegistrationLength, cancellationToken);
|
|
|
|
AgentRegistration registration;
|
|
try {
|
|
registration = MessageSerialization.Deserialize<AgentRegistration>(serializedRegistration);
|
|
} catch (Exception e) {
|
|
return Either.Right<Exception>(new InvalidOperationException("Caught exception during deserialization.", e));
|
|
}
|
|
|
|
var configureInstanceMessages = await agentManager.RegisterAgent(registration);
|
|
return Either.Left(new RegistrationResult(registration.AgentInfo, configureInstanceMessages));
|
|
}
|
|
|
|
private readonly record struct RegistrationResult(AgentInfo AgentInfo, ImmutableArray<ConfigureInstanceMessage> ConfigureInstanceMessages);
|
|
}
|