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

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; namespace mROA.Implementation.Backend;
public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule public class NetworkGatewayModule() : IGatewayModule
{ {
private readonly TcpListener _tcpListener = new(endpoint); private readonly IPEndPoint? _endpoint;
private IInteractionModule? _interactionModule; 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() public void Run()
{ {
@@ -26,8 +37,6 @@ public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule
} }
Console.WriteLine("Stopping"); Console.WriteLine("Stopping");
} }
public void Dispose() public void Dispose()
@@ -38,22 +47,33 @@ public class NetworkGatewayModule(IPEndPoint endpoint) : IGatewayModule
private void HandleIncomingConnections() private void HandleIncomingConnections()
{ {
if (_interactionModule is null) if (_hub is null)
throw new NullReferenceException("Interaction module 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) while (true)
{ {
var client = _tcpListener.AcceptTcpClient(); var client = _tcpListener.AcceptTcpClient();
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); 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"); Console.WriteLine("Client registered");
} }
} }
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is IInteractionModule interactionModule) if (dependency is IConnectionHub interactionModule)
_interactionModule = interactionModule; _hub = interactionModule;
} }
} }
@@ -1,66 +1,66 @@
using mROA.Abstract; // using mROA.Abstract;
//
namespace mROA.Implementation.Backend; // namespace mROA.Implementation.Backend;
//
public class StreamBasedInteractionModule : IInteractionModule // public class StreamBasedInteractionModule : IInteractionModule
{ // {
internal ISerialisationModule _serialisationModule; // internal ISerialisationModule _serialisationModule;
private readonly Dictionary<int, Stream> _streams = new(); // private readonly Dictionary<int, Stream> _streams = new();
internal Action<int, byte[]>? _handler; // internal Action<int, byte[]>? _handler;
//
public void RegisterSource(Stream stream) // public void RegisterSource(Stream stream)
{ // {
var id = Random.Shared.Next(); // var id = Random.Shared.Next();
_streams.Add(id, stream); // _streams.Add(id, stream);
_ = ListenTo((id, stream), _handler!); // _ = ListenTo((id, stream), _handler!);
_serialisationModule.SendWelcomeMessage(id); // _serialisationModule.SendWelcomeMessage(id);
} // }
//
public Stream GetSource(int clientId) // public Stream GetSource(int clientId)
{ // {
return _streams.GetValueOrDefault(clientId, Stream.Null); // return _streams.GetValueOrDefault(clientId, Stream.Null);
} // }
//
public void SendTo(int clientId, byte[] message) // public void SendTo(int clientId, byte[] message)
{ // {
if (!_streams.TryGetValue(clientId, out var stream)) // if (!_streams.TryGetValue(clientId, out var stream))
{ // {
throw new KeyNotFoundException($"Client {clientId} not found"); // throw new KeyNotFoundException($"Client {clientId} not found");
} // }
//
stream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort)); // stream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
stream.Write(message, 0, message.Length); // stream.Write(message, 0, message.Length);
} // }
//
private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action) // private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action)
{ // {
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository(); // TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
const int bufferSize = ushort.MaxValue; // const int bufferSize = ushort.MaxValue;
try // try
{ // {
byte[] buffer = new byte[bufferSize]; // byte[] buffer = new byte[bufferSize];
while (client.stream.CanRead) // while (client.stream.CanRead)
{ // {
await client.stream.ReadExactlyAsync(buffer, 0, 2); // await client.stream.ReadExactlyAsync(buffer, 0, 2);
var len = BitConverter.ToUInt16(buffer, 0); // var len = BitConverter.ToUInt16(buffer, 0);
await client.stream.ReadExactlyAsync(buffer, 0, len); // await client.stream.ReadExactlyAsync(buffer, 0, len);
_ = Task.Run(() => action(client.id, buffer[..len])); // _ = Task.Run(() => action(client.id, buffer[..len]));
} // }
} // }
catch (Exception) // catch (Exception)
{ // {
Console.WriteLine($"Client handling finished:{client.id}"); // Console.WriteLine($"Client handling finished:{client.id}");
_streams.Remove(client.id); // _streams.Remove(client.id);
} // }
} // }
//
public void Inject<T>(T dependency) // public void Inject<T>(T dependency)
{ // {
if (dependency is ISerialisationModule serialisationModule) // if (dependency is ISerialisationModule serialisationModule)
{ // {
_handler = serialisationModule.HandleIncomingRequest; // _handler = serialisationModule.HandleIncomingRequest;
_serialisationModule = serialisationModule; // _serialisationModule = serialisationModule;
} // }
} // }
//
} // }
@@ -10,7 +10,7 @@ public class CreativeSerializationModuleProducer : ISerialisationModuleProducer
private IInjectableModule[] _creationModules; private IInjectableModule[] _creationModules;
private StreamBasedInteractionModule? _interactionModule; private StreamBasedInteractionModule? _interactionModule;
public CreativeSerializationModuleProducer(IInjectableModule[] creationModules, Type serializationModuleType) public CreativeSerializationModuleProducer(IInjectableModule[] creationModules, Type serializationModuleType)а
{ {
_creationModules = creationModules; _creationModules = creationModules;
_serializationModuleType = serializationModuleType; _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; namespace mROA.Implementation.Frontend;
public class JsonFrontendSerialisationModule // public class JsonFrontendSerialisationModule
: ISerialisationModule.IFrontendSerialisationModule // : ISerialisationModule.IFrontendSerialisationModule
{ // {
private IInteractionModule.IFrontendInteractionModule? _interactionModule; // private IInteractionModule.IFrontendInteractionModule? _interactionModule;
public int ClientId => _interactionModule!.ClientId; // public int ClientId => _interactionModule!.ClientId;
//
public async Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution // public async Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution
{ // {
if (_interactionModule is null) // if (_interactionModule is null)
throw new Exception("Interaction module not initialized"); // throw new Exception("Interaction module not initialized");
//
var receiveMessage = await _interactionModule.ReceiveMessage(); // var receiveMessage = await _interactionModule.ReceiveMessage();
var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!; // var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
//
while (message.Id != requestId) // while (message.Id != requestId)
{ // {
receiveMessage = await _interactionModule.ReceiveMessage(); // receiveMessage = await _interactionModule.ReceiveMessage();
message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!; // message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
} // }
//
var parsed = JsonSerializer.Deserialize<T>(message.Data)!; // var parsed = JsonSerializer.Deserialize<T>(message.Data)!;
//
if (message.SchemaId == MessageType.ErrorCommandExecution) // if (message.SchemaId == MessageType.ErrorCommandExecution)
{ // {
throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception) // throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
{ CallRequestId = requestId }; // { CallRequestId = requestId };
} // }
//
return parsed; // return parsed;
} // }
//
public async Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId) // public async Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId)
{ // {
if (_interactionModule is null) // if (_interactionModule is null)
throw new Exception("Interaction module not initialized"); // throw new Exception("Interaction module not initialized");
//
var receiveMessage = await _interactionModule.ReceiveMessage(); // var receiveMessage = await _interactionModule.ReceiveMessage();
//
var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!; // var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
while (message.Id != requestId) // while (message.Id != requestId)
{ // {
receiveMessage = await _interactionModule.ReceiveMessage(); // receiveMessage = await _interactionModule.ReceiveMessage();
//
message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!; // message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
} // }
//
if (message.SchemaId == MessageType.ErrorCommandExecution) // if (message.SchemaId == MessageType.ErrorCommandExecution)
{ // {
throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception) // throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
{ CallRequestId = requestId }; // { CallRequestId = requestId };
} // }
//
return JsonSerializer.Deserialize<FinalCommandExecution<T>>(message.Data)!; // return JsonSerializer.Deserialize<FinalCommandExecution<T>>(message.Data)!;
} // }
//
public void PostCallRequest(ICallRequest callRequest) // public void PostCallRequest(ICallRequest callRequest)
{ // {
if (_interactionModule is null) // if (_interactionModule is null)
throw new Exception("Interaction module not initialized"); // throw new Exception("Interaction module not initialized");
//
//
var post = JsonSerializer.SerializeToUtf8Bytes(callRequest, callRequest.GetType()); // var post = JsonSerializer.SerializeToUtf8Bytes(callRequest, callRequest.GetType());
_interactionModule.PostMessage(JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage // _interactionModule.PostMessage(JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage
{ // {
Id = callRequest.CallRequestId, // Id = callRequest.CallRequestId,
Data = post, // Data = post,
SchemaId = MessageType.CallRequest // SchemaId = MessageType.CallRequest
})); // }));
} // }
//
public void Inject<T>(T dependency) // public void Inject<T>(T dependency)
{ // {
if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule) // if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule)
_interactionModule = interactionModule; // _interactionModule = interactionModule;
} // }
} // }
public class RemoteException(string error) : Exception public class RemoteException(string error) : Exception
{ {
@@ -9,13 +9,19 @@ namespace mROA.Implementation.Frontend;
public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
{ {
private readonly TcpClient _tcpClient = new(); private readonly TcpClient _tcpClient = new();
private StreamBasedFrontendInteractionModule? _interactionModule; private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is StreamBasedFrontendInteractionModule interactionModule) switch (dependency)
{ {
case NextGenerationInteractionModule interactionModule:
_interactionModule = 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"); throw new Exception("Interaction module was not injected");
_tcpClient.Connect(ipEndPoint); _tcpClient.Connect(ipEndPoint);
_interactionModule.ServerStream = _tcpClient.GetStream(); _interactionModule.BaseStream = _tcpClient.GetStream();
var welcomeMessage = _interactionModule.ReceiveMessage().GetAwaiter().GetResult(); var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
var message = JsonSerializer.Deserialize<NetworkMessage>(welcomeMessage); if (welcomeMessage.SchemaId != MessageType.IdAssigning)
if (message.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; namespace mROA.Implementation.Frontend;
public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontendInteractionModule // public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontendInteractionModule
{ // {
public Stream? ServerStream { get; set; } // public Stream? ServerStream { get; set; }
public int ClientId { get; set; } // public int ClientId { get; set; }
//
public NetworkMessage[] UnhandledMessages() // public NetworkMessage[] UnhandledMessages()
{ // {
return Array.Empty<NetworkMessage>(); // return Array.Empty<NetworkMessage>();
} // }
//
public NetworkMessage LastMessage() // public NetworkMessage LastMessage()
{ // {
return null; // return null;
} // }
//
//
//
public async Task<byte[]> ReceiveMessage() // public async Task<byte[]> ReceiveMessage()
{ // {
if (ServerStream is null) // if (ServerStream is null)
throw new IOException("Server is not connected."); // throw new IOException("Server is not connected.");
//
const int bufferSize = ushort.MaxValue; // const int bufferSize = ushort.MaxValue;
//
var buffer = new byte[bufferSize]; // var buffer = new byte[bufferSize];
if (!ServerStream.CanRead) throw new IOException("Server is not connected."); // if (!ServerStream.CanRead) throw new IOException("Server is not connected.");
//
await ServerStream.ReadExactlyAsync(buffer, 0, 2); // await ServerStream.ReadExactlyAsync(buffer, 0, 2);
var len = BitConverter.ToUInt16(buffer, 0); // var len = BitConverter.ToUInt16(buffer, 0);
await ServerStream.ReadExactlyAsync(buffer, 0, len); // await ServerStream.ReadExactlyAsync(buffer, 0, len);
//
return buffer[..len]; // return buffer[..len];
} // }
//
public void PostMessage(byte[] message) // public void PostMessage(byte[] message)
{ // {
if (ServerStream is null) // if (ServerStream is null)
throw new IOException("Server is not connected."); // throw new IOException("Server is not connected.");
//
ServerStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort)); // ServerStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
ServerStream.Write(message, 0, message.Length); // ServerStream.Write(message, 0, message.Length);
} // }
//
public void Inject<T>(T dependency) // 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; namespace mROA.Implementation;
public class NextGenerationInteractionModule : INextGenerationInteractionModule public class NextGenerationInteractionModule : INextGenerationInteractionModule
{ {
private ISerializationToolkit? _serialization; private ISerializationToolkit? _serialization;
public int ConntectionId { get; set; } public int ConntectionId { get; private set; }
public Stream? BaseStream { get; set; } public Stream? BaseStream { get; set; }
private Task<NetworkMessage>? _currentReceiving; private Task<NetworkMessage>? _currentReceiving;
private const int BufferSize = ushort.MaxValue; private const int BufferSize = ushort.MaxValue;
@@ -13,8 +14,15 @@ public class NextGenerationInteractionModule : INextGenerationInteractionModule
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is ISerializationToolkit toolkit) switch (dependency)
{
case ISerializationToolkit toolkit:
_serialization = toolkit; _serialization = toolkit;
break;
case IIdentityGenerator identityGenerator:
ConntectionId = identityGenerator.GetNextIdentity();
break;
}
} }