новые модули для новой архитектуры

This commit is contained in:
2025-02-17 12:46:40 +03:00
parent 5c643dd2c9
commit 327822d48c
13 changed files with 300 additions and 304 deletions
+12
View File
@@ -0,0 +1,12 @@
namespace mROA.Abstract;
public delegate void ConnectionHandler(INextGenerationInteractionModule interactionModule);
public delegate void DisconnectionHandler(INextGenerationInteractionModule interactionModule);
public interface IConnectionHub
{
void RegisterInteracion(INextGenerationInteractionModule interaction);
INextGenerationInteractionModule GetInteracion(int id);
event ConnectionHandler? OnConnectied;
event DisconnectionHandler? OnDisconnected;
}
+6
View File
@@ -0,0 +1,6 @@
namespace mROA.Abstract;
public interface IIdentityGenerator
{
int GetNextIdentity();
}
@@ -0,0 +1,13 @@
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class BackendIdentityGenerator : IIdentityGenerator
{
private int _currentId;
public int GetNextIdentity()
{
return ++_currentId;
}
}
@@ -0,0 +1,21 @@
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class ConntectionHub : IConnectionHub
{
private Dictionary<int, INextGenerationInteractionModule> _connections = new();
public void RegisterInteracion(INextGenerationInteractionModule interaction)
{
OnConnectied?.Invoke(interaction);
}
public INextGenerationInteractionModule GetInteracion(int id)
{
}
public event ConnectionHandler? OnConnectied;
public event DisconnectionHandler? OnDisconnected;
}
@@ -4,11 +4,22 @@ using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule
public class NetworkGatewayModule() : IGatewayModule
{
private readonly TcpListener _tcpListener = new(endpoint);
private IInteractionModule? _interactionModule;
private readonly IPEndPoint? _endpoint;
private readonly Type? _interactionModuleType;
private readonly IInjectableModule[]? _injectableModules;
private readonly TcpListener? _tcpListener;
private IConnectionHub? _hub;
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules)
{
_endpoint = endpoint;
_tcpListener = new(_endpoint);
_interactionModuleType = interactionModuleType;
_injectableModules = injectableModules;
}
public void Run()
{
@@ -26,8 +37,6 @@ public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule
}
Console.WriteLine("Stopping");
}
public void Dispose()
@@ -38,22 +47,33 @@ public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule
private void HandleIncomingConnections()
{
if (_interactionModule is null)
throw new NullReferenceException("Interaction module is null");
if (_hub is null)
throw new NullReferenceException("Hub module is null");
if (_tcpListener == null)
throw new NullReferenceException("TcpListener is null");
if (_injectableModules is null)
throw new NullReferenceException("InjectableModules is null");
if (_interactionModuleType is null)
throw new NullReferenceException("InteractionModuleType is null");
while (true)
{
var client = _tcpListener.AcceptTcpClient();
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
_interactionModule.RegisterSource(client.GetStream());
var interacton = Activator.CreateInstance(_interactionModuleType) as INextGenerationInteractionModule;
foreach (var injectableModule in _injectableModules)
interacton.Inject(injectableModule);
_hub.RegisterInteracion(new NextGenerationInteractionModule());
Console.WriteLine("Client registered");
}
}
public void Inject<T>(T dependency)
{
if (dependency is IInteractionModule interactionModule)
_interactionModule = interactionModule;
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule;
}
}
@@ -1,66 +1,66 @@
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class StreamBasedInteractionModule : IInteractionModule
{
internal ISerialisationModule _serialisationModule;
private readonly Dictionary<int, Stream> _streams = new();
internal Action<int, byte[]>? _handler;
public void RegisterSource(Stream stream)
{
var id = Random.Shared.Next();
_streams.Add(id, stream);
_ = ListenTo((id, stream), _handler!);
_serialisationModule.SendWelcomeMessage(id);
}
public Stream GetSource(int clientId)
{
return _streams.GetValueOrDefault(clientId, Stream.Null);
}
public void SendTo(int clientId, byte[] message)
{
if (!_streams.TryGetValue(clientId, out var stream))
{
throw new KeyNotFoundException($"Client {clientId} not found");
}
stream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
stream.Write(message, 0, message.Length);
}
private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action)
{
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
const int bufferSize = ushort.MaxValue;
try
{
byte[] buffer = new byte[bufferSize];
while (client.stream.CanRead)
{
await client.stream.ReadExactlyAsync(buffer, 0, 2);
var len = BitConverter.ToUInt16(buffer, 0);
await client.stream.ReadExactlyAsync(buffer, 0, len);
_ = Task.Run(() => action(client.id, buffer[..len]));
}
}
catch (Exception)
{
Console.WriteLine($"Client handling finished:{client.id}");
_streams.Remove(client.id);
}
}
public void Inject<T>(T dependency)
{
if (dependency is ISerialisationModule serialisationModule)
{
_handler = serialisationModule.HandleIncomingRequest;
_serialisationModule = serialisationModule;
}
}
}
// using mROA.Abstract;
//
// namespace mROA.Implementation.Backend;
//
// public class StreamBasedInteractionModule : IInteractionModule
// {
// internal ISerialisationModule _serialisationModule;
// private readonly Dictionary<int, Stream> _streams = new();
// internal Action<int, byte[]>? _handler;
//
// public void RegisterSource(Stream stream)
// {
// var id = Random.Shared.Next();
// _streams.Add(id, stream);
// _ = ListenTo((id, stream), _handler!);
// _serialisationModule.SendWelcomeMessage(id);
// }
//
// public Stream GetSource(int clientId)
// {
// return _streams.GetValueOrDefault(clientId, Stream.Null);
// }
//
// public void SendTo(int clientId, byte[] message)
// {
// if (!_streams.TryGetValue(clientId, out var stream))
// {
// throw new KeyNotFoundException($"Client {clientId} not found");
// }
//
// stream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
// stream.Write(message, 0, message.Length);
// }
//
// private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action)
// {
// TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
// const int bufferSize = ushort.MaxValue;
// try
// {
// byte[] buffer = new byte[bufferSize];
// while (client.stream.CanRead)
// {
// await client.stream.ReadExactlyAsync(buffer, 0, 2);
// var len = BitConverter.ToUInt16(buffer, 0);
// await client.stream.ReadExactlyAsync(buffer, 0, len);
// _ = Task.Run(() => action(client.id, buffer[..len]));
// }
// }
// catch (Exception)
// {
// Console.WriteLine($"Client handling finished:{client.id}");
// _streams.Remove(client.id);
// }
// }
//
// public void Inject<T>(T dependency)
// {
// if (dependency is ISerialisationModule serialisationModule)
// {
// _handler = serialisationModule.HandleIncomingRequest;
// _serialisationModule = serialisationModule;
// }
// }
//
// }
@@ -10,7 +10,7 @@ public class CreativeSerializationModuleProducer : ISerialisationModuleProducer
private IInjectableModule[] _creationModules;
private StreamBasedInteractionModule? _interactionModule;
public CreativeSerializationModuleProducer(IInjectableModule[] creationModules, Type serializationModuleType)
public CreativeSerializationModuleProducer(IInjectableModule[] creationModules, Type serializationModuleType)а
{
_creationModules = creationModules;
_serializationModuleType = serializationModuleType;
@@ -1,29 +0,0 @@
using mROA.Abstract;
namespace mROA.Implementation.Frontend;
public class JsonFrontendCallbackSerializationModule : ISerialisationModule
{
private IInteractionModule.IFrontendInteractionModule? _interactionModule;
public void Inject<T>(T dependency)
{
if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule)
_interactionModule = interactionModule;
}
public void HandleIncomingRequest(int clientId, byte[] message)
{
}
public void PostResponse(NetworkMessage message, int clientId)
{
throw new NotImplementedException();
}
public void SendWelcomeMessage(int clientId)
{
throw new NotImplementedException();
}
}
@@ -4,82 +4,82 @@ using mROA.Abstract;
namespace mROA.Implementation.Frontend;
public class JsonFrontendSerialisationModule
: ISerialisationModule.IFrontendSerialisationModule
{
private IInteractionModule.IFrontendInteractionModule? _interactionModule;
public int ClientId => _interactionModule!.ClientId;
public async Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution
{
if (_interactionModule is null)
throw new Exception("Interaction module not initialized");
var receiveMessage = await _interactionModule.ReceiveMessage();
var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
while (message.Id != requestId)
{
receiveMessage = await _interactionModule.ReceiveMessage();
message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
}
var parsed = JsonSerializer.Deserialize<T>(message.Data)!;
if (message.SchemaId == MessageType.ErrorCommandExecution)
{
throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
{ CallRequestId = requestId };
}
return parsed;
}
public async Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId)
{
if (_interactionModule is null)
throw new Exception("Interaction module not initialized");
var receiveMessage = await _interactionModule.ReceiveMessage();
var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
while (message.Id != requestId)
{
receiveMessage = await _interactionModule.ReceiveMessage();
message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
}
if (message.SchemaId == MessageType.ErrorCommandExecution)
{
throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
{ CallRequestId = requestId };
}
return JsonSerializer.Deserialize<FinalCommandExecution<T>>(message.Data)!;
}
public void PostCallRequest(ICallRequest callRequest)
{
if (_interactionModule is null)
throw new Exception("Interaction module not initialized");
var post = JsonSerializer.SerializeToUtf8Bytes(callRequest, callRequest.GetType());
_interactionModule.PostMessage(JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage
{
Id = callRequest.CallRequestId,
Data = post,
SchemaId = MessageType.CallRequest
}));
}
public void Inject<T>(T dependency)
{
if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule)
_interactionModule = interactionModule;
}
}
// public class JsonFrontendSerialisationModule
// : ISerialisationModule.IFrontendSerialisationModule
// {
// private IInteractionModule.IFrontendInteractionModule? _interactionModule;
// public int ClientId => _interactionModule!.ClientId;
//
// public async Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution
// {
// if (_interactionModule is null)
// throw new Exception("Interaction module not initialized");
//
// var receiveMessage = await _interactionModule.ReceiveMessage();
// var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
//
// while (message.Id != requestId)
// {
// receiveMessage = await _interactionModule.ReceiveMessage();
// message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
// }
//
// var parsed = JsonSerializer.Deserialize<T>(message.Data)!;
//
// if (message.SchemaId == MessageType.ErrorCommandExecution)
// {
// throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
// { CallRequestId = requestId };
// }
//
// return parsed;
// }
//
// public async Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId)
// {
// if (_interactionModule is null)
// throw new Exception("Interaction module not initialized");
//
// var receiveMessage = await _interactionModule.ReceiveMessage();
//
// var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
// while (message.Id != requestId)
// {
// receiveMessage = await _interactionModule.ReceiveMessage();
//
// message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
// }
//
// if (message.SchemaId == MessageType.ErrorCommandExecution)
// {
// throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
// { CallRequestId = requestId };
// }
//
// return JsonSerializer.Deserialize<FinalCommandExecution<T>>(message.Data)!;
// }
//
// public void PostCallRequest(ICallRequest callRequest)
// {
// if (_interactionModule is null)
// throw new Exception("Interaction module not initialized");
//
//
// var post = JsonSerializer.SerializeToUtf8Bytes(callRequest, callRequest.GetType());
// _interactionModule.PostMessage(JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage
// {
// Id = callRequest.CallRequestId,
// Data = post,
// SchemaId = MessageType.CallRequest
// }));
// }
//
// public void Inject<T>(T dependency)
// {
// if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule)
// _interactionModule = interactionModule;
// }
// }
public class RemoteException(string error) : Exception
{
@@ -9,13 +9,19 @@ namespace mROA.Implementation.Frontend;
public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
{
private readonly TcpClient _tcpClient = new();
private StreamBasedFrontendInteractionModule? _interactionModule;
private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
public void Inject<T>(T dependency)
{
if (dependency is StreamBasedFrontendInteractionModule interactionModule)
switch (dependency)
{
_interactionModule = interactionModule;
case NextGenerationInteractionModule interactionModule:
_interactionModule = interactionModule;
break;
case ISerializationToolkit toolkit:
_serialization = toolkit;
break;
}
}
@@ -25,14 +31,13 @@ public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
throw new Exception("Interaction module was not injected");
_tcpClient.Connect(ipEndPoint);
_interactionModule.ServerStream = _tcpClient.GetStream();
var welcomeMessage = _interactionModule.ReceiveMessage().GetAwaiter().GetResult();
var message = JsonSerializer.Deserialize<NetworkMessage>(welcomeMessage);
if (message.SchemaId != MessageType.IdAssigning)
_interactionModule.BaseStream = _tcpClient.GetStream();
var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
if (welcomeMessage.SchemaId != MessageType.IdAssigning)
{
throw new Exception($"Incorrect message type. Must be IdAssigning, current : {message.SchemaId.ToString()}");
throw new Exception($"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.SchemaId.ToString()}");
}
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(JsonSerializer.Deserialize<IdAssingnment>(message.Data)!.Id);
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize<IdAssingnment>(welcomeMessage.Data)!.Id);
}
}
@@ -2,50 +2,50 @@ using mROA.Abstract;
namespace mROA.Implementation.Frontend;
public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontendInteractionModule
{
public Stream? ServerStream { get; set; }
public int ClientId { get; set; }
public NetworkMessage[] UnhandledMessages()
{
return Array.Empty<NetworkMessage>();
}
public NetworkMessage LastMessage()
{
return null;
}
public async Task<byte[]> ReceiveMessage()
{
if (ServerStream is null)
throw new IOException("Server is not connected.");
const int bufferSize = ushort.MaxValue;
var buffer = new byte[bufferSize];
if (!ServerStream.CanRead) throw new IOException("Server is not connected.");
await ServerStream.ReadExactlyAsync(buffer, 0, 2);
var len = BitConverter.ToUInt16(buffer, 0);
await ServerStream.ReadExactlyAsync(buffer, 0, len);
return buffer[..len];
}
public void PostMessage(byte[] message)
{
if (ServerStream is null)
throw new IOException("Server is not connected.");
ServerStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
ServerStream.Write(message, 0, message.Length);
}
public void Inject<T>(T dependency)
{
}
}
// public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontendInteractionModule
// {
// public Stream? ServerStream { get; set; }
// public int ClientId { get; set; }
//
// public NetworkMessage[] UnhandledMessages()
// {
// return Array.Empty<NetworkMessage>();
// }
//
// public NetworkMessage LastMessage()
// {
// return null;
// }
//
//
//
// public async Task<byte[]> ReceiveMessage()
// {
// if (ServerStream is null)
// throw new IOException("Server is not connected.");
//
// const int bufferSize = ushort.MaxValue;
//
// var buffer = new byte[bufferSize];
// if (!ServerStream.CanRead) throw new IOException("Server is not connected.");
//
// await ServerStream.ReadExactlyAsync(buffer, 0, 2);
// var len = BitConverter.ToUInt16(buffer, 0);
// await ServerStream.ReadExactlyAsync(buffer, 0, len);
//
// return buffer[..len];
// }
//
// public void PostMessage(byte[] message)
// {
// if (ServerStream is null)
// throw new IOException("Server is not connected.");
//
// ServerStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
// ServerStream.Write(message, 0, message.Length);
// }
//
// public void Inject<T>(T dependency)
// {
// }
// }
@@ -1,60 +0,0 @@
using mROA.Abstract;
using mROA.Implementation.Backend;
namespace mROA.Implementation.Frontend;
public class StreamBasedVirtualBackendInteractionModule : StreamBasedInteractionModule, IInteractionModule
{
private Stream? _serverStream { get; set; }
private StreamBasedFrontendInteractionModule? _interactionModule;
public void RegisterSource(Stream stream)
{
}
public Stream GetSource(int clientId)
{
return _serverStream;
}
public void SendTo(int clientId, byte[] message)
{
_serverStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
_serverStream.Write(message, 0, message.Length);
}
private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action)
{
const int bufferSize = ushort.MaxValue;
try
{
byte[] buffer = new byte[bufferSize];
while (client.stream.CanRead)
{
await client.stream.ReadExactlyAsync(buffer, 0, 2);
var len = BitConverter.ToUInt16(buffer, 0);
await client.stream.ReadExactlyAsync(buffer, 0, len);
_ = Task.Run(() => action(client.id, buffer[..len]));
}
}
catch (Exception)
{
}
}
public void Inject<T>(T dependency)
{
base.Inject(dependency);
if (dependency is StreamBasedFrontendInteractionModule interactionModule)
{
_interactionModule = interactionModule;
}
}
public void StartVirtualInteraction()
{
_serverStream = _interactionModule.ServerStream;
_ = ListenTo((0, _serverStream), _handler!);
}
}
@@ -1,11 +1,12 @@
using mROA.Abstract;
using System.Security.Cryptography;
using mROA.Abstract;
namespace mROA.Implementation;
public class NextGenerationInteractionModule : INextGenerationInteractionModule
{
private ISerializationToolkit? _serialization;
public int ConntectionId { get; set; }
public int ConntectionId { get; private set; }
public Stream? BaseStream { get; set; }
private Task<NetworkMessage>? _currentReceiving;
private const int BufferSize = ushort.MaxValue;
@@ -13,8 +14,15 @@ public class NextGenerationInteractionModule : INextGenerationInteractionModule
public void Inject<T>(T dependency)
{
if (dependency is ISerializationToolkit toolkit)
_serialization = toolkit;
switch (dependency)
{
case ISerializationToolkit toolkit:
_serialization = toolkit;
break;
case IIdentityGenerator identityGenerator:
ConntectionId = identityGenerator.GetNextIdentity();
break;
}
}