mirror of
https://github.com/chylex/Minecraft-Phantom-Panel.git
synced 2025-08-16 21:31:45 +02:00
.config
.run
.workdir
Agent
Common
Controller
Phantom.Controller
Phantom.Controller.Database
Phantom.Controller.Database.Postgres
Phantom.Controller.Minecraft
Phantom.Controller.Rpc
Phantom.Controller.Rpc.csproj
RpcClientConnectionClosedEventArgs.cs
RpcConnectionToClient.cs
RpcRuntime.cs
Phantom.Controller.Services
Docker
Utils
Web
.dockerignore
.gitattributes
.gitignore
AddMigration.bat
AddMigration.sh
Directory.Build.props
Directory.Build.targets
Dockerfile
LICENSE
Packages.props
PhantomPanel.sln
README.md
global.json
113 lines
5.2 KiB
C#
113 lines
5.2 KiB
C#
using NetMQ.Sockets;
|
|
using Phantom.Utils.Rpc;
|
|
using Phantom.Utils.Rpc.Message;
|
|
using Phantom.Utils.Rpc.Sockets;
|
|
using Phantom.Utils.Tasks;
|
|
using Serilog;
|
|
using Serilog.Events;
|
|
|
|
namespace Phantom.Controller.Rpc;
|
|
|
|
public static class RpcRuntime {
|
|
public static Task Launch<TClientListener, TServerListener, TReplyMessage>(RpcConfiguration config, IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions, Func<RpcConnectionToClient<TClientListener>, TServerListener> listenerFactory, CancellationToken cancellationToken) where TReplyMessage : IMessage<TClientListener, NoReply>, IMessage<TServerListener, NoReply> {
|
|
return RpcRuntime<TClientListener, TServerListener, TReplyMessage>.Launch(config, messageDefinitions, listenerFactory, cancellationToken);
|
|
}
|
|
}
|
|
|
|
internal sealed class RpcRuntime<TClientListener, TServerListener, TReplyMessage> : RpcRuntime<ServerSocket> where TReplyMessage : IMessage<TClientListener, NoReply>, IMessage<TServerListener, NoReply> {
|
|
internal static Task Launch(RpcConfiguration config, IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions, Func<RpcConnectionToClient<TClientListener>, TServerListener> listenerFactory, CancellationToken cancellationToken) {
|
|
var socket = RpcServerSocket.Connect(config);
|
|
return new RpcRuntime<TClientListener, TServerListener, TReplyMessage>(socket, messageDefinitions, listenerFactory, cancellationToken).Launch();
|
|
}
|
|
|
|
private readonly IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions;
|
|
private readonly Func<RpcConnectionToClient<TClientListener>, TServerListener> listenerFactory;
|
|
private readonly CancellationToken cancellationToken;
|
|
|
|
private RpcRuntime(RpcServerSocket socket, IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions, Func<RpcConnectionToClient<TClientListener>, TServerListener> listenerFactory, CancellationToken cancellationToken) : base(socket) {
|
|
this.messageDefinitions = messageDefinitions;
|
|
this.listenerFactory = listenerFactory;
|
|
this.cancellationToken = cancellationToken;
|
|
}
|
|
|
|
protected override void Run(ServerSocket socket, ILogger logger, MessageReplyTracker replyTracker, TaskManager taskManager) {
|
|
var clients = new Dictionary<ulong, Client>();
|
|
|
|
void OnConnectionClosed(object? sender, RpcClientConnectionClosedEventArgs e) {
|
|
clients.Remove(e.RoutingId);
|
|
logger.Debug("Closed connection to {RoutingId}.", e.RoutingId);
|
|
}
|
|
|
|
while (!cancellationToken.IsCancellationRequested) {
|
|
var (routingId, data) = socket.Receive(cancellationToken);
|
|
|
|
if (data.Length == 0) {
|
|
LogMessageType(logger, routingId, data, messageType: null);
|
|
continue;
|
|
}
|
|
|
|
Type? messageType = messageDefinitions.ToServer.TryGetType(data, out var type) ? type : null;
|
|
|
|
if (!clients.TryGetValue(routingId, out var client)) {
|
|
if (!CheckIsRegistrationMessage(messageType, logger, routingId)) {
|
|
continue;
|
|
}
|
|
|
|
var connection = new RpcConnectionToClient<TClientListener>(socket, routingId, messageDefinitions.ToClient, replyTracker);
|
|
connection.Closed += OnConnectionClosed;
|
|
|
|
client = new Client(connection, messageDefinitions, listenerFactory(connection), logger, taskManager, cancellationToken);
|
|
clients[routingId] = client;
|
|
}
|
|
|
|
if (!client.Connection.IsAuthorized && !CheckIsRegistrationMessage(messageType, logger, routingId)) {
|
|
continue;
|
|
}
|
|
|
|
LogMessageType(logger, routingId, data, messageType);
|
|
messageDefinitions.ToServer.Handle(data, client);
|
|
}
|
|
|
|
foreach (var client in clients.Values) {
|
|
client.Connection.Closed -= OnConnectionClosed;
|
|
}
|
|
}
|
|
|
|
private void LogMessageType(ILogger logger, uint routingId, ReadOnlyMemory<byte> data, Type? messageType) {
|
|
if (!logger.IsEnabled(LogEventLevel.Verbose)) {
|
|
return;
|
|
}
|
|
|
|
if (data.Length > 0 && messageType != null) {
|
|
logger.Verbose("Received {MessageType} ({Bytes} B) from {RoutingId}.", messageType.Name, data.Length, routingId);
|
|
}
|
|
else {
|
|
logger.Verbose("Received {Bytes} B message from {RoutingId}.", data.Length, routingId);
|
|
}
|
|
}
|
|
|
|
private bool CheckIsRegistrationMessage(Type? messageType, ILogger logger, uint routingId) {
|
|
if (messageType != null && messageDefinitions.IsRegistrationMessage(messageType)) {
|
|
return true;
|
|
}
|
|
|
|
logger.Warning("Received {MessageType} from {RoutingId} who is not registered.", messageType?.Name ?? "unknown message", routingId);
|
|
return false;
|
|
}
|
|
|
|
private sealed class Client : MessageHandler<TServerListener> {
|
|
public RpcConnectionToClient<TClientListener> Connection { get; }
|
|
|
|
private readonly IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions;
|
|
|
|
public Client(RpcConnectionToClient<TClientListener> connection, IMessageDefinitions<TClientListener, TServerListener, TReplyMessage> messageDefinitions, TServerListener listener, ILogger logger, TaskManager taskManager, CancellationToken cancellationToken) : base(listener, logger, taskManager, cancellationToken) {
|
|
this.Connection = connection;
|
|
this.messageDefinitions = messageDefinitions;
|
|
}
|
|
|
|
protected override Task SendReply(uint sequenceId, byte[] serializedReply) {
|
|
return Connection.Send(messageDefinitions.CreateReplyMessage(sequenceId, serializedReply));
|
|
}
|
|
}
|
|
}
|