From 3d3772a341fd8166eeb1941239b1038b9286370b Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 12 Apr 2025 12:44:38 +0300 Subject: [PATCH 01/32] Primary implementation of untrusted message channel --- mROA/Abstract/IInteractionModule.cs | 11 +++- .../Backend/NetworkGatewayModule.cs | 21 +++++-- .../Frontend/NetworkFrontendBridge.cs | 21 +++++-- .../NextGenerationInteractionModule.cs | 62 ++++++++++++++++--- mROA/mROA.csproj | 1 + 5 files changed, 96 insertions(+), 20 deletions(-) diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs index d797ae0..fae3768 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading.Channels; using System.Threading.Tasks; using mROA.Implementation; @@ -8,13 +9,17 @@ namespace mROA.Abstract public interface INextGenerationInteractionModule : IInjectableModule, IDisposable { int ConnectionId { get; set; } - public Stream? BaseStream { get; set; } + Stream? BaseStream { get; set; } + ChannelReader UntrustedReceiveChanel { get; set; } + ChannelWriter<(int clientId, NetworkMessageHeader messageHeader)> UntrustedPostChanel { get; set; } + Task GetNextMessageReceiving(bool infinite = true); Task PostMessageAsync(NetworkMessageHeader messageHeader); + Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader); void HandleMessage(NetworkMessageHeader messageHeader); - NetworkMessageHeader[] UnhandledMessages { get; } + // NetworkMessageHeader[] UnhandledMessages { get; } NetworkMessageHeader? FirstByFilter(Predicate predicate); - event Action OnDisconected; + event Action OnDisconnected; Task Restart(bool sendRecovery); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index a3236a8..f756920 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -67,13 +68,18 @@ namespace mROA.Implementation.Backend var client = _tcpListener.AcceptTcpClient(); Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule; - + foreach (var injectableModule in _injectableModules!) interaction!.Inject(injectableModule); interaction!.Inject(_serialization); interaction.BaseStream = client.GetStream(); - + interaction.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleWriter = false, + SingleReader = false, + AllowSynchronousContinuations = true + }).Reader; var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; @@ -87,12 +93,19 @@ namespace mROA.Implementation.Backend break; case EMessageType.ClientRecovery: { - interaction.BaseStream = null; var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); + recoveryInteraction.UntrustedReceiveChanel = + Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleWriter = false, + SingleReader = false, + AllowSynchronousContinuations = true, + + }).Reader; recoveryInteraction.BaseStream = client.GetStream(); - + recoveryInteraction.Restart(false); Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); break; diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index ca32354..27e8219 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; using Exception = System.Exception; @@ -11,7 +12,7 @@ namespace mROA.Implementation.Frontend { private readonly IPEndPoint _serverEndPoint; private TcpClient _tcpClient = new(); - private NextGenerationInteractionModule? _interactionModule; + private INextGenerationInteractionModule? _interactionModule; private ISerializationToolkit? _serialization; public NetworkFrontendBridge(IPEndPoint serverEndPoint) @@ -42,12 +43,14 @@ namespace mROA.Implementation.Frontend _tcpClient.Connect(_serverEndPoint); _interactionModule.BaseStream = _tcpClient.GetStream(); - - _interactionModule.OnDisconected += id => + _interactionModule.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions { - Reconnect(); - }; - + SingleWriter = false, + SingleReader = false, + AllowSynchronousContinuations = true + }).Reader; + _interactionModule.OnDisconnected += id => { Reconnect(); }; + _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); if (idMessage.MessageType != EMessageType.IdAssigning) @@ -67,6 +70,12 @@ namespace mROA.Implementation.Frontend _tcpClient = new TcpClient(); _tcpClient.Connect(_serverEndPoint); _interactionModule.BaseStream = _tcpClient.GetStream(); + _interactionModule.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleWriter = false, + SingleReader = false, + AllowSynchronousContinuations = true + }).Reader; await _interactionModule.Restart(true); } diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 57ba7dd..92d63a3 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -20,6 +21,8 @@ namespace mROA.Implementation private bool _isInReconnectionState; private bool _isActive = true; private TaskCompletionSource _reconnection; + private ValueTask? _trustedReceive; + private TaskCompletionSource _untrustedReceive; public NextGenerationInteractionModule() { @@ -30,9 +33,13 @@ namespace mROA.Implementation public Stream? BaseStream { - get => _baseStream; set => _baseStream = value; + get => _baseStream; + set => _baseStream = value; } + public ChannelReader UntrustedReceiveChanel { get; set; } + public ChannelWriter<(int clientId, NetworkMessageHeader messageHeader)> UntrustedPostChanel { get; set; } + public void Inject(T dependency) { @@ -53,7 +60,6 @@ namespace mROA.Implementation if (_currentReceiving != null) return _currentReceiving; _currentReceiving = Task.Run(async () => await GetNextMessage()); return _currentReceiving; - } #pragma warning disable CS8602 // Dereference of a possibly null reference. private async ValueTask PostMessageInternal(NetworkMessageHeader messageHeader) @@ -68,7 +74,7 @@ namespace mROA.Implementation if (!_baseStream.CanWrite) return false; - + await BaseStream.WriteAsync(header); await BaseStream.WriteAsync(rawMessage); return true; @@ -101,25 +107,31 @@ namespace mROA.Implementation { return; } + _isConnected = false; withError = true; await MakeRecovery("OUT"); } } + public async Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader) + { + await UntrustedPostChanel.WriteAsync((ConnectionId, messageHeader)); + } + public void HandleMessage(NetworkMessageHeader messageHeader) { _messageBuffer.Remove(messageHeader); } - public NetworkMessageHeader[] UnhandledMessages => _messageBuffer.ToArray(); + // public NetworkMessageHeader[] UnhandledMessages => _messageBuffer.ToArray(); public NetworkMessageHeader? FirstByFilter(Predicate predicate) { return _messageBuffer.FirstOrDefault(m => predicate(m)); } - public event Action? OnDisconected; + public event Action? OnDisconnected; private async Task GetNextMessage() { @@ -140,7 +152,41 @@ namespace mROA.Implementation try { - var message = await Receive(); + NetworkMessageHeader message; + + var wasNull = _untrustedReceive is null; + + _trustedReceive ??= Receive(); + _untrustedReceive = new TaskCompletionSource(); + + + if (!wasNull) + { + if (_trustedReceive.Value.IsCompleted) + { + _trustedReceive = Receive(); + } + + if (_untrustedReceive.Task.IsCompleted) + { + _untrustedReceive = new TaskCompletionSource(); + _ = UntrustedReceiveChanel.ReadAsync().AsTask() + .ContinueWith(task => _untrustedReceive.SetResult(task.Result)); + } + } + else + { + _ = UntrustedReceiveChanel.ReadAsync().AsTask() + .ContinueWith(task => _untrustedReceive.SetResult(task.Result)); + } + + + await Task.WhenAny(_trustedReceive.Value.AsTask() , _untrustedReceive.Task); + + message = _trustedReceive.Value.IsCompleted + ? _trustedReceive.Value.Result + : _untrustedReceive.Task.Result; + _currentReceiving = Task.Run(async () => await GetNextMessage()); return message; @@ -151,6 +197,7 @@ namespace mROA.Implementation { return NetworkMessageHeader.Null; } + withError = true; await MakeRecovery("IN"); } @@ -238,7 +285,7 @@ namespace mROA.Implementation Console.WriteLine("Call OnDisconnected from {0}", source); _isInReconnectionState = true; - OnDisconected?.Invoke(ConnectionId); + OnDisconnected?.Invoke(ConnectionId); } Console.WriteLine("Waiting for reconnect from {0}", source); @@ -263,6 +310,7 @@ namespace mROA.Implementation { _currentReceiving?.Dispose(); } + _baseStream?.Dispose(); } } diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 5c9aea9..3c172de 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -26,6 +26,7 @@ + From d2a41150f14adc3d5d280f277690e5e32525b861 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Wed, 30 Apr 2025 12:25:23 +0300 Subject: [PATCH 02/32] Channel interaction module refresh base --- Example.Backend/Program.cs | 2 +- Example.Frontend/Program.cs | 4 +- mROA.Test/NextGenTest.cs | 8 +- mROA/Abstract/IConnectionHub.cs | 4 +- mROA/Abstract/IInteractionModule.cs | 11 +-- mROA/Implementation/Backend/ConnectionHub.cs | 6 +- .../Backend/NetworkGatewayModule.cs | 8 +- ...nModule.cs => ChannelInteractionModule.cs} | 92 +++++++------------ .../Frontend/NetworkFrontendBridge.cs | 16 ++-- mROA/Implementation/RepresentationModule.cs | 4 +- mROA/Implementation/StreamExtractor.cs | 76 +++++++++++++++ mROA/mROA.csproj | 2 +- 12 files changed, 143 insertions(+), 90 deletions(-) rename mROA/Implementation/{NextGenerationInteractionModule.cs => ChannelInteractionModule.cs} (76%) create mode 100644 mROA/Implementation/StreamExtractor.cs diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 1e12d48..719d274 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -19,7 +19,7 @@ class Program builder.Modules.Add(new BackendIdentityGenerator()); // builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule), // builder.GetModule()!); - builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule), + builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(ChannelInteractionModule), builder.GetModule()!); builder.Modules.Add(new ConnectionHub()); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 8ecc3f4..e87a449 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -23,7 +23,7 @@ class Program builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new RemoteContextRepository()); - builder.Modules.Add(new NextGenerationInteractionModule()); + builder.Modules.Add(new ChannelInteractionModule()); builder.Modules.Add(new RepresentationModule()); builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567))); builder.Modules.Add(new StaticRepresentationModuleProducer()); @@ -58,7 +58,7 @@ class Program Console.WriteLine("Printer created"); Thread.Sleep(100); - frontendBridge.Obstacle(); + // frontendBridge.Obstacle(); var name = disposingPrinter.GetName(); DemoCheck.BasicNonParamsCall = true; Console.WriteLine("Printer name : {0}", name); diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs index 0b708a7..64c6d86 100644 --- a/mROA.Test/NextGenTest.cs +++ b/mROA.Test/NextGenTest.cs @@ -11,17 +11,17 @@ namespace mROA.Test public class NextGenTest { private TcpListener _listener; - private NextGenerationInteractionModule _interactionModuleA; - private NextGenerationInteractionModule _interactionModuleB; + private ChannelInteractionModule _interactionModuleA; + private ChannelInteractionModule _interactionModuleB; private Guid[] guids = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; [SetUp] public void Setup() { _listener = new TcpListener(IPAddress.Loopback, 4567); - _interactionModuleA = new NextGenerationInteractionModule(); + _interactionModuleA = new ChannelInteractionModule(); _interactionModuleA.Inject(new JsonSerializationToolkit()); - _interactionModuleB = new NextGenerationInteractionModule(); + _interactionModuleB = new ChannelInteractionModule(); _interactionModuleB.Inject(new JsonSerializationToolkit()); } diff --git a/mROA/Abstract/IConnectionHub.cs b/mROA/Abstract/IConnectionHub.cs index 3c6afd4..01f60b9 100644 --- a/mROA/Abstract/IConnectionHub.cs +++ b/mROA/Abstract/IConnectionHub.cs @@ -6,8 +6,8 @@ public interface IConnectionHub : IInjectableModule { - void RegisterInteraction(INextGenerationInteractionModule interaction); - INextGenerationInteractionModule GetInteraction(int id); + void RegisterInteraction(IChannelInteractionModule interaction); + IChannelInteractionModule GetInteraction(int id); event ConnectionHandler? OnConnected; event DisconnectionHandler? OnDisconnected; } diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs index fae3768..cffade7 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -6,18 +6,17 @@ using mROA.Implementation; namespace mROA.Abstract { - public interface INextGenerationInteractionModule : IInjectableModule, IDisposable + public interface IChannelInteractionModule : IInjectableModule, IDisposable { int ConnectionId { get; set; } - Stream? BaseStream { get; set; } - ChannelReader UntrustedReceiveChanel { get; set; } - ChannelWriter<(int clientId, NetworkMessageHeader messageHeader)> UntrustedPostChanel { get; set; } - + ChannelWriter ReceiveChanel { get; } + ChannelReader TrustedPostChanel { get; } + ChannelReader UntrustedPostChanel { get; } + Action IsConnected { get; set; } Task GetNextMessageReceiving(bool infinite = true); Task PostMessageAsync(NetworkMessageHeader messageHeader); Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader); void HandleMessage(NetworkMessageHeader messageHeader); - // NetworkMessageHeader[] UnhandledMessages { get; } NetworkMessageHeader? FirstByFilter(Predicate predicate); event Action OnDisconnected; Task Restart(bool sendRecovery); diff --git a/mROA/Implementation/Backend/ConnectionHub.cs b/mROA/Implementation/Backend/ConnectionHub.cs index de302b0..22b7b6b 100644 --- a/mROA/Implementation/Backend/ConnectionHub.cs +++ b/mROA/Implementation/Backend/ConnectionHub.cs @@ -6,10 +6,10 @@ namespace mROA.Implementation.Backend { public class ConnectionHub : IConnectionHub { - private readonly Dictionary _connections = new(); + private readonly Dictionary _connections = new(); private ISerializationToolkit? _serializationToolkit; - public void RegisterInteraction(INextGenerationInteractionModule interaction) + public void RegisterInteraction(IChannelInteractionModule interaction) { if (_serializationToolkit is null) throw new NullReferenceException("Serialization toolkit is null"); @@ -21,7 +21,7 @@ namespace mROA.Implementation.Backend OnConnected?.Invoke(module); } - public INextGenerationInteractionModule GetInteraction(int id) + public IChannelInteractionModule GetInteraction(int id) { return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found"); } diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index f756920..4c3f22b 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -67,19 +67,21 @@ namespace mROA.Implementation.Backend { var client = _tcpListener.AcceptTcpClient(); Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); - var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule; + var interaction = Activator.CreateInstance(_interactionModuleType!) as IChannelInteractionModule; foreach (var injectableModule in _injectableModules!) interaction!.Inject(injectableModule); interaction!.Inject(_serialization); interaction.BaseStream = client.GetStream(); - interaction.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions + var channel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleWriter = false, SingleReader = false, AllowSynchronousContinuations = true - }).Reader; + }); + interaction.UntrustedReceiveChanel = channel.Reader; + interaction.UntrustedReceiveChanelWriter = channel.Writer; var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs similarity index 76% rename from mROA/Implementation/NextGenerationInteractionModule.cs rename to mROA/Implementation/ChannelInteractionModule.cs index 92d63a3..e5d51ba 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -2,43 +2,59 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; namespace mROA.Implementation { - public class NextGenerationInteractionModule : INextGenerationInteractionModule + public class ChannelInteractionModule : IChannelInteractionModule { - private int DebugId = new Random().Next(); + private readonly ChannelReader _receiveReader; + private readonly Channel _inputChannel; + private readonly Channel _outputTrustedChannel; + private readonly Channel _outputUntrustedChannel; private const int BufferSize = ushort.MaxValue; private readonly Memory _buffer = new byte[BufferSize]; private readonly List _messageBuffer = new(128); private Task? _currentReceiving; private ISerializationToolkit? _serialization; - private Stream? _baseStream; private bool _isConnected = true; private bool _isInReconnectionState; private bool _isActive = true; private TaskCompletionSource _reconnection; - private ValueTask? _trustedReceive; - private TaskCompletionSource _untrustedReceive; - public NextGenerationInteractionModule() + public ChannelInteractionModule() { _reconnection = new TaskCompletionSource(); + _inputChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleReader = false, + SingleWriter = false, + AllowSynchronousContinuations = true + }); + _receiveReader = _inputChannel.Reader; + _outputTrustedChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleReader = true, + SingleWriter = true, + AllowSynchronousContinuations = true + }); + _outputUntrustedChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + { + SingleReader = true, + SingleWriter = true, + AllowSynchronousContinuations = true + }); } public int ConnectionId { get; set; } - public Stream? BaseStream - { - get => _baseStream; - set => _baseStream = value; - } - - public ChannelReader UntrustedReceiveChanel { get; set; } - public ChannelWriter<(int clientId, NetworkMessageHeader messageHeader)> UntrustedPostChanel { get; set; } + public ChannelWriter ReceiveChanel => _inputChannel.Writer; + public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; + public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; + public Action IsConnected { get; set; } public void Inject(T dependency) @@ -152,46 +168,10 @@ namespace mROA.Implementation try { - NetworkMessageHeader message; - - var wasNull = _untrustedReceive is null; - - _trustedReceive ??= Receive(); - _untrustedReceive = new TaskCompletionSource(); - - - if (!wasNull) - { - if (_trustedReceive.Value.IsCompleted) - { - _trustedReceive = Receive(); - } - - if (_untrustedReceive.Task.IsCompleted) - { - _untrustedReceive = new TaskCompletionSource(); - _ = UntrustedReceiveChanel.ReadAsync().AsTask() - .ContinueWith(task => _untrustedReceive.SetResult(task.Result)); - } - } - else - { - _ = UntrustedReceiveChanel.ReadAsync().AsTask() - .ContinueWith(task => _untrustedReceive.SetResult(task.Result)); - } - - - await Task.WhenAny(_trustedReceive.Value.AsTask() , _untrustedReceive.Task); - - message = _trustedReceive.Value.IsCompleted - ? _trustedReceive.Value.Result - : _untrustedReceive.Task.Result; - - _currentReceiving = Task.Run(async () => await GetNextMessage()); - + var message = await _receiveReader.ReadAsync(); return message; } - catch (Exception ex) + catch (Exception) { if (!_isActive) { @@ -276,12 +256,6 @@ namespace mROA.Implementation lock (_reconnection) { Console.WriteLine("Got lock from {0}", source); - if (_isConnected || _isInReconnectionState) - { - Console.WriteLine( - $"{source} {_isConnected} {_isInReconnectionState} {!_baseStream.CanRead} {!_baseStream.CanWrite}"); - return; - } Console.WriteLine("Call OnDisconnected from {0}", source); _isInReconnectionState = true; @@ -310,8 +284,6 @@ namespace mROA.Implementation { _currentReceiving?.Dispose(); } - - _baseStream?.Dispose(); } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 27e8219..2a5ec69 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -12,7 +12,7 @@ namespace mROA.Implementation.Frontend { private readonly IPEndPoint _serverEndPoint; private TcpClient _tcpClient = new(); - private INextGenerationInteractionModule? _interactionModule; + private IChannelInteractionModule? _interactionModule; private ISerializationToolkit? _serialization; public NetworkFrontendBridge(IPEndPoint serverEndPoint) @@ -24,7 +24,7 @@ namespace mROA.Implementation.Frontend { switch (dependency) { - case NextGenerationInteractionModule interactionModule: + case ChannelInteractionModule interactionModule: _interactionModule = interactionModule; break; case ISerializationToolkit toolkit: @@ -43,12 +43,14 @@ namespace mROA.Implementation.Frontend _tcpClient.Connect(_serverEndPoint); _interactionModule.BaseStream = _tcpClient.GetStream(); - _interactionModule.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions + var channel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleWriter = false, SingleReader = false, AllowSynchronousContinuations = true - }).Reader; + }); + _interactionModule.UntrustedReceiveChanel = channel.Reader; + _interactionModule.UntrustedReceiveChanelWriter = channel.Writer; _interactionModule.OnDisconnected += id => { Reconnect(); }; _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); @@ -70,12 +72,14 @@ namespace mROA.Implementation.Frontend _tcpClient = new TcpClient(); _tcpClient.Connect(_serverEndPoint); _interactionModule.BaseStream = _tcpClient.GetStream(); - _interactionModule.UntrustedReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions + var channel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleWriter = false, SingleReader = false, AllowSynchronousContinuations = true - }).Reader; + }); + _interactionModule.UntrustedReceiveChanel = channel.Reader; + _interactionModule.UntrustedReceiveChanelWriter = channel.Writer; await _interactionModule.Restart(true); } diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 6ea6fcd..d758c6f 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -7,7 +7,7 @@ namespace mROA.Implementation { public class RepresentationModule : IRepresentationModule { - private INextGenerationInteractionModule? _interaction; + private IChannelInteractionModule? _interaction; private ISerializationToolkit? _serialization; public void Inject(T dependency) @@ -17,7 +17,7 @@ namespace mROA.Implementation case ISerializationToolkit toolkit: _serialization = toolkit; break; - case INextGenerationInteractionModule interactionModule: + case IChannelInteractionModule interactionModule: _interaction = interactionModule; break; } diff --git a/mROA/Implementation/StreamExtractor.cs b/mROA/Implementation/StreamExtractor.cs new file mode 100644 index 0000000..f9f71c5 --- /dev/null +++ b/mROA/Implementation/StreamExtractor.cs @@ -0,0 +1,76 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using mROA.Abstract; + +namespace mROA.Implementation +{ + public class StreamExtractor + { + private readonly Stream _ioStream; + private readonly ISerializationToolkit _serializationToolkit; + private const int BufferSize = ushort.MaxValue; + private readonly Memory _buffer = new byte[BufferSize]; + private bool _manualConnectionState = true; + public StreamExtractor(Stream ioStream, ISerializationToolkit serializationToolkit) + { + _ioStream = ioStream; + _serializationToolkit = serializationToolkit; + } + + public event Action MessageReceived; + + private ushort ReadMessageLength() + { + var firstBit = _ioStream.ReadByte(); + if (firstBit == -1) + { + _manualConnectionState = false; + throw new EndOfStreamException(); + } + + _manualConnectionState = true; + var secondBit = (byte)_ioStream.ReadByte(); + + var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit }); + + return len; + } + + public async Task SingleReceive() + { + var len = ReadMessageLength(); + var localSpan = _buffer[..len]; + + await _ioStream.ReadExactlyAsync(localSpan); + + var message = _serializationToolkit.Deserialize(localSpan.Span); +#if TRACE + Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.MessageType}"); + TransmissionConfig.TotalTransmittedBytes += len; + Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); +#endif + MessageReceived(message); + } + + public async Task InfiniteReceive(CancellationToken token) + { + while (token.IsCancellationRequested == false) + { + await SingleReceive(); + } + } + + public async Task Send(NetworkMessageHeader message) + { + var rawMessage = _serializationToolkit.Serialize(message); + var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); + + await _ioStream.WriteAsync(header); + await _ioStream.WriteAsync(rawMessage); + } + + public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState; + } +} \ No newline at end of file diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 3c172de..e52150a 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - + TRACE; From 4e9b5956204919011c4d37d9d2489e7f281b0231 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Fri, 2 May 2025 12:08:31 +0300 Subject: [PATCH 03/32] Additional channel changes --- mROA/Abstract/IInteractionModule.cs | 2 +- .../Backend/NetworkGatewayModule.cs | 36 ++--- .../ChannelInteractionModule.cs | 141 +++++------------- .../Frontend/NetworkFrontendBridge.cs | 48 +++--- mROA/Implementation/NetworkMessageHeader.cs | 18 +++ mROA/Implementation/StreamExtractor.cs | 35 ++++- 6 files changed, 131 insertions(+), 149 deletions(-) diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs index cffade7..4a884e8 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -12,7 +12,7 @@ namespace mROA.Abstract ChannelWriter ReceiveChanel { get; } ChannelReader TrustedPostChanel { get; } ChannelReader UntrustedPostChanel { get; } - Action IsConnected { get; set; } + Func IsConnected { get; set; } Task GetNextMessageReceiving(bool infinite = true); Task PostMessageAsync(NetworkMessageHeader messageHeader); Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader); diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 4c3f22b..52ac70c 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -73,21 +74,20 @@ namespace mROA.Implementation.Backend interaction!.Inject(injectableModule); interaction!.Inject(_serialization); - interaction.BaseStream = client.GetStream(); - var channel = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleWriter = false, - SingleReader = false, - AllowSynchronousContinuations = true - }); - interaction.UntrustedReceiveChanel = channel.Reader; - interaction.UntrustedReceiveChanelWriter = channel.Writer; + + + var streamExtractor = new StreamExtractor(client.GetStream(), _serialization); + interaction.IsConnected = () => streamExtractor.IsConnected; + streamExtractor.MessageReceived += message => interaction.ReceiveChanel.WriteAsync(message); + streamExtractor.SingleReceive(); var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; - + switch (connectionRequest.MessageType) { case EMessageType.ClientConnect: + Task.Run(async () => await streamExtractor.LoopedReceive()); + streamExtractor.SendFromChannel(interaction.TrustedPostChanel); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, new IdAssignment { Id = -interaction.ConnectionId })); _hub!.RegisterInteraction(interaction); @@ -95,19 +95,13 @@ namespace mROA.Implementation.Backend break; case EMessageType.ClientRecovery: { - interaction.BaseStream = null; var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); - recoveryInteraction.UntrustedReceiveChanel = - Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleWriter = false, - SingleReader = false, - AllowSynchronousContinuations = true, - - }).Reader; - recoveryInteraction.BaseStream = client.GetStream(); + + streamExtractor = new StreamExtractor(client.GetStream(), _serialization); + streamExtractor.MessageReceived += message => recoveryInteraction.ReceiveChanel.WriteAsync(message); + _ = streamExtractor.LoopedReceive(); recoveryInteraction.Restart(false); Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); break; @@ -118,7 +112,7 @@ namespace mROA.Implementation.Backend } } } - + private void ThrowIfNotInjected() { if (_hub is null) diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index e5d51ba..c3f637b 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -12,22 +12,20 @@ namespace mROA.Implementation public class ChannelInteractionModule : IChannelInteractionModule { private readonly ChannelReader _receiveReader; + private readonly ChannelWriter _trustedWriter; + private readonly ChannelWriter _untrustedWriter; private readonly Channel _inputChannel; private readonly Channel _outputTrustedChannel; private readonly Channel _outputUntrustedChannel; - private const int BufferSize = ushort.MaxValue; - private readonly Memory _buffer = new byte[BufferSize]; private readonly List _messageBuffer = new(128); private Task? _currentReceiving; private ISerializationToolkit? _serialization; private bool _isConnected = true; - private bool _isInReconnectionState; private bool _isActive = true; private TaskCompletionSource _reconnection; public ChannelInteractionModule() { - _reconnection = new TaskCompletionSource(); _inputChannel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = false, @@ -35,18 +33,21 @@ namespace mROA.Implementation AllowSynchronousContinuations = true }); _receiveReader = _inputChannel.Reader; - _outputTrustedChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + _outputTrustedChannel = Channel.CreateBounded(new BoundedChannelOptions(1) { SingleReader = true, SingleWriter = true, - AllowSynchronousContinuations = true + AllowSynchronousContinuations = true, + }); + _trustedWriter = _outputTrustedChannel.Writer; _outputUntrustedChannel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true, AllowSynchronousContinuations = true }); + _untrustedWriter = _outputUntrustedChannel.Writer; } public int ConnectionId { get; set; } @@ -54,7 +55,7 @@ namespace mROA.Implementation public ChannelWriter ReceiveChanel => _inputChannel.Writer; public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; - public Action IsConnected { get; set; } + public Func IsConnected { get; set; } public void Inject(T dependency) @@ -72,7 +73,7 @@ namespace mROA.Implementation public Task GetNextMessageReceiving(bool infinite = true) { - if (!infinite) return Receive().AsTask(); + if (!infinite) return _receiveReader.ReadAsync().AsTask(); if (_currentReceiving != null) return _currentReceiving; _currentReceiving = Task.Run(async () => await GetNextMessage()); return _currentReceiving; @@ -80,19 +81,12 @@ namespace mROA.Implementation #pragma warning disable CS8602 // Dereference of a possibly null reference. private async ValueTask PostMessageInternal(NetworkMessageHeader messageHeader) { -#if TRACE - Console.WriteLine( - $"{DateTime.Now.TimeOfDay} Posting message: {messageHeader.Id} - {messageHeader.MessageType} to {ConnectionId}"); -#endif - - var rawMessage = _serialization.Serialize(messageHeader); - var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); - - if (!_baseStream.CanWrite) + if (!IsConnected()) + { return false; - - await BaseStream.WriteAsync(header); - await BaseStream.WriteAsync(rawMessage); + } + + await _trustedWriter.WriteAsync(messageHeader); return true; } #pragma warning restore CS8602 // Dereference of a possibly null reference. @@ -100,9 +94,6 @@ namespace mROA.Implementation public async Task PostMessageAsync(NetworkMessageHeader messageHeader) { - if (BaseStream == null) - throw new NullReferenceException("BaseStream is null"); - if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); @@ -132,7 +123,7 @@ namespace mROA.Implementation public async Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader) { - await UntrustedPostChanel.WriteAsync((ConnectionId, messageHeader)); + await _untrustedWriter.WriteAsync(messageHeader); } public void HandleMessage(NetworkMessageHeader messageHeader) @@ -151,9 +142,6 @@ namespace mROA.Implementation private async Task GetNextMessage() { - if (BaseStream == null) - throw new NullReferenceException("BaseStream is null"); - if (_serialization == null) throw new NullReferenceException("Serialization toolkit is null"); @@ -184,65 +172,17 @@ namespace mROA.Implementation } } - private ushort ReadMessageLength() - { - var firstBit = BaseStream.ReadByte(); - if (firstBit == -1) - { - _isConnected = false; - throw new EndOfStreamException(); - } - - _isConnected = true; - var secondBit = (byte)BaseStream.ReadByte(); - - var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit }); - - return len; - } - - private async ValueTask Receive() - { - var len = ReadMessageLength(); - var localSpan = _buffer[..len]; - - await BaseStream.ReadExactlyAsync(localSpan); - - var message = _serialization.Deserialize(localSpan.Span); -#if TRACE - Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.MessageType}"); - TransmissionConfig.TotalTransmittedBytes += len; - Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); -#endif - _messageBuffer.Add(message); - return message; - } - public async Task Restart(bool sendRecovery) { if (sendRecovery) { await PostMessageAsync( new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)))); - var iTest = _baseStream.ReadByte(); - var bTest = (byte)iTest; - _baseStream.WriteByte(bTest); - } - else - { - const byte confirmByte = 128; - _baseStream.WriteByte(confirmByte); - var iPong = _baseStream.ReadByte(); - var bPong = (byte)iPong; - if (confirmByte != bPong) - { - Console.WriteLine("Incorrect byte"); - } } Console.WriteLine("Setting result for reconnection"); - var setting = _reconnection.TrySetResult(BaseStream); - _isInReconnectionState = false; + var setting = _reconnection.TrySetResult(null); + // _isInReconnectionState = false; _isConnected = true; Console.WriteLine($"Set result for reconnection {setting}"); @@ -251,29 +191,30 @@ namespace mROA.Implementation private async Task MakeRecovery(string source) { - Console.WriteLine("Staring recovery from {0}", source); - - lock (_reconnection) - { - Console.WriteLine("Got lock from {0}", source); - - Console.WriteLine("Call OnDisconnected from {0}", source); - _isInReconnectionState = true; - OnDisconnected?.Invoke(ConnectionId); - } - - Console.WriteLine("Waiting for reconnect from {0}", source); - if (!_reconnection.Task.IsCompleted && !_isConnected) - { - Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); - await _reconnection.Task; - } - - Console.WriteLine("Reconnect finished from {0}", source); - lock (_reconnection) - { - _isInReconnectionState = false; - } + //TODO переделать реконнект + // Console.WriteLine("Staring recovery from {0}", source); + // + // lock (_reconnection) + // { + // Console.WriteLine("Got lock from {0}", source); + // + // Console.WriteLine("Call OnDisconnected from {0}", source); + // _isInReconnectionState = true; + // OnDisconnected?.Invoke(ConnectionId); + // } + // + // Console.WriteLine("Waiting for reconnect from {0}", source); + // if (!_reconnection.Task.IsCompleted && !_isConnected) + // { + // Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); + // await _reconnection.Task; + // } + // + // Console.WriteLine("Reconnect finished from {0}", source); + // lock (_reconnection) + // { + // _isInReconnectionState = false; + // } } public void Dispose() diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 2a5ec69..5c48b40 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -14,10 +15,13 @@ namespace mROA.Implementation.Frontend private TcpClient _tcpClient = new(); private IChannelInteractionModule? _interactionModule; private ISerializationToolkit? _serialization; + private StreamExtractor _currentExtractor; + private CancellationTokenSource _rawExtractorCancellation; public NetworkFrontendBridge(IPEndPoint serverEndPoint) { _serverEndPoint = serverEndPoint; + _rawExtractorCancellation = new CancellationTokenSource(); } public void Inject(T dependency) @@ -42,19 +46,15 @@ namespace mROA.Implementation.Frontend _tcpClient.Connect(_serverEndPoint); - _interactionModule.BaseStream = _tcpClient.GetStream(); - var channel = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleWriter = false, - SingleReader = false, - AllowSynchronousContinuations = true - }); - _interactionModule.UntrustedReceiveChanel = channel.Reader; - _interactionModule.UntrustedReceiveChanelWriter = channel.Writer; + PrepareExtractor(); + _interactionModule.IsConnected = () => _currentExtractor.IsConnected; _interactionModule.OnDisconnected += id => { Reconnect(); }; _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); + + _currentExtractor.SingleReceive(); var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); + if (idMessage.MessageType != EMessageType.IdAssigning) { throw new Exception( @@ -62,30 +62,40 @@ namespace mROA.Implementation.Frontend } + var stopToken = _rawExtractorCancellation.Token; + Task.Run(async () => await _currentExtractor.LoopedReceive(stopToken)); + var assignment = _serialization.Deserialize(idMessage.Data)!; _interactionModule.ConnectionId = -assignment.Id; TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); } + private void PrepareExtractor() + { + _currentExtractor = new StreamExtractor(_tcpClient.GetStream(), _serialization); + + _ = _currentExtractor.SendFromChannel(_interactionModule.TrustedPostChanel, + _rawExtractorCancellation.Token); + _currentExtractor.MessageReceived += message => _interactionModule.ReceiveChanel.WriteAsync(message); + } + private async Task Reconnect() { _tcpClient = new TcpClient(); _tcpClient.Connect(_serverEndPoint); - _interactionModule.BaseStream = _tcpClient.GetStream(); - var channel = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleWriter = false, - SingleReader = false, - AllowSynchronousContinuations = true - }); - _interactionModule.UntrustedReceiveChanel = channel.Reader; - _interactionModule.UntrustedReceiveChanelWriter = channel.Writer; + + _rawExtractorCancellation.Cancel(); + _rawExtractorCancellation = new CancellationTokenSource(); + + PrepareExtractor(); + + _ = _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token); + await _interactionModule.Restart(true); } public void Obstacle() { - _interactionModule!.BaseStream!.Dispose(); _tcpClient.Dispose(); } diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index a75cdb0..8e6c643 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -8,6 +8,24 @@ namespace mROA.Implementation { public class NetworkMessageHeader { + protected bool Equals(NetworkMessageHeader other) + { + return Id.Equals(other.Id) && MessageType == other.MessageType; + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((NetworkMessageHeader)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Id, (int)MessageType); + } + public static readonly NetworkMessageHeader Null = new(); public NetworkMessageHeader() { diff --git a/mROA/Implementation/StreamExtractor.cs b/mROA/Implementation/StreamExtractor.cs index f9f71c5..53d345d 100644 --- a/mROA/Implementation/StreamExtractor.cs +++ b/mROA/Implementation/StreamExtractor.cs @@ -1,6 +1,7 @@ using System; using System.IO; using System.Threading; +using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -13,6 +14,7 @@ namespace mROA.Implementation private const int BufferSize = ushort.MaxValue; private readonly Memory _buffer = new byte[BufferSize]; private bool _manualConnectionState = true; + public StreamExtractor(Stream ioStream, ISerializationToolkit serializationToolkit) { _ioStream = ioStream; @@ -38,12 +40,12 @@ namespace mROA.Implementation return len; } - public async Task SingleReceive() + public async Task SingleReceive(CancellationToken Token = default) { var len = ReadMessageLength(); var localSpan = _buffer[..len]; - await _ioStream.ReadExactlyAsync(localSpan); + await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); var message = _serializationToolkit.Deserialize(localSpan.Span); #if TRACE @@ -54,23 +56,40 @@ namespace mROA.Implementation MessageReceived(message); } - public async Task InfiniteReceive(CancellationToken token) + public async Task LoopedReceive(CancellationToken token = default) { - while (token.IsCancellationRequested == false) + while (token.IsCancellationRequested == false && IsConnected) { - await SingleReceive(); + await SingleReceive(token); } } - public async Task Send(NetworkMessageHeader message) + public async Task Send(NetworkMessageHeader message, CancellationToken token = default) { var rawMessage = _serializationToolkit.Serialize(message); var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); - await _ioStream.WriteAsync(header); - await _ioStream.WriteAsync(rawMessage); +#if TRACE + Console.WriteLine($"{DateTime.Now.TimeOfDay} Posting Message {message.Id} - {message.MessageType}"); + TransmissionConfig.TotalTransmittedBytes += rawMessage.Length; + Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); +#endif + + await _ioStream.WriteAsync(header, token); + await _ioStream.WriteAsync(rawMessage, token); } + public async Task SendFromChannel(ChannelReader channel, + CancellationToken token = default) + { + while (token.IsCancellationRequested == false && IsConnected) + { + var message = await channel.ReadAsync(token); + await Send(message, token); + } + } + + public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState; } } \ No newline at end of file From e6466b133bdbeb85f2f2488c50ddeb2df172fe48 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 2 May 2025 13:34:40 +0300 Subject: [PATCH 04/32] Abstraction of representation module rewrite --- ...tionModule.cs => IRepresentationModule.cs} | 14 +-- .../Frontend/NetworkFrontendBridge.cs | 2 + .../Frontend/RequestExtractor.cs | 103 ++++++++---------- mROA/Implementation/NetworkMessageHeader.cs | 5 + mROA/Implementation/RemoteObjectBase.cs | 74 ++++++------- mROA/Implementation/RepresentationModule.cs | 11 ++ 6 files changed, 104 insertions(+), 105 deletions(-) rename mROA/Abstract/{ISerialisationModule.cs => IRepresentationModule.cs} (52%) diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/IRepresentationModule.cs similarity index 52% rename from mROA/Abstract/ISerialisationModule.cs rename to mROA/Abstract/IRepresentationModule.cs index 4cea03f..2d9fc06 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/IRepresentationModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using mROA.Implementation; @@ -9,16 +10,13 @@ namespace mROA.Abstract { int Id { get; } - Task GetMessageAsync(Guid? requestId = null, EMessageType? messageType = null, - CancellationToken token = default); - - T GetMessage(Guid? requestId = null, EMessageType? messageType = null); - - Task GetRawMessage(Guid? requestId = null, EMessageType? messageType = null, - CancellationToken token = default); + Task<(object parced, EMessageType originalType)> GetSingle(Predicate rule, CancellationToken token, + params Func[] converter); + + IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, CancellationToken token, + params Func[] converter); Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull; - Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType); void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull; void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType); } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 5c48b40..4b98fab 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index fbe9539..5b348d9 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -4,7 +4,6 @@ using System.Threading; using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.Backend; -using mROA.Implementation.CommandExecution; // ReSharper disable MethodHasAsyncOverload @@ -45,22 +44,32 @@ namespace mROA.Implementation.Frontend } } - public Task StartExtraction() + public async Task StartExtraction() { - return Task.Run(() => - { - ThrowIfNotInjected(); - var multiClientOwnershipRepository = - TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; - multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); + ThrowIfNotInjected(); + var multiClientOwnershipRepository = + TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + multiClientOwnershipRepository?.RegisterOwnership(_representationModule!.Id); - try - { + try + { #if TRACE var sw = new Stopwatch(); #endif - while (true) - { + + var streamTokenSource = new CancellationTokenSource(); + + var query = _representationModule!.GetStream(m => + m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest + or EMessageType.EventRequest or EMessageType.ClientDisconnect, streamTokenSource.Token, + m => m.MessageType == EMessageType.CallRequest ? typeof(DefaultCallRequest) : null, + m => m.MessageType == EMessageType.CancelRequest ? typeof(CancelRequest) : null, + m => m.MessageType == EMessageType.EventRequest ? typeof(DefaultCallRequest) : null, + m => m.MessageType == EMessageType.ClientDisconnect ? typeof(ClientDisconnect) : null); + + + await foreach (var command in query) + { #if TRACE Console.WriteLine("Waiting for request..."); if (sw.IsRunning) @@ -69,50 +78,34 @@ namespace mROA.Implementation.Frontend Console.WriteLine($"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds."); } #endif - var tokenSource = new CancellationTokenSource(); - var token = tokenSource.Token; - var defaultRequest = - _representationModule!.GetMessageAsync( - messageType: EMessageType.CallRequest, token: token); - var cancelRequest = - _representationModule!.GetMessageAsync( - messageType: EMessageType.CancelRequest, token: token); - var eventRequest = - _representationModule!.GetMessageAsync( - messageType: EMessageType.EventRequest, token: token); - var disconnectRequest = - _representationModule!.GetMessageAsync( - messageType: EMessageType.ClientDisconnect, token:token); - Task.WaitAny(defaultRequest, cancelRequest, eventRequest, disconnectRequest); + #if TRACE Console.WriteLine("Request received"); sw.Restart(); #endif - if (cancelRequest.IsCompleted) - { -#if TRACE - Console.WriteLine("Cancelling request"); -#endif - HandleCancelRequest(tokenSource, cancelRequest.Result); - } - else if (defaultRequest.IsCompleted) - { - HandleCallRequest(tokenSource, defaultRequest.Result); - } - else if(eventRequest.IsCompleted) - { - HandleEventRequest(tokenSource, eventRequest.Result); - }else if (disconnectRequest.IsCompleted) - { + switch (command.originalType) + { + case EMessageType.CallRequest: + HandleCallRequest((command.parced as DefaultCallRequest)!); break; - } + case EMessageType.ClientDisconnect: + return; + case EMessageType.EventRequest: + HandleEventRequest((command.parced as DefaultCallRequest)!); + break; + case EMessageType.CancelRequest: + HandleCancelRequest((command.parced as CancelRequest)!); + + break; + default: + continue; } } - catch - { - multiClientOwnershipRepository?.FreeOwnership(); - } - }); + } + catch + { + multiClientOwnershipRepository?.FreeOwnership(); + } } private void ThrowIfNotInjected() @@ -129,20 +122,17 @@ namespace mROA.Implementation.Frontend throw new NullReferenceException("Method repository is null."); } - private void HandleCancelRequest(CancellationTokenSource tokenSource, CancelRequest req) + private void HandleCancelRequest(CancelRequest req) { - tokenSource.Cancel(); _executeModule!.Execute(req, _realContextRepository!, _representationModule!); } - private void HandleCallRequest(CancellationTokenSource tokenSource, DefaultCallRequest request) + private void HandleCallRequest(DefaultCallRequest request) { - tokenSource.Cancel(); - var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!); var resultType = result.MessageType; - + if (resultType == EMessageType.Unknown) { return; @@ -151,9 +141,8 @@ namespace mROA.Implementation.Frontend _representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType()); } - private void HandleEventRequest(CancellationTokenSource tokenSource, DefaultCallRequest request) + private void HandleEventRequest(DefaultCallRequest request) { - tokenSource.Cancel(); _executeModule!.Execute(request, _remoteContextRepository!, _representationModule!); } } diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index 8e6c643..61ecea2 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -1,6 +1,7 @@ using System; using System.Text.Json.Serialization; using mROA.Abstract; +using mROA.Implementation.Attributes; // ReSharper disable UnusedMember.Global @@ -45,5 +46,9 @@ namespace mROA.Implementation public EMessageType MessageType { get; set; } public byte[] Data { get; set; } + + [JsonIgnore] + [SerializationIgnore] + public object Parced { get; set; } } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 7f2be6f..941cb52 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -10,7 +10,7 @@ namespace mROA.Implementation { public abstract class RemoteObjectBase : IDisposable { - protected bool Equals(RemoteObjectBase other) + public bool Equals(RemoteObjectBase other) { return _identifier.Equals(other._identifier); } @@ -60,40 +60,36 @@ namespace mROA.Implementation var localTokenSource = new CancellationTokenSource(); - var successResponse = - _representationModule.GetMessageAsync>(request.Id, - EMessageType.FinishedCommandExecution, - localTokenSource.Token); - var errorResponse = - _representationModule.GetMessageAsync(requestId: request.Id, - EMessageType.ExceptionCommandExecution, localTokenSource.Token); + var responseRequestTask = _representationModule.GetSingle( + m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, + localTokenSource.Token, + m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null, + m => m.MessageType is EMessageType.ExceptionCommandExecution + ? typeof(ExceptionCommandExecution) + : null); - cancellationToken.Register(async () => + cancellationToken.Register(() => { #if TRACE Console.WriteLine("Cancelling task"); #endif - await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest, + _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest, new CancelRequest { Id = request.Id - }); - localTokenSource.Cancel(); + }).ContinueWith(_ => localTokenSource.Cancel()); }); - Task.WaitAny(new Task[] - { - successResponse, errorResponse - }, cancellationToken); + var response = await responseRequestTask; - if (successResponse.IsCompletedSuccessfully) + if (response.parced is FinalCommandExecution successResponse) { localTokenSource.Cancel(); - return successResponse.Result.Result!; + return successResponse.Result!; } localTokenSource.Cancel(); - throw errorResponse.Result.GetException(); + throw (response.parced as ExceptionCommandExecution)!.GetException(); } protected async Task CallAsync(int methodId, object?[]? parameters = null, @@ -107,40 +103,38 @@ namespace mROA.Implementation var localTokenSource = new CancellationTokenSource(); - var successResponse = - _representationModule.GetMessageAsync(request.Id, - EMessageType.FinishedCommandExecution, - localTokenSource.Token); - var errorResponse = - _representationModule.GetMessageAsync(requestId: request.Id, - EMessageType.ExceptionCommandExecution, localTokenSource.Token); + var responceRequestTask = _representationModule.GetSingle( + m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, + localTokenSource.Token, + m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null, + m => m.MessageType is EMessageType.ExceptionCommandExecution + ? typeof(ExceptionCommandExecution) + : null); - cancellationToken.Register(async () => + + cancellationToken.Register(() => { #if TRACE Console.WriteLine("Cancelling task"); #endif - await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest, + _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest, new CancelRequest { Id = request.Id - }); - localTokenSource.Cancel(); + }).ContinueWith(_ => localTokenSource.Cancel()); }); - Task.WaitAny(new Task[] - { - errorResponse, successResponse - }, cancellationToken); - + var responseRequest = await responceRequestTask; #if TRACE Console.WriteLine($"Handling message"); #endif - if (successResponse.IsCompletedSuccessfully) - return; - - if (errorResponse.IsCompletedSuccessfully) - throw errorResponse.Result.GetException(); + switch (responseRequest.originalType) + { + case EMessageType.FinishedCommandExecution: + return; + case EMessageType.ExceptionCommandExecution: + throw (responseRequest.parced as ExceptionCommandExecution)!.GetException(); + } } public override string ToString() diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index d758c6f..2e80308 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -28,6 +29,16 @@ namespace mROA.Implementation public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")) .ConnectionId; + public Task<(object parced, EMessageType originalType)> GetSingle(Predicate rule, CancellationToken token, params Func[] converter) + { + throw new NotImplementedException(); + } + + public IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, CancellationToken token, params Func[] converter) + { + throw new NotImplementedException(); + } + public async Task GetMessageAsync(Guid? requestId, EMessageType? messageType, CancellationToken token = default) { From 557a52f24c3964afd49a647a0779039c5ecca6a9 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 2 May 2025 19:17:11 +0300 Subject: [PATCH 05/32] Some strange breaking changes --- mROA.Test/NextGenTest.cs | 4 +- ...Module.cs => IChannelInteractionModule.cs} | 6 +- mROA/Abstract/IRepresentationModule.cs | 3 +- .../Backend/NetworkGatewayModule.cs | 6 +- .../ChannelInteractionModule.cs | 20 ++--- .../Frontend/NetworkFrontendBridge.cs | 2 +- .../Frontend/RequestExtractor.cs | 25 +++--- mROA/Implementation/RemoteObjectBase.cs | 12 +-- mROA/Implementation/RepresentationModule.cs | 88 +++++++------------ mROA/Implementation/StreamExtractor.cs | 2 +- 10 files changed, 73 insertions(+), 95 deletions(-) rename mROA/Abstract/{IInteractionModule.cs => IChannelInteractionModule.cs} (69%) diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs index 64c6d86..6a36ef5 100644 --- a/mROA.Test/NextGenTest.cs +++ b/mROA.Test/NextGenTest.cs @@ -33,7 +33,7 @@ namespace mROA.Test Task.Run(() => { _listener.Start(); - _interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream(); + // _interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream(); foreach (var guid in guids) { @@ -43,7 +43,7 @@ namespace mROA.Test var client = new TcpClient(); client.Connect(IPAddress.Loopback, 4567); - _interactionModuleA.BaseStream = client.GetStream(); + // _interactionModuleA.BaseStream = client.GetStream(); var tasks = guids.Select(ReadStream); diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IChannelInteractionModule.cs similarity index 69% rename from mROA/Abstract/IInteractionModule.cs rename to mROA/Abstract/IChannelInteractionModule.cs index 4a884e8..e9030d1 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IChannelInteractionModule.cs @@ -9,15 +9,13 @@ namespace mROA.Abstract public interface IChannelInteractionModule : IInjectableModule, IDisposable { int ConnectionId { get; set; } - ChannelWriter ReceiveChanel { get; } + Channel ReceiveChanel { get; } ChannelReader TrustedPostChanel { get; } ChannelReader UntrustedPostChanel { get; } Func IsConnected { get; set; } - Task GetNextMessageReceiving(bool infinite = true); + ValueTask GetNextMessageReceiving(bool infinite = true); Task PostMessageAsync(NetworkMessageHeader messageHeader); Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader); - void HandleMessage(NetworkMessageHeader messageHeader); - NetworkMessageHeader? FirstByFilter(Predicate predicate); event Action OnDisconnected; Task Restart(bool sendRecovery); } diff --git a/mROA/Abstract/IRepresentationModule.cs b/mROA/Abstract/IRepresentationModule.cs index 2d9fc06..bca9a76 100644 --- a/mROA/Abstract/IRepresentationModule.cs +++ b/mROA/Abstract/IRepresentationModule.cs @@ -10,7 +10,8 @@ namespace mROA.Abstract { int Id { get; } - Task<(object parced, EMessageType originalType)> GetSingle(Predicate rule, CancellationToken token, + Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate rule, + CancellationToken token, params Func[] converter); IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, CancellationToken token, diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 52ac70c..c5d15b8 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -78,7 +78,7 @@ namespace mROA.Implementation.Backend var streamExtractor = new StreamExtractor(client.GetStream(), _serialization); interaction.IsConnected = () => streamExtractor.IsConnected; - streamExtractor.MessageReceived += message => interaction.ReceiveChanel.WriteAsync(message); + streamExtractor.MessageReceived = message => interaction.ReceiveChanel.Writer.WriteAsync(message); streamExtractor.SingleReceive(); var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; @@ -98,10 +98,8 @@ namespace mROA.Implementation.Backend var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); - streamExtractor = new StreamExtractor(client.GetStream(), _serialization); - streamExtractor.MessageReceived += message => recoveryInteraction.ReceiveChanel.WriteAsync(message); + streamExtractor.MessageReceived = message => recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message); - _ = streamExtractor.LoopedReceive(); recoveryInteraction.Restart(false); Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); break; diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index c3f637b..b52d385 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -14,7 +13,6 @@ namespace mROA.Implementation private readonly ChannelReader _receiveReader; private readonly ChannelWriter _trustedWriter; private readonly ChannelWriter _untrustedWriter; - private readonly Channel _inputChannel; private readonly Channel _outputTrustedChannel; private readonly Channel _outputUntrustedChannel; private readonly List _messageBuffer = new(128); @@ -26,13 +24,13 @@ namespace mROA.Implementation public ChannelInteractionModule() { - _inputChannel = Channel.CreateUnbounded(new UnboundedChannelOptions + ReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = false, SingleWriter = false, AllowSynchronousContinuations = true }); - _receiveReader = _inputChannel.Reader; + _receiveReader = ReceiveChanel.Reader; _outputTrustedChannel = Channel.CreateBounded(new BoundedChannelOptions(1) { SingleReader = true, @@ -52,7 +50,8 @@ namespace mROA.Implementation public int ConnectionId { get; set; } - public ChannelWriter ReceiveChanel => _inputChannel.Writer; + public Channel ReceiveChanel { get; } + public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; public Func IsConnected { get; set; } @@ -71,12 +70,12 @@ namespace mROA.Implementation } } - public Task GetNextMessageReceiving(bool infinite = true) + public ValueTask GetNextMessageReceiving(bool infinite = true) { - if (!infinite) return _receiveReader.ReadAsync().AsTask(); - if (_currentReceiving != null) return _currentReceiving; - _currentReceiving = Task.Run(async () => await GetNextMessage()); - return _currentReceiving; + return _receiveReader.ReadAsync(); + // if (_currentReceiving != null) return _currentReceiving; + // _currentReceiving = Task.Run(async () => await GetNextMessage()); + // return _currentReceiving; } #pragma warning disable CS8602 // Dereference of a possibly null reference. private async ValueTask PostMessageInternal(NetworkMessageHeader messageHeader) @@ -192,6 +191,7 @@ namespace mROA.Implementation private async Task MakeRecovery(string source) { //TODO переделать реконнект + // Console.WriteLine("Staring recovery from {0}", source); // // lock (_reconnection) diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 4b98fab..f66281e 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -78,7 +78,7 @@ namespace mROA.Implementation.Frontend _ = _currentExtractor.SendFromChannel(_interactionModule.TrustedPostChanel, _rawExtractorCancellation.Token); - _currentExtractor.MessageReceived += message => _interactionModule.ReceiveChanel.WriteAsync(message); + _currentExtractor.MessageReceived = message => _interactionModule.ReceiveChanel.Writer.WriteAsync(message); } private async Task Reconnect() diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 5b348d9..f5616fc 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -47,6 +47,9 @@ namespace mROA.Implementation.Frontend public async Task StartExtraction() { ThrowIfNotInjected(); + + TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_representationModule.Id); + var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(_representationModule!.Id); @@ -54,11 +57,11 @@ namespace mROA.Implementation.Frontend try { #if TRACE - var sw = new Stopwatch(); + var sw = new Stopwatch(); #endif var streamTokenSource = new CancellationTokenSource(); - + var query = _representationModule!.GetStream(m => m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest or EMessageType.EventRequest or EMessageType.ClientDisconnect, streamTokenSource.Token, @@ -71,17 +74,18 @@ namespace mROA.Implementation.Frontend await foreach (var command in query) { #if TRACE - Console.WriteLine("Waiting for request..."); - if (sw.IsRunning) - { - sw.Stop(); - Console.WriteLine($"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds."); - } + Console.WriteLine("Waiting for request..."); + if (sw.IsRunning) + { + sw.Stop(); + Console.WriteLine( + $"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds."); + } #endif #if TRACE - Console.WriteLine("Request received"); - sw.Restart(); + Console.WriteLine("Request received"); + sw.Restart(); #endif switch (command.originalType) { @@ -95,7 +99,6 @@ namespace mROA.Implementation.Frontend break; case EMessageType.CancelRequest: HandleCancelRequest((command.parced as CancelRequest)!); - break; default: continue; diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 941cb52..c12a07b 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -82,14 +82,14 @@ namespace mROA.Implementation var response = await responseRequestTask; - if (response.parced is FinalCommandExecution successResponse) + if (response.Deserialized is FinalCommandExecution successResponse) { localTokenSource.Cancel(); return successResponse.Result!; } localTokenSource.Cancel(); - throw (response.parced as ExceptionCommandExecution)!.GetException(); + throw (response.Deserialized as ExceptionCommandExecution)!.GetException(); } protected async Task CallAsync(int methodId, object?[]? parameters = null, @@ -103,7 +103,7 @@ namespace mROA.Implementation var localTokenSource = new CancellationTokenSource(); - var responceRequestTask = _representationModule.GetSingle( + var responseRequestTask = _representationModule.GetSingle( m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, localTokenSource.Token, m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null, @@ -124,16 +124,16 @@ namespace mROA.Implementation }).ContinueWith(_ => localTokenSource.Cancel()); }); - var responseRequest = await responceRequestTask; + var responseRequest = await responseRequestTask; #if TRACE Console.WriteLine($"Handling message"); #endif - switch (responseRequest.originalType) + switch (responseRequest.MessageType) { case EMessageType.FinishedCommandExecution: return; case EMessageType.ExceptionCommandExecution: - throw (responseRequest.parced as ExceptionCommandExecution)!.GetException(); + throw (responseRequest.Deserialized as ExceptionCommandExecution)!.GetException(); } } diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 2e80308..acf8878 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -24,72 +26,48 @@ namespace mROA.Implementation } } - - + public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")) .ConnectionId; - public Task<(object parced, EMessageType originalType)> GetSingle(Predicate rule, CancellationToken token, params Func[] converter) + public async Task<(object? Deserialized, EMessageType MessageType)> GetSingle( + Predicate rule, + CancellationToken token = default, params Func[] converter) { - throw new NotImplementedException(); - } - - public IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, CancellationToken token, params Func[] converter) - { - throw new NotImplementedException(); - } - - public async Task GetMessageAsync(Guid? requestId, EMessageType? messageType, - CancellationToken token = default) - { - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is not initialized"); - - var rawMessage = await GetRawMessage(requestId, messageType, token); - return _serialization.Deserialize(rawMessage)!; - } - - public T GetMessage(Guid? requestId = null, EMessageType? messageType = null) - { - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is not initialized"); - - var rawMessage = GetRawMessage(requestId, messageType).GetAwaiter().GetResult(); - return _serialization.Deserialize(rawMessage)!; - } - - public async Task GetRawMessage(Guid? requestId = null, EMessageType? messageType = null, - CancellationToken token = default) - { - if (_interaction == null) - throw new NullReferenceException("Interaction toolkit is not initialized"); - - var fromBuffer = - _interaction.FirstByFilter(message => - (requestId is null || message.Id == requestId) && - (messageType is null || message.MessageType == messageType)); - - if (fromBuffer == null) + var writer = _interaction.ReceiveChanel.Writer; + await foreach (var message in _interaction.ReceiveChanel.Reader.ReadAllAsync(token)) { - while (token.IsCancellationRequested == false) + if (!rule(message)) { - var message = await _interaction.GetNextMessageReceiving(); - if ((requestId is not null && message.Id != requestId) || - (messageType is not null && message.MessageType != messageType)) - continue; - - _interaction.HandleMessage(message); - return message.Data; + await writer.WriteAsync(message, token); + continue; } + + var type = converter.Select(i => i(message)).First(i => i != null)!; + var deserialized = _serialization.Deserialize(message.Data, type); + return (deserialized, message.MessageType); } - if (fromBuffer == null) + return (null, EMessageType.Unknown); + } + + public async IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream( + Predicate rule, [EnumeratorCancellation] CancellationToken token = default, + params Func[] converter) + { + var writer = _interaction?.ReceiveChanel.Writer; + await foreach (var message in _interaction.ReceiveChanel.Reader.ReadAllAsync(token)) { - return Array.Empty(); - } + if (!rule(message)) + { + await writer.WriteAsync(message, token); + continue; + } - _interaction.HandleMessage(fromBuffer); - return fromBuffer.Data; + var type = converter.Select(i => i(message)).First(i => i != null)!; + var deserialized = _serialization.Deserialize(message.Data, type); + yield return (deserialized, message.MessageType)!; + } } public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull diff --git a/mROA/Implementation/StreamExtractor.cs b/mROA/Implementation/StreamExtractor.cs index 53d345d..5e748c0 100644 --- a/mROA/Implementation/StreamExtractor.cs +++ b/mROA/Implementation/StreamExtractor.cs @@ -21,7 +21,7 @@ namespace mROA.Implementation _serializationToolkit = serializationToolkit; } - public event Action MessageReceived; + public Action MessageReceived = _ => { }; private ushort ReadMessageLength() { From 23684d51de1e2740834ea3616548c35493c88ca7 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 2 May 2025 20:15:04 +0300 Subject: [PATCH 06/32] Surprisingly, it works on the channels --- Example.Frontend/Program.cs | 2 +- .../Backend/MultiClientOwnershipRepository.cs | 6 ++---- mROA/Implementation/Backend/NetworkGatewayModule.cs | 10 ++++++++-- mROA/Implementation/ChannelInteractionModule.cs | 6 +++--- mROA/Implementation/Frontend/NetworkFrontendBridge.cs | 11 +++++++---- mROA/Implementation/Frontend/RequestExtractor.cs | 7 +++++-- mROA/Implementation/RemoteContextRepository.cs | 2 +- mROA/Implementation/RepresentationModule.cs | 5 ++++- mROA/mROA.csproj | 2 +- 9 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index e87a449..8a5b163 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -45,7 +45,7 @@ class Program Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var context = builder.GetModule(); - var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory; + var factory = context.GetSingleObject(typeof(IPrinterFactory), -TransmissionConfig.OwnershipRepository.GetHostOwnershipId()) as IPrinterFactory; using (var disposingPrinter = factory.Create("Test")) { diff --git a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs index 56cd389..5bb5197 100644 --- a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs +++ b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs @@ -13,10 +13,8 @@ namespace mROA.Implementation.Backend return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0); } - public int GetHostOwnershipId() - { - return 0; - } + public int GetHostOwnershipId() => 0; + public void RegisterOwnership(int ownershipId) { diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index c5d15b8..b9f31af 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -78,7 +78,10 @@ namespace mROA.Implementation.Backend var streamExtractor = new StreamExtractor(client.GetStream(), _serialization); interaction.IsConnected = () => streamExtractor.IsConnected; - streamExtractor.MessageReceived = message => interaction.ReceiveChanel.Writer.WriteAsync(message); + streamExtractor.MessageReceived = message => + { + interaction.ReceiveChanel.Writer.WriteAsync(message); + }; streamExtractor.SingleReceive(); var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; @@ -98,7 +101,10 @@ namespace mROA.Implementation.Backend var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); - streamExtractor.MessageReceived = message => recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message); + streamExtractor.MessageReceived = message => + { + recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message); + }; recoveryInteraction.Restart(false); Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index b52d385..8671bf1 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -28,14 +28,14 @@ namespace mROA.Implementation { SingleReader = false, SingleWriter = false, - AllowSynchronousContinuations = true + // AllowSynchronousContinuations = true }); _receiveReader = ReceiveChanel.Reader; _outputTrustedChannel = Channel.CreateBounded(new BoundedChannelOptions(1) { SingleReader = true, SingleWriter = true, - AllowSynchronousContinuations = true, + // AllowSynchronousContinuations = true, }); _trustedWriter = _outputTrustedChannel.Writer; @@ -43,7 +43,7 @@ namespace mROA.Implementation { SingleReader = true, SingleWriter = true, - AllowSynchronousContinuations = true + // AllowSynchronousContinuations = true }); _untrustedWriter = _outputUntrustedChannel.Writer; } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index f66281e..4dab9de 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -49,11 +49,11 @@ namespace mROA.Implementation.Frontend _tcpClient.Connect(_serverEndPoint); PrepareExtractor(); - _interactionModule.IsConnected = () => _currentExtractor.IsConnected; + _interactionModule.IsConnected = () => _currentExtractor.IsConnected; _interactionModule.OnDisconnected += id => { Reconnect(); }; _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); - + _currentExtractor.SingleReceive(); var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); @@ -78,7 +78,10 @@ namespace mROA.Implementation.Frontend _ = _currentExtractor.SendFromChannel(_interactionModule.TrustedPostChanel, _rawExtractorCancellation.Token); - _currentExtractor.MessageReceived = message => _interactionModule.ReceiveChanel.Writer.WriteAsync(message); + _currentExtractor.MessageReceived = message => + { + _interactionModule.ReceiveChanel.Writer.WriteAsync(message); + }; } private async Task Reconnect() @@ -90,7 +93,7 @@ namespace mROA.Implementation.Frontend _rawExtractorCancellation = new CancellationTokenSource(); PrepareExtractor(); - + _ = _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token); await _interactionModule.Restart(true); diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index f5616fc..33fe375 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -48,11 +48,14 @@ namespace mROA.Implementation.Frontend { ThrowIfNotInjected(); - TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_representationModule.Id); - + var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(_representationModule!.Id); + if (multiClientOwnershipRepository is not null) + { + TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_representationModule.Id); + } try { diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 8c8ded5..43dceda 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -48,7 +48,7 @@ namespace mROA.Implementation throw new NullReferenceException("representation producer is not initialized"); var representationModule = - _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + _representationProducer.Produce(ownerId); _producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1, representationModule) as RemoteObjectBase)!); diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index acf8878..761472b 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -35,7 +35,10 @@ namespace mROA.Implementation CancellationToken token = default, params Func[] converter) { var writer = _interaction.ReceiveChanel.Writer; - await foreach (var message in _interaction.ReceiveChanel.Reader.ReadAllAsync(token)) + var reader = _interaction.ReceiveChanel.Reader; + + + await foreach (var message in reader.ReadAllAsync(token)) { if (!rule(message)) { diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index e52150a..3c172de 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - TRACE; + From 6812138eb18c8c07ada55778fcb324969847eff8 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 May 2025 14:32:21 +0300 Subject: [PATCH 07/32] Some strange IO Exception found --- Example.Frontend/Program.cs | 2 +- .../Backend/NetworkGatewayModule.cs | 18 +- .../ChannelInteractionModule.cs | 205 ++++++++++++------ .../Frontend/NetworkFrontendBridge.cs | 13 +- mROA/Implementation/StreamExtractor.cs | 95 -------- mROA/mROA.csproj | 2 +- 6 files changed, 154 insertions(+), 181 deletions(-) delete mode 100644 mROA/Implementation/StreamExtractor.cs diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 8a5b163..cf79fd0 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -58,7 +58,7 @@ class Program Console.WriteLine("Printer created"); Thread.Sleep(100); - // frontendBridge.Obstacle(); + frontendBridge.Obstacle(); var name = disposingPrinter.GetName(); DemoCheck.BasicNonParamsCall = true; Console.WriteLine("Printer name : {0}", name); diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index b9f31af..1fe4169 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -75,17 +75,14 @@ namespace mROA.Implementation.Backend interaction!.Inject(_serialization); - - var streamExtractor = new StreamExtractor(client.GetStream(), _serialization); - interaction.IsConnected = () => streamExtractor.IsConnected; - streamExtractor.MessageReceived = message => - { - interaction.ReceiveChanel.Writer.WriteAsync(message); - }; + + var streamExtractor = new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization); + interaction.IsConnected = () => streamExtractor.IsConnected; + streamExtractor.MessageReceived = message => { interaction.ReceiveChanel.Writer.WriteAsync(message); }; streamExtractor.SingleReceive(); var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; - + switch (connectionRequest.MessageType) { case EMessageType.ClientConnect: @@ -101,10 +98,13 @@ namespace mROA.Implementation.Backend var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); + recoveryInteraction.IsConnected = () => streamExtractor.IsConnected; streamExtractor.MessageReceived = message => { recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message); }; + Task.Run(async () => await streamExtractor.LoopedReceive()); + recoveryInteraction.Restart(false); Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); @@ -116,7 +116,7 @@ namespace mROA.Implementation.Backend } } } - + private void ThrowIfNotInjected() { if (_hub is null) diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index 8671bf1..e706dfb 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; @@ -28,24 +29,21 @@ namespace mROA.Implementation { SingleReader = false, SingleWriter = false, - // AllowSynchronousContinuations = true }); _receiveReader = ReceiveChanel.Reader; _outputTrustedChannel = Channel.CreateBounded(new BoundedChannelOptions(1) { SingleReader = true, SingleWriter = true, - // AllowSynchronousContinuations = true, - }); _trustedWriter = _outputTrustedChannel.Writer; _outputUntrustedChannel = Channel.CreateUnbounded(new UnboundedChannelOptions { SingleReader = true, SingleWriter = true, - // AllowSynchronousContinuations = true }); _untrustedWriter = _outputUntrustedChannel.Writer; + _reconnection = new TaskCompletionSource(); } public int ConnectionId { get; set; } @@ -84,7 +82,7 @@ namespace mROA.Implementation { return false; } - + await _trustedWriter.WriteAsync(messageHeader); return true; } @@ -125,13 +123,6 @@ namespace mROA.Implementation await _untrustedWriter.WriteAsync(messageHeader); } - public void HandleMessage(NetworkMessageHeader messageHeader) - { - _messageBuffer.Remove(messageHeader); - } - - // public NetworkMessageHeader[] UnhandledMessages => _messageBuffer.ToArray(); - public NetworkMessageHeader? FirstByFilter(Predicate predicate) { return _messageBuffer.FirstOrDefault(m => predicate(m)); @@ -139,44 +130,18 @@ namespace mROA.Implementation public event Action? OnDisconnected; - private async Task GetNextMessage() - { - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is null"); - - bool withError = false; - - while (true) - { - if (withError) - { - Console.WriteLine("Receive again"); - } - - try - { - var message = await _receiveReader.ReadAsync(); - return message; - } - catch (Exception) - { - if (!_isActive) - { - return NetworkMessageHeader.Null; - } - - withError = true; - await MakeRecovery("IN"); - } - } - } - public async Task Restart(bool sendRecovery) { if (sendRecovery) { await PostMessageAsync( new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)))); + var ping = await ReceiveChanel.Reader.ReadAsync(); + Console.WriteLine($"Ping received {ping.Id}"); + } + else + { + await _trustedWriter.WriteAsync(new NetworkMessageHeader()); } Console.WriteLine("Setting result for reconnection"); @@ -191,30 +156,25 @@ namespace mROA.Implementation private async Task MakeRecovery(string source) { //TODO переделать реконнект - - // Console.WriteLine("Staring recovery from {0}", source); - // - // lock (_reconnection) - // { - // Console.WriteLine("Got lock from {0}", source); - // - // Console.WriteLine("Call OnDisconnected from {0}", source); - // _isInReconnectionState = true; - // OnDisconnected?.Invoke(ConnectionId); - // } - // - // Console.WriteLine("Waiting for reconnect from {0}", source); - // if (!_reconnection.Task.IsCompleted && !_isConnected) - // { - // Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); - // await _reconnection.Task; - // } - // - // Console.WriteLine("Reconnect finished from {0}", source); - // lock (_reconnection) - // { - // _isInReconnectionState = false; - // } + + Console.WriteLine("Staring recovery from {0}", source); + + lock (_reconnection) + { + Console.WriteLine("Got lock from {0}", source); + + Console.WriteLine("Call OnDisconnected from {0}", source); + OnDisconnected?.Invoke(ConnectionId); + } + + Console.WriteLine("Waiting for reconnect from {0}", source); + if (!_reconnection.Task.IsCompleted && !_isConnected) + { + Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); + await _reconnection.Task; + } + + Console.WriteLine("Reconnect finished from {0}", source); } public void Dispose() @@ -226,5 +186,114 @@ namespace mROA.Implementation _currentReceiving?.Dispose(); } } + + public class StreamExtractor + { + private readonly Stream _ioStream; + private readonly ISerializationToolkit _serializationToolkit; + private const int BufferSize = ushort.MaxValue; + private readonly Memory _buffer = new byte[BufferSize]; + private bool _manualConnectionState = true; + + public readonly int Id = new Random().Next(); + + public StreamExtractor(Stream ioStream, ISerializationToolkit serializationToolkit) + { + _ioStream = ioStream; + _serializationToolkit = serializationToolkit; + } + + public Action MessageReceived = _ => { }; + + private ushort ReadMessageLength() + { + var firstBit = _ioStream.ReadByte(); + if (firstBit == -1) + { + _manualConnectionState = false; + throw new EndOfStreamException(); + } + + _manualConnectionState = true; + var secondBit = (byte)_ioStream.ReadByte(); + + var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit }); + + return len; + } + + public async Task SingleReceive(CancellationToken Token = default) + { +#if TRACE + Console.WriteLine($"[{Id}] Single receive started"); +#endif + var len = ReadMessageLength(); + var localSpan = _buffer[..len]; + + await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); + + var message = _serializationToolkit.Deserialize(localSpan.Span); +#if TRACE + Console.WriteLine( + $"{DateTime.Now.TimeOfDay} [{Id}] Received Message {message.Id} - {message.MessageType}"); + TransmissionConfig.TotalTransmittedBytes += len; + Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); +#endif + MessageReceived(message); + } + + public async Task LoopedReceive(CancellationToken token = default) + { +#if TRACE + Console.WriteLine("LoopedReceive started"); +#endif + while (token.IsCancellationRequested == false && IsConnected) + { + await SingleReceive(token); + } + } + + public async Task Send(NetworkMessageHeader message, CancellationToken token = default) + { + try + { + var rawMessage = _serializationToolkit.Serialize(message); + var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); + +#if TRACE + Console.WriteLine( + $"{DateTime.Now.TimeOfDay} [{Id}] Posting Message {message.Id} - {message.MessageType}"); + TransmissionConfig.TotalTransmittedBytes += rawMessage.Length; + Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); +#endif + + await _ioStream.WriteAsync(header, token); + await _ioStream.WriteAsync(rawMessage, token); +#if TRACE + Console.WriteLine( + $"{DateTime.Now.TimeOfDay} [{Id}] Posting finished {message.Id} - {message.MessageType}"); + +#endif + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + + public async Task SendFromChannel(ChannelReader channel, + CancellationToken token = default) + { + while (token.IsCancellationRequested == false && IsConnected) + { + var message = await channel.ReadAsync(token); + await Send(message, token); + } + } + + + public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState; + } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 4dab9de..fdbface 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -17,7 +17,7 @@ namespace mROA.Implementation.Frontend private TcpClient _tcpClient = new(); private IChannelInteractionModule? _interactionModule; private ISerializationToolkit? _serialization; - private StreamExtractor _currentExtractor; + private ChannelInteractionModule.StreamExtractor _currentExtractor; private CancellationTokenSource _rawExtractorCancellation; public NetworkFrontendBridge(IPEndPoint serverEndPoint) @@ -50,7 +50,7 @@ namespace mROA.Implementation.Frontend PrepareExtractor(); _interactionModule.IsConnected = () => _currentExtractor.IsConnected; - _interactionModule.OnDisconnected += id => { Reconnect(); }; + _interactionModule.OnDisconnected += _ => { Reconnect(); }; _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); @@ -64,8 +64,7 @@ namespace mROA.Implementation.Frontend } - var stopToken = _rawExtractorCancellation.Token; - Task.Run(async () => await _currentExtractor.LoopedReceive(stopToken)); + Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token)); var assignment = _serialization.Deserialize(idMessage.Data)!; _interactionModule.ConnectionId = -assignment.Id; @@ -74,9 +73,9 @@ namespace mROA.Implementation.Frontend private void PrepareExtractor() { - _currentExtractor = new StreamExtractor(_tcpClient.GetStream(), _serialization); + _currentExtractor = new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!); - _ = _currentExtractor.SendFromChannel(_interactionModule.TrustedPostChanel, + _ = _currentExtractor.SendFromChannel(_interactionModule!.TrustedPostChanel, _rawExtractorCancellation.Token); _currentExtractor.MessageReceived = message => { @@ -94,7 +93,7 @@ namespace mROA.Implementation.Frontend PrepareExtractor(); - _ = _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token); + Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token)); await _interactionModule.Restart(true); } diff --git a/mROA/Implementation/StreamExtractor.cs b/mROA/Implementation/StreamExtractor.cs deleted file mode 100644 index 5e748c0..0000000 --- a/mROA/Implementation/StreamExtractor.cs +++ /dev/null @@ -1,95 +0,0 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using mROA.Abstract; - -namespace mROA.Implementation -{ - public class StreamExtractor - { - private readonly Stream _ioStream; - private readonly ISerializationToolkit _serializationToolkit; - private const int BufferSize = ushort.MaxValue; - private readonly Memory _buffer = new byte[BufferSize]; - private bool _manualConnectionState = true; - - public StreamExtractor(Stream ioStream, ISerializationToolkit serializationToolkit) - { - _ioStream = ioStream; - _serializationToolkit = serializationToolkit; - } - - public Action MessageReceived = _ => { }; - - private ushort ReadMessageLength() - { - var firstBit = _ioStream.ReadByte(); - if (firstBit == -1) - { - _manualConnectionState = false; - throw new EndOfStreamException(); - } - - _manualConnectionState = true; - var secondBit = (byte)_ioStream.ReadByte(); - - var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit }); - - return len; - } - - public async Task SingleReceive(CancellationToken Token = default) - { - var len = ReadMessageLength(); - var localSpan = _buffer[..len]; - - await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); - - var message = _serializationToolkit.Deserialize(localSpan.Span); -#if TRACE - Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.MessageType}"); - TransmissionConfig.TotalTransmittedBytes += len; - Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); -#endif - MessageReceived(message); - } - - public async Task LoopedReceive(CancellationToken token = default) - { - while (token.IsCancellationRequested == false && IsConnected) - { - await SingleReceive(token); - } - } - - public async Task Send(NetworkMessageHeader message, CancellationToken token = default) - { - var rawMessage = _serializationToolkit.Serialize(message); - var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); - -#if TRACE - Console.WriteLine($"{DateTime.Now.TimeOfDay} Posting Message {message.Id} - {message.MessageType}"); - TransmissionConfig.TotalTransmittedBytes += rawMessage.Length; - Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); -#endif - - await _ioStream.WriteAsync(header, token); - await _ioStream.WriteAsync(rawMessage, token); - } - - public async Task SendFromChannel(ChannelReader channel, - CancellationToken token = default) - { - while (token.IsCancellationRequested == false && IsConnected) - { - var message = await channel.ReadAsync(token); - await Send(message, token); - } - } - - - public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState; - } -} \ No newline at end of file diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 3c172de..e52150a 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - + TRACE; From f62a4943b9db0864c67b1cdc7be94b905d977f9b Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 May 2025 14:54:06 +0300 Subject: [PATCH 08/32] Reconnection bug solved --- .../Backend/NetworkGatewayModule.cs | 16 ++++++++++++---- mROA/Implementation/ChannelInteractionModule.cs | 3 +-- mROA/mROA.csproj | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 1fe4169..b01786c 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; @@ -15,6 +16,7 @@ namespace mROA.Implementation.Backend private readonly TcpListener _tcpListener; private IConnectionHub? _hub; private ISerializationToolkit? _serialization; + private Dictionary _extractorsCTS = new(); public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules) @@ -82,14 +84,16 @@ namespace mROA.Implementation.Backend streamExtractor.SingleReceive(); var connectionRequest = interaction.GetNextMessageReceiving(false) .GetAwaiter().GetResult()!; + var cts = new CancellationTokenSource(); switch (connectionRequest.MessageType) { case EMessageType.ClientConnect: - Task.Run(async () => await streamExtractor.LoopedReceive()); - streamExtractor.SendFromChannel(interaction.TrustedPostChanel); + Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); + _ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, new IdAssignment { Id = -interaction.ConnectionId })); + _extractorsCTS[interaction.ConnectionId] = cts; _hub!.RegisterInteraction(interaction); Console.WriteLine("Client registered"); break; @@ -97,13 +101,17 @@ namespace mROA.Implementation.Backend { var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); - + + _extractorsCTS[recoveryRequest.Id].Cancel(); + recoveryInteraction.IsConnected = () => streamExtractor.IsConnected; streamExtractor.MessageReceived = message => { recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message); }; - Task.Run(async () => await streamExtractor.LoopedReceive()); + _ = streamExtractor.SendFromChannel(recoveryInteraction.TrustedPostChanel, cts.Token); + + Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); recoveryInteraction.Restart(false); diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index e706dfb..4657c62 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -53,8 +53,7 @@ namespace mROA.Implementation public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; public Func IsConnected { get; set; } - - + public void Inject(T dependency) { switch (dependency) diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index e52150a..c0682c2 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - TRACE; + ; From 4f18f41389f361fd8f0f540e2af026697dfafd21 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 May 2025 21:43:02 +0300 Subject: [PATCH 09/32] Client udp service --- Example.Backend/Printer.cs | 5 ++ Example.Frontend/ClientBasedPrinter.cs | 5 ++ Example.Frontend/Program.cs | 2 + Example.Shared/IPrinter.cs | 2 + mROA.Codegen/mROASourceGenerator.cs | 42 ++++++++---- mROA/Abstract/IRepresentationModule.cs | 1 + mROA/Abstract/IUntrustedInteractionModule.cs | 11 ++++ .../Attributes/UntrustedAttribute.cs | 8 +++ mROA/Implementation/RemoteObjectBase.cs | 9 +++ mROA/Implementation/RepresentationModule.cs | 9 ++- .../Implementation/UdpUntrustedInteraction.cs | 64 +++++++++++++++++++ 11 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 mROA/Abstract/IUntrustedInteractionModule.cs create mode 100644 mROA/Implementation/Attributes/UntrustedAttribute.cs create mode 100644 mROA/Implementation/UdpUntrustedInteraction.cs diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 87958c9..dba9a98 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,6 +10,11 @@ namespace Example.Backend { public string Name; + public async Task SomeoneIsApproaching(string humanName) + { + Console.WriteLine(humanName + " is approaching"); + } + public void OnPrintExternal(IPage p0, RequestContext ro) { OnPrint?.Invoke(p0, ro); diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 6afc7a3..1233514 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,6 +8,11 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { + public Task SomeoneIsApproaching(string humanName) + { + return Task.CompletedTask; + } + public void OnPrintExternal(IPage p0, RequestContext ro) { } diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index cf79fd0..97e7880 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -120,6 +121,7 @@ class Program DemoCheck.Show(); Console.ReadKey(); + // // const int iterations = 10000; // var timer = Stopwatch.StartNew(); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index f5b25f0..505d614 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -13,5 +13,7 @@ namespace Example.Shared string GetName(); Task Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken); event Action OnPrint; + [Untrusted] + Task SomeoneIsApproaching(string humanName); } } \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 6329ab2..9f05e44 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -291,23 +291,38 @@ namespace mROA.Codegen $"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{"); + var isUntrusted = method.GetAttributes().Any(i => i.AttributeClass.Name == "UntrustedAttribute"); + var prefix = isAsync ? "await " : ""; var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : ""; var parameterLink = isParametrized ? ", new System.Object[] { " + string.Join(", ", parameters.Select(i => i.Name)) + " }" : string.Empty; - var tokenInsert = isAsync && method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is - { } tokenSymbol - ? ", cancellationToken : " + tokenSymbol.Name - : string.Empty; - var caller = isVoid - ? $"CallAsync({index}{parameterLink}{tokenInsert})" - : isAsync - ? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink}{tokenInsert})" - : $"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink}{tokenInsert})"; - if (!isVoid) - prefix = "return " + prefix; + string caller; + + if (isUntrusted) + { + caller = $"CallUntrustedAsync({index}{parameterLink})"; + } + else + { + var tokenInsert = isAsync && + method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is + { } tokenSymbol + ? ", cancellationToken : " + tokenSymbol.Name + : string.Empty; + + caller = isVoid + ? $"CallAsync({index}{parameterLink}{tokenInsert})" + : isAsync + ? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink}{tokenInsert})" + : $"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink}{tokenInsert})"; + + if (!isVoid) + prefix = "return " + prefix; + + } sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";"); @@ -482,8 +497,8 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}"); var parameterInserts = string.Join(", ", - method.Parameters.Select( - p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); + method.Parameters.Select(p => + Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]"))); var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone(); invokerTemplate.AddDefine("isVoid", "false"); @@ -612,7 +627,6 @@ namespace mROA.Codegen return parts.ToUnityString(); return type.ToDisplayString(); - } public static string ToUnityString(this IParameterSymbol parameter) diff --git a/mROA/Abstract/IRepresentationModule.cs b/mROA/Abstract/IRepresentationModule.cs index bca9a76..be692ea 100644 --- a/mROA/Abstract/IRepresentationModule.cs +++ b/mROA/Abstract/IRepresentationModule.cs @@ -19,6 +19,7 @@ namespace mROA.Abstract Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull; void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull; + Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull; void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType); } } \ No newline at end of file diff --git a/mROA/Abstract/IUntrustedInteractionModule.cs b/mROA/Abstract/IUntrustedInteractionModule.cs new file mode 100644 index 0000000..151902b --- /dev/null +++ b/mROA/Abstract/IUntrustedInteractionModule.cs @@ -0,0 +1,11 @@ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace mROA.Abstract +{ + public interface IUntrustedInteractionModule : IInjectableModule, IDisposable + { + Task Start(IPEndPoint endpoint); + } +} \ No newline at end of file diff --git a/mROA/Implementation/Attributes/UntrustedAttribute.cs b/mROA/Implementation/Attributes/UntrustedAttribute.cs new file mode 100644 index 0000000..2441590 --- /dev/null +++ b/mROA/Implementation/Attributes/UntrustedAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace mROA.Implementation.Attributes +{ + public class UntrustedAttribute : Attribute + { + } +} \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index c12a07b..264fd4b 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -137,6 +137,15 @@ namespace mROA.Implementation } } + protected async Task CallUntrustedAsync(int methodId, object?[]? parameters = null) + { + var request = new DefaultCallRequest + { + CommandId = methodId, ObjectId = _identifier, Parameters = parameters + }; + await _representationModule.PostCallMessageUntrustedAsync(request.Id, EMessageType.CallRequest, request); + } + public override string ToString() { return _identifier.ToString(); diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 761472b..d2f01e9 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -37,7 +37,7 @@ namespace mROA.Implementation var writer = _interaction.ReceiveChanel.Writer; var reader = _interaction.ReceiveChanel.Reader; - + await foreach (var message in reader.ReadAllAsync(token)) { if (!rule(message)) @@ -95,6 +95,13 @@ namespace mROA.Implementation PostCallMessageAsync(id, eMessageType, payload).GetAwaiter().GetResult(); } + public async Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull + { + var serialized = _serialization.Serialize(payload, typeof(T)); + await _interaction.PostMessageUntrustedAsync(new NetworkMessageHeader + { Id = id, MessageType = eMessageType, Data = serialized }); + } + public void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType) { PostCallMessageAsync(id, eMessageType, payload, payloadType).GetAwaiter().GetResult(); diff --git a/mROA/Implementation/UdpUntrustedInteraction.cs b/mROA/Implementation/UdpUntrustedInteraction.cs new file mode 100644 index 0000000..84e067d --- /dev/null +++ b/mROA/Implementation/UdpUntrustedInteraction.cs @@ -0,0 +1,64 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using mROA.Abstract; + +namespace mROA.Implementation +{ + public class UdpUntrustedInteraction : IUntrustedInteractionModule + { + private ISerializationToolkit _serializationToolkit; + private IChannelInteractionModule _channelInteractionModule; + private CancellationTokenSource _tokenSource = new CancellationTokenSource(); + public void Dispose() + { + _tokenSource.Cancel(); + } + + public Task Start(IPEndPoint endpoint) + { + return Task.Run(() => + { + var client = new UdpClient(); + client.Connect(endpoint); + Listening(client, _tokenSource.Token); + Posting(client, _tokenSource.Token); + }, _tokenSource.Token); + } + + private async Task Listening(UdpClient udpClient, CancellationToken token) + { + var writer = _channelInteractionModule.ReceiveChanel.Writer; + while (token.IsCancellationRequested == false) + { + var message = new Memory((await udpClient.ReceiveAsync()).Buffer); + var parsed = _serializationToolkit.Deserialize(message.Span)!; + await writer.WriteAsync(parsed, token); + } + } + + private async Task Posting(UdpClient udpClient, CancellationToken token) + { + await foreach (var post in _channelInteractionModule.UntrustedPostChanel.ReadAllAsync(token)) + { + var serialized = _serializationToolkit.Serialize(post); + await udpClient.SendAsync(serialized, serialized.Length); + } + } + + public void Inject(T dependency) + { + switch (dependency) + { + case IChannelInteractionModule channelModule: + _channelInteractionModule = channelModule; + break; + case ISerializationToolkit serializationToolkit: + _serializationToolkit = serializationToolkit; + break; + } + } + } +} \ No newline at end of file From 8010677a8b39545467844eb416460d35d88a7674 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 May 2025 22:27:40 +0300 Subject: [PATCH 10/32] Untrusted channel works, but it breaks trusted channel --- Example.Backend/Program.cs | 11 ++- Example.Frontend/Program.cs | 19 +++- mROA/Abstract/IUntrustedGateway.cs | 11 +++ .../Backend/NetworkGatewayModule.cs | 4 +- mROA/Implementation/Backend/UdpGateway.cs | 92 +++++++++++++++++++ mROA/Implementation/EMessageType.cs | 1 + .../Implementation/UdpUntrustedInteraction.cs | 20 +++- mROA/mROA.csproj | 2 +- 8 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 mROA/Abstract/IUntrustedGateway.cs create mode 100644 mROA/Implementation/Backend/UdpGateway.cs diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 719d274..4f5a7ab 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -19,9 +19,10 @@ class Program builder.Modules.Add(new BackendIdentityGenerator()); // builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule), // builder.GetModule()!); - builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(ChannelInteractionModule), + var listening = new IPEndPoint(IPAddress.Loopback, 4567); + builder.UseNetworkGateway(listening, typeof(ChannelInteractionModule), builder.GetModule()!); - + builder.Modules.Add(new UdpGateway(listening)); builder.Modules.Add(new ConnectionHub()); builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor))); @@ -45,12 +46,12 @@ class Program builder.Build(); new RemoteTypeBinder(); - TransmissionConfig.RealContextRepository = builder.GetModule(); - TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule(); + TransmissionConfig.RealContextRepository = builder.GetModule()!; + TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule()!; TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository(); + _ = builder.GetModule()!.Start(); var gateway = builder.GetModule(); - gateway.Run(); } } \ No newline at end of file diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 97e7880..6dbf673 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -25,8 +25,10 @@ class Program builder.Modules.Add(new RemoteContextRepository()); builder.Modules.Add(new ChannelInteractionModule()); + builder.Modules.Add(new UdpUntrustedInteraction()); builder.Modules.Add(new RepresentationModule()); - builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567))); + var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 4567); + builder.Modules.Add(new NetworkFrontendBridge(serverEndPoint)); builder.Modules.Add(new StaticRepresentationModuleProducer()); builder.Modules.Add(new RequestExtractor()); builder.Modules.Add(new BasicExecutionModule()); @@ -43,10 +45,13 @@ class Program var frontendBridge = builder.GetModule()!; frontendBridge.Connect(); _ = builder.GetModule()!.StartExtraction(); + _ = builder.GetModule().Start(serverEndPoint); Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var context = builder.GetModule(); - var factory = context.GetSingleObject(typeof(IPrinterFactory), -TransmissionConfig.OwnershipRepository.GetHostOwnershipId()) as IPrinterFactory; + var factory = + context.GetSingleObject(typeof(IPrinterFactory), + -TransmissionConfig.OwnershipRepository.GetHostOwnershipId()) as IPrinterFactory; using (var disposingPrinter = factory.Create("Test")) { @@ -66,6 +71,9 @@ class Program Thread.Sleep(100); + disposingPrinter.SomeoneIsApproaching("Mikhail"); + Console.WriteLine("Approaching detected"); + factory.Register(new ClientBasedPrinter()); DemoCheck.ClientBasedImplementation = true; Console.WriteLine("Registered printer"); @@ -102,6 +110,7 @@ class Program Console.WriteLine("Dispose printer"); } + DemoCheck.Dispose = true; @@ -116,12 +125,12 @@ class Program cts.Cancel(); Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}"); DemoCheck.TaskCancelation = true; - + frontendBridge.Disconnect(); - + DemoCheck.Show(); Console.ReadKey(); - + // // const int iterations = 10000; // var timer = Stopwatch.StartNew(); diff --git a/mROA/Abstract/IUntrustedGateway.cs b/mROA/Abstract/IUntrustedGateway.cs new file mode 100644 index 0000000..9cb5fee --- /dev/null +++ b/mROA/Abstract/IUntrustedGateway.cs @@ -0,0 +1,11 @@ +using System; +using System.Net; +using System.Threading.Tasks; + +namespace mROA.Abstract +{ + public interface IUntrustedGateway : IInjectableModule, IDisposable + { + Task Start(); + } +} \ No newline at end of file diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index b01786c..9634fd1 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -18,6 +18,8 @@ namespace mROA.Implementation.Backend private ISerializationToolkit? _serialization; private Dictionary _extractorsCTS = new(); + + public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules) { @@ -124,7 +126,7 @@ namespace mROA.Implementation.Backend } } } - + private void ThrowIfNotInjected() { if (_hub is null) diff --git a/mROA/Implementation/Backend/UdpGateway.cs b/mROA/Implementation/Backend/UdpGateway.cs new file mode 100644 index 0000000..86806cf --- /dev/null +++ b/mROA/Implementation/Backend/UdpGateway.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; +using mROA.Abstract; + +namespace mROA.Implementation.Backend +{ + public class UdpGateway : IUntrustedGateway + { + private IConnectionHub _hub; + private UdpClient _client; + private Dictionary _reservedPorts = new(); + private CancellationTokenSource _tokenSource = new(); + private ISerializationToolkit _serializationToolkit; + + public UdpGateway(IPEndPoint listeningEndpoint) + { + _client = new UdpClient(listeningEndpoint); + } + + + public void Inject(T dependency) + { + switch (dependency) + { + case IConnectionHub hub: + _hub = hub; + break; + case ISerializationToolkit serializationToolkit: + _serializationToolkit = serializationToolkit; + break; + } + } + + public void Dispose() + { + _tokenSource.Cancel(); + _client.Close(); + } + + public Task Start() + { + var token = _tokenSource.Token; + return Task.Run(async () => + { + while (token.IsCancellationRequested == false) + { + var incoming = await _client.ReceiveAsync(); + var parsed = _serializationToolkit.Deserialize(incoming.Buffer); + try + { + int channelId; + switch (parsed.MessageType) + { + case EMessageType.UntrustedConnect: + channelId = BitConverter.ToInt32(parsed.Data); + _reservedPorts[incoming.RemoteEndPoint] = channelId; + _ = UntrustedSend(_hub.GetInteraction(channelId), incoming.RemoteEndPoint); + break; + default: + channelId = _reservedPorts[incoming.RemoteEndPoint]; + var interaction = _hub.GetInteraction(channelId); + await interaction.ReceiveChanel.Writer.WriteAsync(parsed, token); + break; + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + }, token); + } + + private Task UntrustedSend(IChannelInteractionModule interaction, IPEndPoint endpoint) + { + return Task.Run(async () => + { + await foreach (var post in interaction.UntrustedPostChanel.ReadAllAsync()) + { + var parsed = _serializationToolkit.Serialize(post); + await _client.SendAsync(parsed, parsed.Length, endpoint); + } + } + ); + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/EMessageType.cs b/mROA/Implementation/EMessageType.cs index bfb6304..d53aa72 100644 --- a/mROA/Implementation/EMessageType.cs +++ b/mROA/Implementation/EMessageType.cs @@ -12,5 +12,6 @@ namespace mROA.Implementation ClientRecovery, ClientConnect, ClientDisconnect, + UntrustedConnect, } } \ No newline at end of file diff --git a/mROA/Implementation/UdpUntrustedInteraction.cs b/mROA/Implementation/UdpUntrustedInteraction.cs index 84e067d..e66b526 100644 --- a/mROA/Implementation/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/UdpUntrustedInteraction.cs @@ -12,6 +12,7 @@ namespace mROA.Implementation private ISerializationToolkit _serializationToolkit; private IChannelInteractionModule _channelInteractionModule; private CancellationTokenSource _tokenSource = new CancellationTokenSource(); + public void Dispose() { _tokenSource.Cancel(); @@ -35,19 +36,36 @@ namespace mROA.Implementation { var message = new Memory((await udpClient.ReceiveAsync()).Buffer); var parsed = _serializationToolkit.Deserialize(message.Span)!; + await writer.WriteAsync(parsed, token); } } private async Task Posting(UdpClient udpClient, CancellationToken token) { + var initMessage = new NetworkMessageHeader + { + MessageType = EMessageType.UntrustedConnect, Id = Guid.NewGuid(), + Data = BitConverter.GetBytes(Math.Abs(_channelInteractionModule.ConnectionId)) + }; + + var initParsed = _serializationToolkit.Serialize(initMessage); + + await udpClient.SendAsync(initParsed, initParsed.Length); + await foreach (var post in _channelInteractionModule.UntrustedPostChanel.ReadAllAsync(token)) { var serialized = _serializationToolkit.Serialize(post); +#if TRACE + Console.WriteLine("Untrusted write start"); +#endif await udpClient.SendAsync(serialized, serialized.Length); +#if TRACE + Console.WriteLine("Untrusted write finished"); +#endif } } - + public void Inject(T dependency) { switch (dependency) diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index c0682c2..3c172de 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - ; + From eede4d28c444639284d2609d320ba6ca3dc50880 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 3 May 2025 23:09:32 +0300 Subject: [PATCH 11/32] Untrusted channel exception solved --- mROA.Codegen/MethodRepo.cstmpl | 2 ++ mROA.Codegen/mROASourceGenerator.cs | 11 ++++++ mROA/Abstract/IMethodInvoker.cs | 1 + .../Backend/BasicExecutionModule.cs | 36 ++++++++++++++----- mROA/Implementation/Backend/UdpGateway.cs | 9 +++-- .../{ => Frontend}/UdpUntrustedInteraction.cs | 6 +++- mROA/Implementation/MethodInvoker.cs | 2 ++ 7 files changed, 55 insertions(+), 12 deletions(-) rename mROA/Implementation/{ => Frontend}/UdpUntrustedInteraction.cs (92%) diff --git a/mROA.Codegen/MethodRepo.cstmpl b/mROA.Codegen/MethodRepo.cstmpl index b1c4a93..3860e42 100644 --- a/mROA.Codegen/MethodRepo.cstmpl +++ b/mROA.Codegen/MethodRepo.cstmpl @@ -17,6 +17,7 @@ namespace mROA.Codegen new mROA.Implementation.AsyncMethodInvoker { IsVoid = , + IsTrusted = , ReturnType = typeof(), ParameterTypes = new Type[] { }, SuitableType = typeof(), @@ -26,6 +27,7 @@ namespace mROA.Codegen new mROA.Implementation.MethodInvoker { IsVoid = , + IsTrusted = , ReturnType = typeof(), ParameterTypes = new Type[] { }, SuitableType = typeof(), diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 9f05e44..b2b9f26 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -380,6 +380,7 @@ namespace mROA.Codegen invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", funcInvoking); + invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); } else @@ -390,6 +391,7 @@ namespace mROA.Codegen invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", funcInvoking); + invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower()); backend = invokerTemplate.Compile(); } @@ -474,6 +476,7 @@ namespace mROA.Codegen invokerTemplate.AddDefine("parametersType", parameterTypes); invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", funcInvoking); + invokerTemplate.AddDefine("isTrusted", "true"); var backend = invokerTemplate.Compile(); _methodRepoTemplate.Insert("invoker", backend); @@ -507,6 +510,8 @@ namespace mROA.Codegen invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]"); + invokerTemplate.AddDefine("isTrusted", "true"); + backend = invokerTemplate.Compile(); } else @@ -517,6 +522,8 @@ namespace mROA.Codegen invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}"); + invokerTemplate.AddDefine("isTrusted", "true"); + backend = invokerTemplate.Compile(); } @@ -547,6 +554,8 @@ namespace mROA.Codegen invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}"); + invokerTemplate.AddDefine("isTrusted", "true"); + backend = invokerTemplate.Compile(); } else @@ -560,6 +569,8 @@ namespace mROA.Codegen invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString()); invokerTemplate.AddDefine("funcInvoking", $"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); + invokerTemplate.AddDefine("isTrusted", "true"); + backend = invokerTemplate.Compile(); } diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs index dcb04db..f151cae 100644 --- a/mROA/Abstract/IMethodInvoker.cs +++ b/mROA/Abstract/IMethodInvoker.cs @@ -5,6 +5,7 @@ namespace mROA.Abstract public interface IMethodInvoker { bool IsVoid { get; } + bool IsTrusted { get; } Type[] ParameterTypes { get; } Type? ReturnType { get; } Type SuitableType { get; } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index f184d20..fee9bbb 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -95,7 +95,8 @@ namespace mROA.Implementation.Backend } } - private static object GetContext(ICallRequest command, IContextRepository contextRepository, IMethodInvoker invoker) + private static object GetContext(ICallRequest command, IContextRepository contextRepository, + IMethodInvoker invoker) { var context = command.ObjectId.ContextId != -1 ? contextRepository.GetObject(command.ObjectId) @@ -147,7 +148,12 @@ namespace mROA.Implementation.Backend { var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext }); - if (invoker.IsVoid) + if (!invoker.IsTrusted) + { + return new AsyncCommandExecution(); + } + + if (invoker.IsVoid ) { return new FinalCommandExecution { @@ -163,10 +169,15 @@ namespace mROA.Implementation.Backend } catch (Exception e) { - return new ExceptionCommandExecution + if (invoker.IsTrusted) + return new ExceptionCommandExecution + { + Id = command.Id, + Exception = e.ToString() + }; + return new AsyncCommandExecution { - Id = command.Id, - Exception = e.ToString() + Id = command.Id }; } } @@ -198,7 +209,9 @@ namespace mROA.Implementation.Backend TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); - representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, payload); + if (invoker.IsTrusted) + representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, + payload); multiClientOwnershipRepository?.FreeOwnership(); }); @@ -209,10 +222,15 @@ namespace mROA.Implementation.Backend } catch (Exception e) { - return new ExceptionCommandExecution + if (invoker.IsTrusted) + return new ExceptionCommandExecution + { + Id = command.Id, + Exception = e.ToString() + }; + return new AsyncCommandExecution { - Id = command.Id, - Exception = e.ToString() + Id = command.Id }; } } diff --git a/mROA/Implementation/Backend/UdpGateway.cs b/mROA/Implementation/Backend/UdpGateway.cs index 86806cf..68be81a 100644 --- a/mROA/Implementation/Backend/UdpGateway.cs +++ b/mROA/Implementation/Backend/UdpGateway.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; +using static mROA.Implementation.EMessageType; namespace mROA.Implementation.Backend { @@ -56,12 +57,12 @@ namespace mROA.Implementation.Backend int channelId; switch (parsed.MessageType) { - case EMessageType.UntrustedConnect: + case UntrustedConnect: channelId = BitConverter.ToInt32(parsed.Data); _reservedPorts[incoming.RemoteEndPoint] = channelId; _ = UntrustedSend(_hub.GetInteraction(channelId), incoming.RemoteEndPoint); break; - default: + default: channelId = _reservedPorts[incoming.RemoteEndPoint]; var interaction = _hub.GetInteraction(channelId); await interaction.ReceiveChanel.Writer.WriteAsync(parsed, token); @@ -82,6 +83,10 @@ namespace mROA.Implementation.Backend { await foreach (var post in interaction.UntrustedPostChanel.ReadAllAsync()) { + if (post.MessageType is not (CallRequest or EMessageType.CancelRequest + or EventRequest)) + continue; + var parsed = _serializationToolkit.Serialize(post); await _client.SendAsync(parsed, parsed.Length, endpoint); } diff --git a/mROA/Implementation/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs similarity index 92% rename from mROA/Implementation/UdpUntrustedInteraction.cs rename to mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index e66b526..6dafb47 100644 --- a/mROA/Implementation/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; using mROA.Abstract; -namespace mROA.Implementation +namespace mROA.Implementation.Frontend { public class UdpUntrustedInteraction : IUntrustedInteractionModule { @@ -55,6 +55,10 @@ namespace mROA.Implementation await foreach (var post in _channelInteractionModule.UntrustedPostChanel.ReadAllAsync(token)) { + if (post.MessageType is not (EMessageType.CallRequest or EMessageType.CancelRequest + or EMessageType.EventRequest)) + continue; + var serialized = _serializationToolkit.Serialize(post); #if TRACE Console.WriteLine("Untrusted write start"); diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index 59efb7d..ff713db 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -6,6 +6,7 @@ namespace mROA.Implementation public class MethodInvoker : IMethodInvoker { public bool IsVoid { get; set; } + public bool IsTrusted { get; set; } = true; public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } public Func Invoking { get; set; } = (_, _, _) => null; @@ -32,6 +33,7 @@ namespace mROA.Implementation public class AsyncMethodInvoker : IMethodInvoker { public bool IsVoid { get; set; } + public bool IsTrusted { get; set; } = true; public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } public Type SuitableType { get; set; } From 9575f745f9febcce4da6d92b35b030bcae145255 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 19:43:15 +0300 Subject: [PATCH 12/32] Remove non-context serialization module --- mROA/Abstract/IChannelInteractionModule.cs | 1 + .../IContextualSerializationToolKit.cs | 5 +- mROA/Abstract/IEndPointContext.cs | 2 +- mROA/Abstract/IRepresentationModule.cs | 21 ++-- mROA/Abstract/ISerializationToolkit.cs | 22 ++-- .../Backend/BasicExecutionModule.cs | 4 +- mROA/Implementation/Backend/ConnectionHub.cs | 4 +- .../Backend/HubRequestExtractor.cs | 4 +- .../Backend/NetworkGatewayModule.cs | 4 +- mROA/Implementation/Backend/UdpGateway.cs | 4 +- .../ChannelInteractionModule.cs | 29 +++-- mROA/Implementation/EndPointContext.cs | 4 + .../Frontend/NetworkFrontendBridge.cs | 4 +- .../Frontend/RequestExtractor.cs | 4 +- .../Frontend/UdpUntrustedInteraction.cs | 4 +- .../JsonSerializationToolkit.cs | 108 +++++++++--------- mROA/Implementation/NetworkMessageHeader.cs | 2 +- mROA/Implementation/RemoteObjectBase.cs | 5 +- mROA/Implementation/RepresentationModule.cs | 38 +++--- 19 files changed, 138 insertions(+), 131 deletions(-) rename {mROA.Cbor => mROA/Abstract}/IContextualSerializationToolKit.cs (85%) diff --git a/mROA/Abstract/IChannelInteractionModule.cs b/mROA/Abstract/IChannelInteractionModule.cs index e9030d1..1abdb10 100644 --- a/mROA/Abstract/IChannelInteractionModule.cs +++ b/mROA/Abstract/IChannelInteractionModule.cs @@ -9,6 +9,7 @@ namespace mROA.Abstract public interface IChannelInteractionModule : IInjectableModule, IDisposable { int ConnectionId { get; set; } + IEndPointContext Context { get; set; } Channel ReceiveChanel { get; } ChannelReader TrustedPostChanel { get; } ChannelReader UntrustedPostChanel { get; } diff --git a/mROA.Cbor/IContextualSerializationToolKit.cs b/mROA/Abstract/IContextualSerializationToolKit.cs similarity index 85% rename from mROA.Cbor/IContextualSerializationToolKit.cs rename to mROA/Abstract/IContextualSerializationToolKit.cs index 957ca29..d027205 100644 --- a/mROA.Cbor/IContextualSerializationToolKit.cs +++ b/mROA/Abstract/IContextualSerializationToolKit.cs @@ -1,9 +1,8 @@ using System; -using mROA.Abstract; -namespace mROA.Cbor +namespace mROA.Abstract { - public interface IContextualSerializationToolKit : ISerializationToolkit + public interface IContextualSerializationToolKit { byte[] Serialize(object objectToSerialize, IEndPointContext? context); void Serialize(object objectToSerialize, Span destination, IEndPointContext? context); diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs index 0267321..494669e 100644 --- a/mROA/Abstract/IEndPointContext.cs +++ b/mROA/Abstract/IEndPointContext.cs @@ -1,6 +1,6 @@ namespace mROA.Abstract { - public interface IEndPointContext + public interface IEndPointContext : IInjectableModule { IContextRepository RealRepository { get; } IContextRepository RemoteRepository { get; } diff --git a/mROA/Abstract/IRepresentationModule.cs b/mROA/Abstract/IRepresentationModule.cs index be692ea..101b399 100644 --- a/mROA/Abstract/IRepresentationModule.cs +++ b/mROA/Abstract/IRepresentationModule.cs @@ -11,15 +11,20 @@ namespace mROA.Abstract int Id { get; } Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate rule, - CancellationToken token, - params Func[] converter); - - IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, CancellationToken token, + IEndPointContext? context, CancellationToken token = default, params Func[] converter); - Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull; - void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull; - Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull; - void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType); + IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate rule, + IEndPointContext? context, CancellationToken token = default, + params Func[] converter); + + Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) + where T : notnull; + + void PostCallMessage(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) + where T : notnull; + + Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) + where T : notnull; } } \ No newline at end of file diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs index 497c953..92b806a 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -2,15 +2,15 @@ namespace mROA.Abstract { - public interface ISerializationToolkit : IInjectableModule - { - byte[] Serialize(T objectToSerialize); - byte[] Serialize(object objectToSerialize, Type type); - T? Deserialize(byte[] rawData); - object? Deserialize(byte[] rawData, Type type); - T? Deserialize(Span rawData); - object? Deserialize(Span rawData, Type type); - T? Cast(object? nonCasted); - object? Cast(object? nonCasted, Type type); - } + // public interface IContextualSerializationToolKit : IInjectableModule + // { + // byte[] Serialize(T objectToSerialize); + // byte[] Serialize(object objectToSerialize, Type type); + // T? Deserialize(byte[] rawData); + // object? Deserialize(byte[] rawData, Type type); + // T? Deserialize(Span rawData); + // object? Deserialize(Span rawData, Type type); + // T? Cast(object? nonCasted); + // object? Cast(object? nonCasted, Type type); + // } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index fee9bbb..3264b52 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation.Backend { private ICancellationRepository? _cancellationRepo; private IMethodRepository? _methodRepo; - private ISerializationToolkit? _serialization; + private IContextualSerializationToolKit? _serialization; public void Inject(T dependency) { @@ -21,7 +21,7 @@ namespace mROA.Implementation.Backend case ICancellationRepository cancellationRepo: _cancellationRepo = cancellationRepo; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serialization = serializationToolkit; break; } diff --git a/mROA/Implementation/Backend/ConnectionHub.cs b/mROA/Implementation/Backend/ConnectionHub.cs index 22b7b6b..34c7064 100644 --- a/mROA/Implementation/Backend/ConnectionHub.cs +++ b/mROA/Implementation/Backend/ConnectionHub.cs @@ -7,7 +7,7 @@ namespace mROA.Implementation.Backend public class ConnectionHub : IConnectionHub { private readonly Dictionary _connections = new(); - private ISerializationToolkit? _serializationToolkit; + private IContextualSerializationToolKit? _serializationToolkit; public void RegisterInteraction(IChannelInteractionModule interaction) { @@ -31,7 +31,7 @@ namespace mROA.Implementation.Backend public void Inject(T dependency) { - if (dependency is ISerializationToolkit serializationToolkit) + if (dependency is IContextualSerializationToolKit serializationToolkit) _serializationToolkit = serializationToolkit; } } diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 71171de..7d760fe 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -10,7 +10,7 @@ namespace mROA.Implementation.Backend private IContextRepository? _contextRepository; private IContextRepository? _remoteContextRepository; private IMethodRepository? _methodRepository; - private ISerializationToolkit? _serializationToolkit; + private IContextualSerializationToolKit? _serializationToolkit; private IExecuteModule? _executeModule; private readonly Type _extractorType; @@ -37,7 +37,7 @@ namespace mROA.Implementation.Backend case IMethodRepository methodRepository: _methodRepository = methodRepository; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; case IExecuteModule executeModule: diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 9634fd1..9112bdd 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -15,7 +15,7 @@ namespace mROA.Implementation.Backend private readonly Type? _interactionModuleType; private readonly TcpListener _tcpListener; private IConnectionHub? _hub; - private ISerializationToolkit? _serialization; + private IContextualSerializationToolKit? _serialization; private Dictionary _extractorsCTS = new(); @@ -58,7 +58,7 @@ namespace mROA.Implementation.Backend case IConnectionHub interactionModule: _hub = interactionModule; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serialization = serializationToolkit; break; } diff --git a/mROA/Implementation/Backend/UdpGateway.cs b/mROA/Implementation/Backend/UdpGateway.cs index 68be81a..0bbcf5d 100644 --- a/mROA/Implementation/Backend/UdpGateway.cs +++ b/mROA/Implementation/Backend/UdpGateway.cs @@ -16,7 +16,7 @@ namespace mROA.Implementation.Backend private UdpClient _client; private Dictionary _reservedPorts = new(); private CancellationTokenSource _tokenSource = new(); - private ISerializationToolkit _serializationToolkit; + private IContextualSerializationToolKit _serializationToolkit; public UdpGateway(IPEndPoint listeningEndpoint) { @@ -31,7 +31,7 @@ namespace mROA.Implementation.Backend case IConnectionHub hub: _hub = hub; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; } diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index 4657c62..400f333 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Channels; using System.Threading.Tasks; @@ -16,13 +14,12 @@ namespace mROA.Implementation private readonly ChannelWriter _untrustedWriter; private readonly Channel _outputTrustedChannel; private readonly Channel _outputUntrustedChannel; - private readonly List _messageBuffer = new(128); private Task? _currentReceiving; - private ISerializationToolkit? _serialization; + private IContextualSerializationToolKit? _serialization; private bool _isConnected = true; private bool _isActive = true; private TaskCompletionSource _reconnection; - + public IEndPointContext Context { get; set; } public ChannelInteractionModule() { ReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions @@ -58,12 +55,15 @@ namespace mROA.Implementation { switch (dependency) { - case ISerializationToolkit toolkit: + case IContextualSerializationToolKit toolkit: _serialization = toolkit; break; case IIdentityGenerator identityGenerator: ConnectionId = identityGenerator.GetNextIdentity(); break; + case IEndPointContext endpointContext: + Context = endpointContext; + break; } } @@ -122,11 +122,6 @@ namespace mROA.Implementation await _untrustedWriter.WriteAsync(messageHeader); } - public NetworkMessageHeader? FirstByFilter(Predicate predicate) - { - return _messageBuffer.FirstOrDefault(m => predicate(m)); - } - public event Action? OnDisconnected; public async Task Restart(bool sendRecovery) @@ -189,17 +184,18 @@ namespace mROA.Implementation public class StreamExtractor { private readonly Stream _ioStream; - private readonly ISerializationToolkit _serializationToolkit; + private readonly IContextualSerializationToolKit _serializationToolkit; private const int BufferSize = ushort.MaxValue; private readonly Memory _buffer = new byte[BufferSize]; private bool _manualConnectionState = true; - + private IEndPointContext Context; public readonly int Id = new Random().Next(); - public StreamExtractor(Stream ioStream, ISerializationToolkit serializationToolkit) + public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit, IEndPointContext context) { _ioStream = ioStream; _serializationToolkit = serializationToolkit; + Context = context; } public Action MessageReceived = _ => { }; @@ -231,7 +227,7 @@ namespace mROA.Implementation await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); - var message = _serializationToolkit.Deserialize(localSpan.Span); + var message = _serializationToolkit.Deserialize(localSpan, Context); #if TRACE Console.WriteLine( $"{DateTime.Now.TimeOfDay} [{Id}] Received Message {message.Id} - {message.MessageType}"); @@ -254,9 +250,10 @@ namespace mROA.Implementation public async Task Send(NetworkMessageHeader message, CancellationToken token = default) { + try { - var rawMessage = _serializationToolkit.Serialize(message); + var rawMessage = _serializationToolkit.Serialize(message, Context); var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); #if TRACE diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index e6351e9..b249aeb 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -16,5 +16,9 @@ namespace mROA.Implementation // ReSharper disable once UnusedMember.Global set { OwnerFunc = () => value; } } + + public void Inject(T dependency) + { + } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index fdbface..e7ed3c6 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -16,7 +16,7 @@ namespace mROA.Implementation.Frontend private readonly IPEndPoint _serverEndPoint; private TcpClient _tcpClient = new(); private IChannelInteractionModule? _interactionModule; - private ISerializationToolkit? _serialization; + private IContextualSerializationToolKit? _serialization; private ChannelInteractionModule.StreamExtractor _currentExtractor; private CancellationTokenSource _rawExtractorCancellation; @@ -33,7 +33,7 @@ namespace mROA.Implementation.Frontend case ChannelInteractionModule interactionModule: _interactionModule = interactionModule; break; - case ISerializationToolkit toolkit: + case IContextualSerializationToolKit toolkit: _serialization = toolkit; break; } diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 33fe375..f38152e 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -16,7 +16,7 @@ namespace mROA.Implementation.Frontend private IContextRepository? _realContextRepository; private IContextRepository? _remoteContextRepository; private IRepresentationModule? _representationModule; - private ISerializationToolkit? _serializationToolkit; + private IContextualSerializationToolKit? _serializationToolkit; public void Inject(T dependency) { @@ -38,7 +38,7 @@ namespace mROA.Implementation.Frontend case IRepresentationModule representationModule: _representationModule = representationModule; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; } diff --git a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index 6dafb47..4ee2f00 100644 --- a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation.Frontend { public class UdpUntrustedInteraction : IUntrustedInteractionModule { - private ISerializationToolkit _serializationToolkit; + private IContextualSerializationToolKit _serializationToolkit; private IChannelInteractionModule _channelInteractionModule; private CancellationTokenSource _tokenSource = new CancellationTokenSource(); @@ -77,7 +77,7 @@ namespace mROA.Implementation.Frontend case IChannelInteractionModule channelModule: _channelInteractionModule = channelModule; break; - case ISerializationToolkit serializationToolkit: + case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; } diff --git a/mROA/Implementation/JsonSerializationToolkit.cs b/mROA/Implementation/JsonSerializationToolkit.cs index 61a3c7e..38f8c19 100644 --- a/mROA/Implementation/JsonSerializationToolkit.cs +++ b/mROA/Implementation/JsonSerializationToolkit.cs @@ -4,58 +4,58 @@ using mROA.Abstract; namespace mROA.Implementation { - public class JsonSerializationToolkit : ISerializationToolkit - { - public byte[] Serialize(T objectToSerialize) - { - return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize); - } - - public byte[] Serialize(object objectToSerialize, Type type) - { - return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type); - } - - public T? Deserialize(byte[] rawData) - { - return JsonSerializer.Deserialize(rawData); - } - - public object? Deserialize(byte[] rawData, Type type) - { - return JsonSerializer.Deserialize(rawData, type); - } - - public T? Deserialize(Span rawData) - { - return JsonSerializer.Deserialize(rawData); - } - - public object? Deserialize(Span rawData, Type type) - { - return JsonSerializer.Deserialize(rawData, type); - } - - public T Cast(object nonCasted) - { - return nonCasted switch - { - JsonElement jsonElement => jsonElement.Deserialize()!, - T casted => casted, - _ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName) - }; - } - - public object Cast(object nonCasted, Type type) - { - if (nonCasted is JsonElement jsonElement) - return jsonElement.Deserialize(type)!; - - throw new JsonException("Cannot cast object to type " + type.FullName); - } - - public void Inject(T dependency) - { - } - } + // public class JsonSerializationToolkit : IContextualSerializationToolKit + // { + // public byte[] Serialize(T objectToSerialize) + // { + // return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize); + // } + // + // public byte[] Serialize(object objectToSerialize, Type type) + // { + // return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type); + // } + // + // public T? Deserialize(byte[] rawData) + // { + // return JsonSerializer.Deserialize(rawData); + // } + // + // public object? Deserialize(byte[] rawData, Type type) + // { + // return JsonSerializer.Deserialize(rawData, type); + // } + // + // public T? Deserialize(Span rawData) + // { + // return JsonSerializer.Deserialize(rawData); + // } + // + // public object? Deserialize(Span rawData, Type type) + // { + // return JsonSerializer.Deserialize(rawData, type); + // } + // + // public T Cast(object nonCasted) + // { + // return nonCasted switch + // { + // JsonElement jsonElement => jsonElement.Deserialize()!, + // T casted => casted, + // _ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName) + // }; + // } + // + // public object Cast(object nonCasted, Type type) + // { + // if (nonCasted is JsonElement jsonElement) + // return jsonElement.Deserialize(type)!; + // + // throw new JsonException("Cannot cast object to type " + type.FullName); + // } + // + // public void Inject(T dependency) + // { + // } + // } } \ No newline at end of file diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index 61ecea2..db47fe9 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -34,7 +34,7 @@ namespace mROA.Implementation MessageType = EMessageType.Unknown; Data = Array.Empty(); } - public NetworkMessageHeader(ISerializationToolkit serializationToolkit, INetworkMessage networkMessage) + public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit, INetworkMessage networkMessage) { MessageType = networkMessage.MessageType; Data = serializationToolkit.Serialize(networkMessage); diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 264fd4b..89fb54e 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -1,4 +1,5 @@ using System; +using System.Net; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -10,6 +11,7 @@ namespace mROA.Implementation { public abstract class RemoteObjectBase : IDisposable { + private readonly IEndPointContext _context; public bool Equals(RemoteObjectBase other) { return _identifier.Equals(other._identifier); @@ -31,10 +33,11 @@ namespace mROA.Implementation private readonly ComplexObjectIdentifier _identifier; private readonly IRepresentationModule _representationModule; - protected RemoteObjectBase(int id, IRepresentationModule representationModule) + protected RemoteObjectBase(int id, IRepresentationModule representationModule, IEndPointContext context) { _identifier = new ComplexObjectIdentifier { ContextId = id, OwnerId = representationModule.Id }; _representationModule = representationModule; + _context = context; } public int Id => _identifier.ContextId; diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index d2f01e9..14db0fd 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -11,13 +11,13 @@ namespace mROA.Implementation public class RepresentationModule : IRepresentationModule { private IChannelInteractionModule? _interaction; - private ISerializationToolkit? _serialization; + private IContextualSerializationToolKit? _serialization; public void Inject(T dependency) { switch (dependency) { - case ISerializationToolkit toolkit: + case IContextualSerializationToolKit toolkit: _serialization = toolkit; break; case IChannelInteractionModule interactionModule: @@ -31,7 +31,7 @@ namespace mROA.Implementation .ConnectionId; public async Task<(object? Deserialized, EMessageType MessageType)> GetSingle( - Predicate rule, + Predicate rule, IEndPointContext? context, CancellationToken token = default, params Func[] converter) { var writer = _interaction.ReceiveChanel.Writer; @@ -47,7 +47,7 @@ namespace mROA.Implementation } var type = converter.Select(i => i(message)).First(i => i != null)!; - var deserialized = _serialization.Deserialize(message.Data, type); + var deserialized = _serialization.Deserialize(message.Data, type, context); return (deserialized, message.MessageType); } @@ -55,7 +55,7 @@ namespace mROA.Implementation } public async IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream( - Predicate rule, [EnumeratorCancellation] CancellationToken token = default, + Predicate rule, IEndPointContext? context, [EnumeratorCancellation] CancellationToken token = default, params Func[] converter) { var writer = _interaction?.ReceiveChanel.Writer; @@ -68,43 +68,41 @@ namespace mROA.Implementation } var type = converter.Select(i => i(message)).First(i => i != null)!; - var deserialized = _serialization.Deserialize(message.Data, type); + var deserialized = _serialization.Deserialize(message.Data, type, context); yield return (deserialized, message.MessageType)!; } } - public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull + public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload, + IEndPointContext? context) where T : notnull { - await PostCallMessageAsync(id, eMessageType, payload, typeof(T)); + await PostCallMessageAsync(id, eMessageType, payload, context); } - - public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType) + + public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, + IEndPointContext? context) { if (_interaction == null) throw new NullReferenceException("Interaction toolkit is not initialized"); if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - var serialized = _serialization.Serialize(payload, payloadType); + var serialized = _serialization.Serialize(payload, context); await _interaction.PostMessageAsync(new NetworkMessageHeader { Id = id, MessageType = eMessageType, Data = serialized }); } - public void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull + public void PostCallMessage(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull { - PostCallMessageAsync(id, eMessageType, payload).GetAwaiter().GetResult(); + PostCallMessageAsync(id, eMessageType, payload, context).GetAwaiter().GetResult(); } - public async Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull + public async Task PostCallMessageUntrustedAsync(Guid id, EMessageType eMessageType, T payload, + IEndPointContext? context) where T : notnull { - var serialized = _serialization.Serialize(payload, typeof(T)); + var serialized = _serialization.Serialize(payload, context); await _interaction.PostMessageUntrustedAsync(new NetworkMessageHeader { Id = id, MessageType = eMessageType, Data = serialized }); } - - public void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType) - { - PostCallMessageAsync(id, eMessageType, payload, payloadType).GetAwaiter().GetResult(); - } } } \ No newline at end of file From 75c5e5a328ecb9828dd03c0a86ee3afba875c4c7 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 19:44:41 +0300 Subject: [PATCH 13/32] Solved RemoteObjectBase.cs --- mROA/Implementation/RemoteObjectBase.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 89fb54e..efcbeed 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -12,6 +12,7 @@ namespace mROA.Implementation public abstract class RemoteObjectBase : IDisposable { private readonly IEndPointContext _context; + public bool Equals(RemoteObjectBase other) { return _identifier.Equals(other._identifier); @@ -59,12 +60,12 @@ namespace mROA.Implementation CommandId = methodId, ObjectId = _identifier, Parameters = parameters }; - await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request); + await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context); var localTokenSource = new CancellationTokenSource(); var responseRequestTask = _representationModule.GetSingle( - m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, + m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, _context, localTokenSource.Token, m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null, m => m.MessageType is EMessageType.ExceptionCommandExecution @@ -80,7 +81,7 @@ namespace mROA.Implementation new CancelRequest { Id = request.Id - }).ContinueWith(_ => localTokenSource.Cancel()); + }, _context).ContinueWith(_ => localTokenSource.Cancel()); }); var response = await responseRequestTask; @@ -102,12 +103,12 @@ namespace mROA.Implementation { CommandId = methodId, ObjectId = _identifier, Parameters = parameters }; - await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request); + await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context); var localTokenSource = new CancellationTokenSource(); var responseRequestTask = _representationModule.GetSingle( - m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, + m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, _context, localTokenSource.Token, m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null, m => m.MessageType is EMessageType.ExceptionCommandExecution @@ -124,7 +125,7 @@ namespace mROA.Implementation new CancelRequest { Id = request.Id - }).ContinueWith(_ => localTokenSource.Cancel()); + }, _context).ContinueWith(_ => localTokenSource.Cancel()); }); var responseRequest = await responseRequestTask; @@ -146,7 +147,8 @@ namespace mROA.Implementation { CommandId = methodId, ObjectId = _identifier, Parameters = parameters }; - await _representationModule.PostCallMessageUntrustedAsync(request.Id, EMessageType.CallRequest, request); + await _representationModule.PostCallMessageUntrustedAsync(request.Id, EMessageType.CallRequest, request, + _context); } public override string ToString() From 8f97e5b0a6798d908a958d37bfaaed8523eb9ef3 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 19:49:15 +0300 Subject: [PATCH 14/32] More modules solved --- mROA/Implementation/Backend/NetworkGatewayModule.cs | 2 +- mROA/Implementation/ChannelInteractionModule.cs | 2 +- .../Frontend/NetworkFrontendBridge.cs | 13 ++++++++----- mROA/Implementation/Frontend/RequestExtractor.cs | 9 ++++++--- mROA/Implementation/NetworkMessageHeader.cs | 5 +++-- 5 files changed, 19 insertions(+), 12 deletions(-) diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 9112bdd..ab3e85a 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -94,7 +94,7 @@ namespace mROA.Implementation.Backend Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); _ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, - new IdAssignment { Id = -interaction.ConnectionId })); + new IdAssignment { Id = -interaction.ConnectionId }, TODO)); _extractorsCTS[interaction.ConnectionId] = cts; _hub!.RegisterInteraction(interaction); Console.WriteLine("Client registered"); diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index 400f333..d8b999f 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -129,7 +129,7 @@ namespace mROA.Implementation if (sendRecovery) { await PostMessageAsync( - new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)))); + new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), Context)); var ping = await ReceiveChanel.Reader.ReadAsync(); Console.WriteLine($"Ping received {ping.Id}"); } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index e7ed3c6..eabc2bd 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -19,7 +19,7 @@ namespace mROA.Implementation.Frontend private IContextualSerializationToolKit? _serialization; private ChannelInteractionModule.StreamExtractor _currentExtractor; private CancellationTokenSource _rawExtractorCancellation; - + private IEndPointContext _context; public NetworkFrontendBridge(IPEndPoint serverEndPoint) { _serverEndPoint = serverEndPoint; @@ -36,6 +36,9 @@ namespace mROA.Implementation.Frontend case IContextualSerializationToolKit toolkit: _serialization = toolkit; break; + case IEndPointContext endPointContext: + _context = endPointContext; + break; } } @@ -52,7 +55,7 @@ namespace mROA.Implementation.Frontend _interactionModule.IsConnected = () => _currentExtractor.IsConnected; _interactionModule.OnDisconnected += _ => { Reconnect(); }; - _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait(); + _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect(), _context)).Wait(); _currentExtractor.SingleReceive(); var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); @@ -66,14 +69,14 @@ namespace mROA.Implementation.Frontend Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token)); - var assignment = _serialization.Deserialize(idMessage.Data)!; + var assignment = _serialization.Deserialize(idMessage.Data, _context)!; _interactionModule.ConnectionId = -assignment.Id; TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); } private void PrepareExtractor() { - _currentExtractor = new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!); + _currentExtractor = new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!, _context); _ = _currentExtractor.SendFromChannel(_interactionModule!.TrustedPostChanel, _rawExtractorCancellation.Token); @@ -105,7 +108,7 @@ namespace mROA.Implementation.Frontend public void Disconnect() { - _ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect())); + _ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect(), _context)); _interactionModule.Dispose(); _tcpClient.Dispose(); } diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index f38152e..8822cb4 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -17,7 +17,7 @@ namespace mROA.Implementation.Frontend private IContextRepository? _remoteContextRepository; private IRepresentationModule? _representationModule; private IContextualSerializationToolKit? _serializationToolkit; - + private IEndPointContext _context; public void Inject(T dependency) { switch (dependency) @@ -41,6 +41,9 @@ namespace mROA.Implementation.Frontend case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; + case IEndPointContext remoteContext: + _context = remoteContext; + break; } } @@ -67,7 +70,7 @@ namespace mROA.Implementation.Frontend var query = _representationModule!.GetStream(m => m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest - or EMessageType.EventRequest or EMessageType.ClientDisconnect, streamTokenSource.Token, + or EMessageType.EventRequest or EMessageType.ClientDisconnect, _context, streamTokenSource.Token, m => m.MessageType == EMessageType.CallRequest ? typeof(DefaultCallRequest) : null, m => m.MessageType == EMessageType.CancelRequest ? typeof(CancelRequest) : null, m => m.MessageType == EMessageType.EventRequest ? typeof(DefaultCallRequest) : null, @@ -144,7 +147,7 @@ namespace mROA.Implementation.Frontend return; } - _representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType()); + _representationModule!.PostCallMessage(request.Id, resultType, result, _context); } private void HandleEventRequest(DefaultCallRequest request) diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index db47fe9..dee20f1 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -34,10 +34,11 @@ namespace mROA.Implementation MessageType = EMessageType.Unknown; Data = Array.Empty(); } - public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit, INetworkMessage networkMessage) + public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit, + INetworkMessage networkMessage, IEndPointContext context) { MessageType = networkMessage.MessageType; - Data = serializationToolkit.Serialize(networkMessage); + Data = serializationToolkit.Serialize(networkMessage, context); Id = Guid.NewGuid(); } public Guid Id { get; set; } From 149ea07569e9866568eb50ed0d942697d5512561 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 20:14:46 +0300 Subject: [PATCH 15/32] Execution module solved --- mROA.Test/CborTest.cs | 125 -------------- mROA.Test/FrontendFinalTest.cs | 92 ----------- mROA.Test/NextGenTest.cs | 79 --------- mROA.Test/StreamTest.cs | 65 -------- mROA.Test/UnSOization.cs | 26 --- mROA.Test/UnitTest1.cs | 154 ------------------ mROA/Abstract/IExecuteModule.cs | 2 +- .../Backend/BasicExecutionModule.cs | 20 +-- mROA/Implementation/Backend/UdpGateway.cs | 9 +- .../Frontend/RequestExtractor.cs | 6 +- .../Frontend/UdpUntrustedInteraction.cs | 2 +- 11 files changed, 23 insertions(+), 557 deletions(-) delete mode 100644 mROA.Test/CborTest.cs delete mode 100644 mROA.Test/FrontendFinalTest.cs delete mode 100644 mROA.Test/NextGenTest.cs delete mode 100644 mROA.Test/StreamTest.cs delete mode 100644 mROA.Test/UnSOization.cs delete mode 100644 mROA.Test/UnitTest1.cs diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs deleted file mode 100644 index cfa7d20..0000000 --- a/mROA.Test/CborTest.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using mROA.Cbor; - -namespace mROA.Test; - -public class CborTest -{ - private ComplexTestObject _complexTestObject; - private IContextualSerializationToolKit _serializationToolKit; - private BasicCollectionElement _basicCollectionElement; - - [SetUp] - public void Setup() - { - _basicCollectionElement = new() { A = 567565, B = "test text", C = 2.781f }; - - _complexTestObject = new ComplexTestObject - { - IntValue = 123, - DoubleValue = 3.14159, - StringValue = "abc", - EnumValue = TestEnum.X, - CollectionElements = - [ - _basicCollectionElement, - new BasicCollectionElement { A = 8_000_000, B = "Fi number", C = 1.618f } - ], - IntArray = [1, 4, 8, 16, 87] - }; - _serializationToolKit = new CborSerializationToolkit(); - } - - [Test] - public void BasicOnly() - { - var value = 123; - var data = _serializationToolKit.Serialize(value, null); - - var deserialize = _serializationToolKit.Deserialize(data, null); - Assert.That(value, Is.EqualTo(deserialize)); - } - - [Test] - public void ComplexFlat() - { - var value = _basicCollectionElement; - var data = _serializationToolKit.Serialize(value, null); - var deserialize = _serializationToolKit.Deserialize(data, null); - Assert.That(value, Is.EqualTo(deserialize)); - } - - [Test] - public void ComplexFull() - { - var value = _complexTestObject; - var data = _serializationToolKit.Serialize(value, null); - var deserialize = _serializationToolKit.Deserialize(data, null); - Assert.That(value, Is.EqualTo(deserialize)); - } - - public void SharedObject() - { - } - - - private class ComplexTestObject - { - public int IntValue { get; set; } - public double DoubleValue { get; set; } - public string StringValue { get; set; } - public TestEnum EnumValue { get; set; } - public int[] IntArray { get; set; } - public List CollectionElements { get; set; } - - protected bool Equals(ComplexTestObject other) - { - return IntValue == other.IntValue && DoubleValue.Equals(other.DoubleValue) && StringValue == other.StringValue && IntArray.SequenceEqual(other.IntArray) && CollectionElements.SequenceEqual(other.CollectionElements); - } - - public override bool Equals(object? obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((ComplexTestObject)obj); - } - - public override int GetHashCode() - { - return HashCode.Combine(IntValue, DoubleValue, StringValue, IntArray, CollectionElements); - } - } - - private class BasicCollectionElement - { - public int A { get; set; } - public string B { get; set; } - public float C { get; set; } - - protected bool Equals(BasicCollectionElement other) - { - return A == other.A && B == other.B && C.Equals(other.C); - } - - public override bool Equals(object? obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != GetType()) return false; - return Equals((BasicCollectionElement)obj); - } - - public override int GetHashCode() - { - return HashCode.Combine(A, B, C); - } - } - - public enum TestEnum - { - X = -5, Y, Z - } -} \ No newline at end of file diff --git a/mROA.Test/FrontendFinalTest.cs b/mROA.Test/FrontendFinalTest.cs deleted file mode 100644 index a765343..0000000 --- a/mROA.Test/FrontendFinalTest.cs +++ /dev/null @@ -1,92 +0,0 @@ -// using System.Net; -// using System.Net.Sockets; -// using System.Reflection; -// using mROA.Abstract; -// using mROA.Codegen; -// using Example.Shared; -// using mROA.Implementation; -// -// namespace mROA.Test; -// -// public class FrontendFinalTest -// { -// private StreamBasedInteractionModule _interactionModule; -// private StreamBasedFrontendInteractionModule _frontendInteractionModule; -// private JsonFrontendSerialisationModule _frontendSerialisationModule; -// private ISerialisationModule _serialisationModule; -// private IExecuteModule _executeModule; -// private IMethodRepository _methodRepository; -// private IContextRepository _contextRepository; -// bool isTestNotFinished = true; -// private IContextRepository _frontendContextRepository; -// -// [SetUp] -// public void Setup() -// { -// _methodRepository = new CoCodegenMethodRepository(); -// var repo2 = new ContextRepository(); -// repo2.FillSingletons(typeof(ITestController).Assembly); -// _contextRepository = repo2; -// -// _interactionModule = new StreamBasedInteractionModule(); -// -// _serialisationModule = new JsonSerialisationModule(); -// -// _executeModule = new BasicExecutionModule(); -// -// IInjectableModule[] backendModules = -// [_methodRepository, _contextRepository, _interactionModule, _serialisationModule, _executeModule]; -// -// foreach (var backendModule in backendModules) -// foreach (var injection in backendModules) -// backendModule.Inject(injection); -// -// _frontendInteractionModule = new StreamBasedFrontendInteractionModule(); -// _frontendSerialisationModule = new JsonFrontendSerialisationModule(); -// _frontendContextRepository = new FrontendContextRepository(); -// -// IInjectableModule[] frontendModules = -// [_frontendInteractionModule, _frontendSerialisationModule, _frontendContextRepository]; -// -// foreach (var backendModule in frontendModules) -// foreach (var injection in frontendModules) -// backendModule.Inject(injection); -// -// Task.Run(() => -// { -// TcpListener listener = new TcpListener(IPAddress.Loopback, 4567); -// listener.Start(); -// -// var stream = listener.AcceptTcpClient().GetStream(); -// -// Console.WriteLine("Client connected"); -// -// _interactionModule.RegisterSourse(stream); -// -// while (isTestNotFinished) ; -// }); -// -// var tcpClient = new TcpClient(); -// tcpClient.Connect(IPAddress.Loopback, 4567); -// _frontendInteractionModule.ServerStream = tcpClient.GetStream(); -// } -// -// [Test] -// public void CallTest() -// { -// var singleton = _frontendContextRepository.GetSingleObject(typeof(ITestController)) as ITestController; -// -// var x = singleton.B(); -// Console.WriteLine(x); -// } -// -// [Test] -// public void TransmittionTest() -// { -// var singleton = _frontendContextRepository.GetSingleObject(typeof(ITestController)) as ITestController; -// -// var next = singleton.SharedObjectTransmitionTest().Value; -// var parameter = singleton.GetTestParameter().Value; -// var x = next.Parametrized(new TestParameter { A = 100, LinkedObject = new(parameter!) }); -// } -// } \ No newline at end of file diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs deleted file mode 100644 index 6a36ef5..0000000 --- a/mROA.Test/NextGenTest.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; -using System.Threading.Tasks; -using mROA.Implementation; - -namespace mROA.Test -{ - public class NextGenTest - { - private TcpListener _listener; - private ChannelInteractionModule _interactionModuleA; - private ChannelInteractionModule _interactionModuleB; - private Guid[] guids = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; - - [SetUp] - public void Setup() - { - _listener = new TcpListener(IPAddress.Loopback, 4567); - _interactionModuleA = new ChannelInteractionModule(); - _interactionModuleA.Inject(new JsonSerializationToolkit()); - _interactionModuleB = new ChannelInteractionModule(); - _interactionModuleB.Inject(new JsonSerializationToolkit()); - - } - - [Test] - public void MultithreadedTest() - { - - Task.Run(() => - { - _listener.Start(); - // _interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream(); - - foreach (var guid in guids) - { - _interactionModuleB.PostMessageAsync(new NetworkMessageHeader { Id = guid, Data = "Hello user"u8.ToArray() }); - } - }); - - var client = new TcpClient(); - client.Connect(IPAddress.Loopback, 4567); - // _interactionModuleA.BaseStream = client.GetStream(); - - var tasks = guids.Select(ReadStream); - - Task.WaitAll(tasks.ToArray()); - Assert.Pass(); - - } - - private async Task ReadStream(Guid current) - { - var msg = await _interactionModuleA.GetNextMessageReceiving(); - Console.WriteLine( - $"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}"); - while (msg.Id != current) - { - msg = await _interactionModuleA.GetNextMessageReceiving(); - Console.WriteLine( - $"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}"); - } - - Console.WriteLine($"{Environment.CurrentManagedThreadId} Good message received"); - } - - [TearDown] - public void TearDown() - { - _listener.Stop(); - _listener.Dispose(); - _interactionModuleA.Dispose(); - _interactionModuleB.Dispose(); - } - } -} \ No newline at end of file diff --git a/mROA.Test/StreamTest.cs b/mROA.Test/StreamTest.cs deleted file mode 100644 index 6a10e72..0000000 --- a/mROA.Test/StreamTest.cs +++ /dev/null @@ -1,65 +0,0 @@ -// using System.Net; -// using System.Net.Sockets; -// using System.Text.Json; -// using mROA.Implementation; -// -// namespace mROA.Test; -// -// public class StreamTest -// { -// private StreamBasedInteractionModule _interactionModule; -// private StreamBasedFrontendInteractionModule _frontendInteractionModule; -// private JsonFrontendSerialisationModule _frontendSerialisationModule; -// private ISerialisationModule _serialisationModule; -// private IExecuteModule _executeModule; -// bool isTestNotFinished = true; -// -// [SetUp] -// public void Setup() -// { -// _interactionModule = new StreamBasedInteractionModule(); -// -// _serialisationModule = new JsonSerialisationModule(_interactionModule, new MockMethodRepository()); -// -// _executeModule = new MockExecModule(); -// _serialisationModule.SetExecuteModule(_executeModule); -// -// _frontendInteractionModule = new StreamBasedFrontendInteractionModule(); -// _frontendSerialisationModule = new JsonFrontendSerialisationModule(_frontendInteractionModule); -// -// Task.Run(() => -// { -// TcpListener listener = new TcpListener(IPAddress.Loopback, 4567); -// listener.Start(); -// -// var stream = listener.AcceptTcpClient().GetStream(); -// -// Console.WriteLine("Client connected"); -// -// _interactionModule.RegisterSourse(stream); -// -// while (isTestNotFinished) ; -// }); -// } -// -// [Test] -// public void StreamingTest() -// { -// var tcpClient = new TcpClient(); -// tcpClient.Connect(IPAddress.Loopback, 4567); -// _frontendInteractionModule.ServerStream = tcpClient.GetStream(); -// -// var req = new DefaultCallRequest { CommandId = 1, ObjectId = -1 }; -// _frontendSerialisationModule.PostCallRequest(req); -// var res = ((JsonElement)_frontendSerialisationModule -// .GetNextCommandExecution(req.CallRequestId).GetAwaiter().GetResult().Result!) -// .Deserialize(); -// isTestNotFinished = false; -// Assert.That(res.A == "wqer" && res.B == 5); -// } -// -// [Test] -// public void RemoteObjectTest() -// { -// } -// } \ No newline at end of file diff --git a/mROA.Test/UnSOization.cs b/mROA.Test/UnSOization.cs deleted file mode 100644 index d30c025..0000000 --- a/mROA.Test/UnSOization.cs +++ /dev/null @@ -1,26 +0,0 @@ -using mROA.Implementation; - -namespace mROA.Test; - -public class UnSOization -{ - private ComplexObjectIdentifier _uoi; - - [SetUp] - public void Setup() - { - _uoi = new ComplexObjectIdentifier - { - ContextId = -123, OwnerId = 123 - }; - } - - [Test] - public void FlatTest() - { - var flat = _uoi.Flat; - var next = new ComplexObjectIdentifier { Flat = flat }; - - Assert.That(_uoi, Is.EqualTo(next)); - } -} \ No newline at end of file diff --git a/mROA.Test/UnitTest1.cs b/mROA.Test/UnitTest1.cs deleted file mode 100644 index 78a3e38..0000000 --- a/mROA.Test/UnitTest1.cs +++ /dev/null @@ -1,154 +0,0 @@ -// using System.Diagnostics; -// using System.Reflection; -// using System.Text; -// using System.Text.Json; -// using Example.Shared; -// using mROA.Implementation; -// using Newtonsoft.Json; -// using JsonSerializer = System.Text.Json.JsonSerializer; -// -// namespace mROA.Test; -// -// public class Tests -// { -// private ProgramlyInteractionChanel _interactionModule; -// private ISerialisationModule _serialisationModule; -// private IExecuteModule _executeModule; -// private IMethodRepository _methodRepository; -// private IContextRepository _contextRepository; -// -// private ITestController _testController; -// -// [SetUp] -// public void Setup() -// { -// _interactionModule = new ProgramlyInteractionChanel(); -// var repo = new MethodRepository(); -// repo.CollectForAssembly(Assembly.GetExecutingAssembly()); -// _methodRepository = repo; -// var repo2 = new ContextRepository(); -// repo2.FillSingletons(Assembly.GetExecutingAssembly()); -// _contextRepository = repo2; -// _serialisationModule = new JsonSerialisationModule(_interactionModule, _methodRepository); -// -// _executeModule = new LaunchReadyExecutionModule(_methodRepository, _serialisationModule, _contextRepository); -// TransmissionConfig.DefaultContextRepository = _contextRepository; -// } -// -// [Test] -// public void CommandPipelineTest() -// { -// var sw = Stopwatch.StartNew(); -// -// _interactionModule.PassCommand(132, """ -// { -// "RequestTypeId": 0, -// "CommandId": 2 -// } -// """u8.ToArray()); -// Assert.Pass(_interactionModule.OutputBuffer.Last()); -// } -// -// [Test] -// public void CommandPipelineTestAsync() -// { -// var sw = Stopwatch.StartNew(); -// _interactionModule.PassCommand(132, """ -// { -// "RequestTypeId": 0, -// "CommandId": 3 -// } -// """u8.ToArray()); -// while (_interactionModule.OutputBuffer.Count != 2) ; -// -// Assert.Pass(_interactionModule.OutputBuffer.Last()); -// } -// -// [Test] -// public void MethodRegistrationTest() -// { -// var repo = new MethodRepository(); -// repo.CollectForAssembly(Assembly.GetExecutingAssembly()); -// Assert.That(repo.GetMethods().ToList().Count == 8); -// } -// -// [Test] -// public void ContextSupplyTest() -// { -// var repo = new ContextRepository(); -// repo.FillSingletons(Assembly.GetExecutingAssembly()); -// var singleObject = repo.GetSingleObject(typeof(ITestController)) as ITestController; -// singleObject.B(); -// Assert.That(singleObject.B() == 6); -// } -// -// [Test] -// public void TransmissionTest() -// { -// _interactionModule.PassCommand(132, """ -// { -// "CommandId": 4 -// } -// """u8.ToArray()); -// var response = -// JsonSerializer.Deserialize>( -// JsonSerializer.Deserialize(_interactionModule.OutputBuffer.Last()) -// ?.Result.ToString() -// ); -// -// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes( -// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId }))); -// -// var firstFull = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result") -// .GetInt32(); -// -// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes( -// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 4, ObjectId = response.ContextId }))); -// -// response = -// JsonSerializer.Deserialize>( -// JsonSerializer.Deserialize(_interactionModule.OutputBuffer.Last()) -// ?.Result.ToString() -// ); -// -// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes( -// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId }))); -// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes( -// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId }))); -// -// var secondFull = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result") -// .GetInt32(); -// -// Assert.That(firstFull == 456789 && secondFull == 6); -// } -// -// [Test] -// public void LinkedObjectsAndParametersTest() -// { -// _interactionModule.PassCommand(132, """ -// { -// "CommandId": 6 -// } -// """u8.ToArray()); -// var response = -// JsonSerializer.Deserialize>( -// JsonSerializer.Deserialize(_interactionModule.OutputBuffer.Last()) -// ?.Result.ToString() -// ); -// var x = response.ContextId; -// _interactionModule.PassCommand(132,Encoding.UTF8.GetBytes( -// JsonSerializer.Serialize(new DefaultCallRequest -// { -// CommandId = 5, -// Parameter = new TestParameter -// { -// A = 10, -// LinkedObject = new TransmittedSharedObject { ContextId = x } -// } -// }))); -// -// var finalResponse = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result").GetInt32(); -// -// Assert.That(finalResponse, Is.EqualTo(20)); -// } -// } \ No newline at end of file diff --git a/mROA/Abstract/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs index 3ae2d13..abf76d6 100644 --- a/mROA/Abstract/IExecuteModule.cs +++ b/mROA/Abstract/IExecuteModule.cs @@ -5,6 +5,6 @@ namespace mROA.Abstract public interface IExecuteModule : IInjectableModule { ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, - IRepresentationModule representationModule); + IRepresentationModule representationModule, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 3264b52..1360230 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -28,7 +28,7 @@ namespace mROA.Implementation.Backend } public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, - IRepresentationModule representationModule) + IRepresentationModule representationModule, IEndPointContext endPointContext) { #if TRACE Console.WriteLine(command.GetType().Name); @@ -58,7 +58,7 @@ namespace mROA.Implementation.Backend object?[]? castedParams = null; if (invoker.ParameterTypes.Length != 0) - castedParams = CastedParams(command, invoker); + castedParams = CastedParams(command, invoker, endPointContext); var execContext = new RequestContext(command.Id, representationModule.Id); @@ -68,10 +68,10 @@ namespace mROA.Implementation.Backend case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker: return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command, _cancellationRepo!, - representationModule, execContext); + representationModule, execContext, endPointContext); case AsyncMethodInvoker asyncMethodInvoker: return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo!, - representationModule, execContext); + representationModule, execContext, endPointContext); default: var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); if (command.CommandId == -1) @@ -104,12 +104,12 @@ namespace mROA.Implementation.Backend return context; } - private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker) + private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker, IEndPointContext context) { object?[] castedParams = new object[invoker.ParameterTypes.Length]; for (var i = 0; i < castedParams.Length; i++) { - castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i]); + castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i], context); } return castedParams; @@ -184,7 +184,7 @@ namespace mROA.Implementation.Backend private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, - IRepresentationModule representationModule, RequestContext executionContext) + IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -211,7 +211,7 @@ namespace mROA.Implementation.Backend multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); if (invoker.IsTrusted) representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, - payload); + payload, context); multiClientOwnershipRepository?.FreeOwnership(); }); @@ -237,7 +237,7 @@ namespace mROA.Implementation.Backend private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, - IRepresentationModule representationModule, RequestContext executionContext) + IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -259,7 +259,7 @@ namespace mROA.Implementation.Backend TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, - payload); + payload, context); multiClientOwnershipRepository?.FreeOwnership(); }); diff --git a/mROA/Implementation/Backend/UdpGateway.cs b/mROA/Implementation/Backend/UdpGateway.cs index 0bbcf5d..d2642bb 100644 --- a/mROA/Implementation/Backend/UdpGateway.cs +++ b/mROA/Implementation/Backend/UdpGateway.cs @@ -17,7 +17,7 @@ namespace mROA.Implementation.Backend private Dictionary _reservedPorts = new(); private CancellationTokenSource _tokenSource = new(); private IContextualSerializationToolKit _serializationToolkit; - + private IEndPointContext _context; public UdpGateway(IPEndPoint listeningEndpoint) { _client = new UdpClient(listeningEndpoint); @@ -34,6 +34,9 @@ namespace mROA.Implementation.Backend case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; + case IEndPointContext context: + _context = context; + break; } } @@ -51,7 +54,7 @@ namespace mROA.Implementation.Backend while (token.IsCancellationRequested == false) { var incoming = await _client.ReceiveAsync(); - var parsed = _serializationToolkit.Deserialize(incoming.Buffer); + var parsed = _serializationToolkit.Deserialize(incoming.Buffer, _context); try { int channelId; @@ -87,7 +90,7 @@ namespace mROA.Implementation.Backend or EventRequest)) continue; - var parsed = _serializationToolkit.Serialize(post); + var parsed = _serializationToolkit.Serialize(post, _context); await _client.SendAsync(parsed, parsed.Length, endpoint); } } diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 8822cb4..ef88ddc 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,5 +1,7 @@ using System; +#if TRACE using System.Diagnostics; +#endif using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -18,6 +20,7 @@ namespace mROA.Implementation.Frontend private IRepresentationModule? _representationModule; private IContextualSerializationToolKit? _serializationToolkit; private IEndPointContext _context; + public void Inject(T dependency) { switch (dependency) @@ -70,7 +73,8 @@ namespace mROA.Implementation.Frontend var query = _representationModule!.GetStream(m => m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest - or EMessageType.EventRequest or EMessageType.ClientDisconnect, _context, streamTokenSource.Token, + or EMessageType.EventRequest or EMessageType.ClientDisconnect, _context, + streamTokenSource.Token, m => m.MessageType == EMessageType.CallRequest ? typeof(DefaultCallRequest) : null, m => m.MessageType == EMessageType.CancelRequest ? typeof(CancelRequest) : null, m => m.MessageType == EMessageType.EventRequest ? typeof(DefaultCallRequest) : null, diff --git a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index 4ee2f00..07896f3 100644 --- a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -11,7 +11,7 @@ namespace mROA.Implementation.Frontend { private IContextualSerializationToolKit _serializationToolkit; private IChannelInteractionModule _channelInteractionModule; - private CancellationTokenSource _tokenSource = new CancellationTokenSource(); + private CancellationTokenSource _tokenSource = new(); public void Dispose() { From b86e13210c2476f42a82bde392973215b1c589a2 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 20:18:39 +0300 Subject: [PATCH 16/32] All modules solved, just NetworkGatewayModule.cs logic must remake --- mROA/Implementation/Backend/NetworkGatewayModule.cs | 9 ++++++--- mROA/Implementation/Frontend/RequestExtractor.cs | 6 +++--- .../Frontend/UdpUntrustedInteraction.cs | 11 +++++++---- mROA/Implementation/NetworkMessageHeader.cs | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index ab3e85a..e170b2d 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -80,7 +80,10 @@ namespace mROA.Implementation.Backend interaction!.Inject(_serialization); - var streamExtractor = new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization); + //TODO сделать контекст + var context = new EndPointContext(); + + var streamExtractor = new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization, context); interaction.IsConnected = () => streamExtractor.IsConnected; streamExtractor.MessageReceived = message => { interaction.ReceiveChanel.Writer.WriteAsync(message); }; streamExtractor.SingleReceive(); @@ -94,14 +97,14 @@ namespace mROA.Implementation.Backend Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); _ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, - new IdAssignment { Id = -interaction.ConnectionId }, TODO)); + new IdAssignment { Id = -interaction.ConnectionId }, null)); _extractorsCTS[interaction.ConnectionId] = cts; _hub!.RegisterInteraction(interaction); Console.WriteLine("Client registered"); break; case EMessageType.ClientRecovery: { - var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data)!; + var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data, null); var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); _extractorsCTS[recoveryRequest.Id].Cancel(); diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index ef88ddc..821b035 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -137,12 +137,12 @@ namespace mROA.Implementation.Frontend private void HandleCancelRequest(CancelRequest req) { - _executeModule!.Execute(req, _realContextRepository!, _representationModule!); + _executeModule!.Execute(req, _realContextRepository!, _representationModule!, _context); } private void HandleCallRequest(DefaultCallRequest request) { - var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!); + var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!, _context); var resultType = result.MessageType; @@ -156,7 +156,7 @@ namespace mROA.Implementation.Frontend private void HandleEventRequest(DefaultCallRequest request) { - _executeModule!.Execute(request, _remoteContextRepository!, _representationModule!); + _executeModule!.Execute(request, _remoteContextRepository!, _representationModule!, _context); } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index 07896f3..e2e7421 100644 --- a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -12,7 +12,7 @@ namespace mROA.Implementation.Frontend private IContextualSerializationToolKit _serializationToolkit; private IChannelInteractionModule _channelInteractionModule; private CancellationTokenSource _tokenSource = new(); - + private IEndPointContext _context; public void Dispose() { _tokenSource.Cancel(); @@ -35,7 +35,7 @@ namespace mROA.Implementation.Frontend while (token.IsCancellationRequested == false) { var message = new Memory((await udpClient.ReceiveAsync()).Buffer); - var parsed = _serializationToolkit.Deserialize(message.Span)!; + var parsed = _serializationToolkit.Deserialize(message, _context); await writer.WriteAsync(parsed, token); } @@ -49,7 +49,7 @@ namespace mROA.Implementation.Frontend Data = BitConverter.GetBytes(Math.Abs(_channelInteractionModule.ConnectionId)) }; - var initParsed = _serializationToolkit.Serialize(initMessage); + var initParsed = _serializationToolkit.Serialize(initMessage, _context); await udpClient.SendAsync(initParsed, initParsed.Length); @@ -59,7 +59,7 @@ namespace mROA.Implementation.Frontend or EMessageType.EventRequest)) continue; - var serialized = _serializationToolkit.Serialize(post); + var serialized = _serializationToolkit.Serialize(post, _context); #if TRACE Console.WriteLine("Untrusted write start"); #endif @@ -80,6 +80,9 @@ namespace mROA.Implementation.Frontend case IContextualSerializationToolKit serializationToolkit: _serializationToolkit = serializationToolkit; break; + case IEndPointContext endPointContext: + _context = endPointContext; + break; } } } diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index dee20f1..cb31c3e 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -35,7 +35,7 @@ namespace mROA.Implementation Data = Array.Empty(); } public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit, - INetworkMessage networkMessage, IEndPointContext context) + INetworkMessage networkMessage, IEndPointContext? context) { MessageType = networkMessage.MessageType; Data = serializationToolkit.Serialize(networkMessage, context); From c384b18c5a06466e22f606116148bfada56c8ac1 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 4 May 2025 20:28:23 +0300 Subject: [PATCH 17/32] Basic setup of endpoint context --- Example.Frontend/Program.cs | 2 +- .../IContextualSerializationToolKit.cs | 2 +- mROA/Abstract/IEndPointContext.cs | 4 +-- .../Backend/NetworkGatewayModule.cs | 11 ++++--- mROA/Implementation/EndPointContext.cs | 18 ++++++----- .../Frontend/NetworkFrontendBridge.cs | 14 ++++++--- .../Frontend/RequestExtractor.cs | 31 +++++-------------- mROA/Implementation/SharedObjectShell.cs | 4 +-- 8 files changed, 40 insertions(+), 46 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 6dbf673..e9cbf51 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -22,7 +22,7 @@ class Program new RemoteTypeBinder(); // builder.Modules.Add(new JsonSerializationToolkit()); builder.Modules.Add(new CborSerializationToolkit()); - + builder.Modules.Add(new EndPointContext()); builder.Modules.Add(new RemoteContextRepository()); builder.Modules.Add(new ChannelInteractionModule()); builder.Modules.Add(new UdpUntrustedInteraction()); diff --git a/mROA/Abstract/IContextualSerializationToolKit.cs b/mROA/Abstract/IContextualSerializationToolKit.cs index d027205..6cfa9ac 100644 --- a/mROA/Abstract/IContextualSerializationToolKit.cs +++ b/mROA/Abstract/IContextualSerializationToolKit.cs @@ -2,7 +2,7 @@ namespace mROA.Abstract { - public interface IContextualSerializationToolKit + public interface IContextualSerializationToolKit : IInjectableModule { byte[] Serialize(object objectToSerialize, IEndPointContext? context); void Serialize(object objectToSerialize, Span destination, IEndPointContext? context); diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs index 494669e..44db796 100644 --- a/mROA/Abstract/IEndPointContext.cs +++ b/mROA/Abstract/IEndPointContext.cs @@ -4,7 +4,7 @@ { IContextRepository RealRepository { get; } IContextRepository RemoteRepository { get; } - int HostId { get; } - int OwnerId { get; } + int HostId { get; set; } + int OwnerId { get; set; } } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index e170b2d..7f19f32 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -18,8 +18,6 @@ namespace mROA.Implementation.Backend private IContextualSerializationToolKit? _serialization; private Dictionary _extractorsCTS = new(); - - public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules) { @@ -82,8 +80,9 @@ namespace mROA.Implementation.Backend //TODO сделать контекст var context = new EndPointContext(); - - var streamExtractor = new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization, context); + + var streamExtractor = + new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization, context); interaction.IsConnected = () => streamExtractor.IsConnected; streamExtractor.MessageReceived = message => { interaction.ReceiveChanel.Writer.WriteAsync(message); }; streamExtractor.SingleReceive(); @@ -94,6 +93,8 @@ namespace mROA.Implementation.Backend switch (connectionRequest.MessageType) { case EMessageType.ClientConnect: + context.HostId = 0; + context.OwnerId = interaction.ConnectionId; Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); _ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, @@ -129,7 +130,7 @@ namespace mROA.Implementation.Backend } } } - + private void ThrowIfNotInjected() { if (_hub is null) diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index b249aeb..6962f86 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -1,24 +1,28 @@ using System; using mROA.Abstract; +using mROA.Implementation.Backend; namespace mROA.Implementation { public class EndPointContext : IEndPointContext { - public Func OwnerFunc; public IContextRepository RealRepository { get; set; } public IContextRepository RemoteRepository { get; set; } public int HostId { get; set; } - public int OwnerId - { - get => OwnerFunc(); - // ReSharper disable once UnusedMember.Global - set { OwnerFunc = () => value; } - } + public int OwnerId { get; set; } public void Inject(T dependency) { + switch (dependency) + { + case RemoteContextRepository remoteRepository: + RemoteRepository = remoteRepository; + break; + case ContextRepository realRepository: + RealRepository = realRepository; + break; + } } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index eabc2bd..049a108 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -20,6 +20,7 @@ namespace mROA.Implementation.Frontend private ChannelInteractionModule.StreamExtractor _currentExtractor; private CancellationTokenSource _rawExtractorCancellation; private IEndPointContext _context; + public NetworkFrontendBridge(IPEndPoint serverEndPoint) { _serverEndPoint = serverEndPoint; @@ -55,7 +56,8 @@ namespace mROA.Implementation.Frontend _interactionModule.IsConnected = () => _currentExtractor.IsConnected; _interactionModule.OnDisconnected += _ => { Reconnect(); }; - _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect(), _context)).Wait(); + _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect(), _context)) + .Wait(); _currentExtractor.SingleReceive(); var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); @@ -69,14 +71,17 @@ namespace mROA.Implementation.Frontend Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token)); - var assignment = _serialization.Deserialize(idMessage.Data, _context)!; + var assignment = _serialization.Deserialize(idMessage.Data, _context); _interactionModule.ConnectionId = -assignment.Id; TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); + _context.HostId = assignment.Id; + _context.OwnerId = assignment.Id; } private void PrepareExtractor() { - _currentExtractor = new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!, _context); + _currentExtractor = + new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!, _context); _ = _currentExtractor.SendFromChannel(_interactionModule!.TrustedPostChanel, _rawExtractorCancellation.Token); @@ -108,7 +113,8 @@ namespace mROA.Implementation.Frontend public void Disconnect() { - _ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect(), _context)); + _ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect(), + _context)); _interactionModule.Dispose(); _tcpClient.Dispose(); } diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 821b035..3311ca6 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; -using mROA.Implementation.Backend; // ReSharper disable MethodHasAsyncOverload @@ -14,9 +13,11 @@ namespace mROA.Implementation.Frontend public class RequestExtractor : IRequestExtractor { private IExecuteModule? _executeModule; + private IMethodRepository? _methodRepository; - private IContextRepository? _realContextRepository; - private IContextRepository? _remoteContextRepository; + + // private IContextRepository? _realContextRepository; + // private IContextRepository? _remoteContextRepository; private IRepresentationModule? _representationModule; private IContextualSerializationToolKit? _serializationToolkit; private IEndPointContext _context; @@ -28,13 +29,6 @@ namespace mROA.Implementation.Frontend case IExecuteModule executeModule: _executeModule = executeModule; break; - case MultiClientContextRepository: - case ContextRepository: - _realContextRepository = dependency as IContextRepository; - break; - case RemoteContextRepository remoteContextRepository: - _remoteContextRepository = remoteContextRepository; - break; case IMethodRepository methodRepository: _methodRepository = methodRepository; break; @@ -55,14 +49,6 @@ namespace mROA.Implementation.Frontend ThrowIfNotInjected(); - var multiClientOwnershipRepository = - TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; - multiClientOwnershipRepository?.RegisterOwnership(_representationModule!.Id); - if (multiClientOwnershipRepository is not null) - { - TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_representationModule.Id); - } - try { #if TRACE @@ -117,7 +103,6 @@ namespace mROA.Implementation.Frontend } catch { - multiClientOwnershipRepository?.FreeOwnership(); } } @@ -127,8 +112,6 @@ namespace mROA.Implementation.Frontend throw new NullReferenceException("Serializing toolkit is null."); if (_executeModule == null) throw new NullReferenceException("Execute module is null."); - if (_realContextRepository == null) - throw new NullReferenceException("Context repository is null."); if (_representationModule == null) throw new NullReferenceException("Representation module is null."); if (_methodRepository == null) @@ -137,12 +120,12 @@ namespace mROA.Implementation.Frontend private void HandleCancelRequest(CancelRequest req) { - _executeModule!.Execute(req, _realContextRepository!, _representationModule!, _context); + _executeModule!.Execute(req, _context.RealRepository, _representationModule!, _context); } private void HandleCallRequest(DefaultCallRequest request) { - var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!, _context); + var result = _executeModule!.Execute(request, _context.RealRepository, _representationModule!, _context); var resultType = result.MessageType; @@ -156,7 +139,7 @@ namespace mROA.Implementation.Frontend private void HandleEventRequest(DefaultCallRequest request) { - _executeModule!.Execute(request, _remoteContextRepository!, _representationModule!, _context); + _executeModule!.Execute(request, _context.RemoteRepository, _representationModule!, _context); } } } \ No newline at end of file diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 0fe0450..46a632a 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -63,8 +63,8 @@ namespace mROA.Implementation { RealRepository = TransmissionConfig.RealContextRepository, RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, - HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), - OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId + HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), + OwnerId = 0 }; public ComplexObjectIdentifier Identifier From cc5f82c7e791a095d2cf33bc1c33146cd1cec545 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Mon, 5 May 2025 14:37:17 +0300 Subject: [PATCH 18/32] Prefinal local endpoint context override --- Example.Backend/Program.cs | 5 ++-- mROA/Abstract/IContextRepository.cs | 2 +- .../Backend/BasicExecutionModule.cs | 10 ++++---- .../Backend/ContextRepository.cs | 2 +- .../Backend/HubRequestExtractor.cs | 24 +++++++++---------- .../Backend/MultiClientContextRepository.cs | 4 ++-- .../ComplexContextRepository.cs | 2 +- .../Implementation/RemoteContextRepository.cs | 4 ++-- mROA/Implementation/SharedObjectShell.cs | 2 +- 9 files changed, 27 insertions(+), 28 deletions(-) diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 4f5a7ab..408f880 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -7,7 +7,6 @@ using mROA.Codegen; using mROA.Implementation; using mROA.Implementation.Backend; using mROA.Implementation.Bootstrap; -using mROA.Implementation.Frontend; class Program { @@ -24,11 +23,11 @@ class Program builder.GetModule()!); builder.Modules.Add(new UdpGateway(listening)); builder.Modules.Add(new ConnectionHub()); - builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor))); + builder.Modules.Add(new HubRequestExtractor()); builder.UseBasicExecution(); builder.Modules.Add(new CreativeRepresentationModuleProducer( - new IInjectableModule[] { builder.GetModule()! }, + new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); builder.Modules.Add(new RemoteContextRepository()); // builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly); diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 920a317..c4d6c3e 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -8,7 +8,7 @@ namespace mROA.Abstract int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); void ClearObject(ComplexObjectIdentifier id); - T GetObject(ComplexObjectIdentifier id); + T GetObject(ComplexObjectIdentifier id, IEndPointContext context); object GetSingleObject(Type type, int ownerId); int GetObjectIndex(object o, IEndPointContext context); } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 1360230..f161e20 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -49,7 +49,7 @@ namespace mROA.Implementation.Backend if (invoker == null) throw new Exception($"Command {command.CommandId} not found"); - var context = GetContext(command, contextRepository, invoker); + var context = GetContext(command, contextRepository, invoker, endPointContext); if (context == null) throw new NullReferenceException("Instance can't be null"); @@ -96,10 +96,10 @@ namespace mROA.Implementation.Backend } private static object GetContext(ICallRequest command, IContextRepository contextRepository, - IMethodInvoker invoker) + IMethodInvoker invoker, IEndPointContext endPointContext) { var context = command.ObjectId.ContextId != -1 - ? contextRepository.GetObject(command.ObjectId) + ? contextRepository.GetObject(command.ObjectId, endPointContext) : contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId); return context; } @@ -152,8 +152,8 @@ namespace mROA.Implementation.Backend { return new AsyncCommandExecution(); } - - if (invoker.IsVoid ) + + if (invoker.IsVoid) { return new FinalCommandExecution { diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index b4ecc98..5448101 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -44,7 +44,7 @@ namespace mROA.Implementation.Backend _storage.Free(id.ContextId); } - public T GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) { var value = _storage.GetValue(id.ContextId); diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 7d760fe..9c0a2d3 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -1,5 +1,5 @@ -using System; using mROA.Abstract; +using mROA.Implementation.Frontend; namespace mROA.Implementation.Backend { @@ -12,12 +12,6 @@ namespace mROA.Implementation.Backend private IMethodRepository? _methodRepository; private IContextualSerializationToolKit? _serializationToolkit; private IExecuteModule? _executeModule; - private readonly Type _extractorType; - - public HubRequestExtractor(Type extractorType) - { - _extractorType = extractorType; - } public void Inject(T dependency) { @@ -49,7 +43,7 @@ namespace mROA.Implementation.Backend private void HubOnOnConnected(IRepresentationModule interaction) { var extractor = CreateExtractor(interaction); - extractor.StartExtraction().ContinueWith(t => OnDisconnected(interaction)); + extractor.StartExtraction().ContinueWith(_ => OnDisconnected(interaction)); } private void OnDisconnected(IRepresentationModule representationModule) @@ -60,16 +54,22 @@ namespace mROA.Implementation.Backend private IRequestExtractor CreateExtractor(IRepresentationModule interaction) { - var extractor = (IRequestExtractor)Activator.CreateInstance(_extractorType)!; + var extractor = new RequestExtractor(); + var context = new EndPointContext + { + HostId = 0, OwnerId = interaction.Id + }; extractor.Inject(interaction); + if (_contextRepository is IContextRepositoryHub contextHub) - extractor.Inject(contextHub.GetRepository(interaction.Id)); + context.RealRepository = contextHub.GetRepository(interaction.Id); else - extractor.Inject(interaction); + context.RealRepository = _contextRepository!; + + context.RemoteRepository = _remoteContextRepository!; extractor.Inject(_methodRepository); extractor.Inject(_serializationToolkit); extractor.Inject(_executeModule); - extractor.Inject(_remoteContextRepository); return extractor; } } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index a0b3893..370f105 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -32,10 +32,10 @@ namespace mROA.Implementation.Backend repository.ClearObject(id); } - public T GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetObject(id); + return repository.GetObject(id, context); } public object GetSingleObject(Type type, int ownerId) diff --git a/mROA/Implementation/ComplexContextRepository.cs b/mROA/Implementation/ComplexContextRepository.cs index 8f44c78..bcd8285 100644 --- a/mROA/Implementation/ComplexContextRepository.cs +++ b/mROA/Implementation/ComplexContextRepository.cs @@ -52,7 +52,7 @@ namespace mROA.Implementation _storages.Find(i => i.Key == id.OwnerId).Value.Free(id.ContextId); } - public T GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) { throw new NotImplementedException(); } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 43dceda..a6af325 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -23,7 +23,7 @@ namespace mROA.Implementation throw new NotSupportedException(); } - public T GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) { var index = _producedRemoteEndpoints.Find(i => i.Identifier.Equals(id)); if (index is not null) @@ -35,7 +35,7 @@ namespace mROA.Implementation var representationModule = _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var remote = (T)Activator.CreateInstance(remoteType, id.ContextId, - representationModule)!; + representationModule, context)!; _producedRemoteEndpoints.Add((remote as RemoteObjectBase)!); diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 46a632a..d595a23 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -77,7 +77,7 @@ namespace mROA.Implementation set { _identifier = value; - Value = GetDefaultContextRepository().GetObject(Identifier); + Value = GetDefaultContextRepository().GetObject(Identifier, EndPointContext); } } From ff4c3ecee3c9a352fb129ce4ea00a91597833572 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Mon, 5 May 2025 16:30:23 +0300 Subject: [PATCH 19/32] Local endpoint added successful and negative ownerId implemented --- Example.Backend/PagesList.cs | 2 +- Example.Backend/Program.cs | 5 +-- Example.Frontend/Program.cs | 14 +++--- mROA.Cbor/CborSerializationToolkit.cs | 4 +- mROA.Codegen/RemoteEndpoint.cstmpl | 4 +- mROA.Codegen/RemoteTypeBinder.cstmpl | 2 +- mROA.Test/Identifier.cs | 23 ++++++++++ mROA.sln | 3 -- mROA/Abstract/IContextRepository.cs | 4 +- mROA/Abstract/IRemoteObjectFactory.cs | 2 +- .../Backend/BackendIdentityGenerator.cs | 2 +- .../Backend/BasicConfigurationExtensions.cs | 1 - .../Backend/BasicExecutionModule.cs | 16 ++----- mROA/Implementation/Backend/ConnectionHub.cs | 2 +- .../Backend/ContextRepository.cs | 4 +- .../Backend/HubRequestExtractor.cs | 5 ++- .../Backend/MultiClientContextRepository.cs | 18 ++++---- .../Backend/NetworkGatewayModule.cs | 6 +-- .../ComplexContextRepository.cs | 4 +- .../Implementation/ComplexObjectIdentifier.cs | 2 +- .../Frontend/NetworkFrontendBridge.cs | 1 - .../Frontend/UdpUntrustedInteraction.cs | 2 +- .../Implementation/RemoteContextRepository.cs | 10 ++--- mROA/Implementation/RemoteObjectFactory.cs | 4 +- mROA/Implementation/RepresentationModule.cs | 21 ++++----- mROA/Implementation/SharedObjectShell.cs | 19 +++----- mROA/Implementation/TransmissionConfig.cs | 44 +++++++++---------- 27 files changed, 110 insertions(+), 114 deletions(-) create mode 100644 mROA.Test/Identifier.cs diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs index 1b195c9..35db8f1 100644 --- a/Example.Backend/PagesList.cs +++ b/Example.Backend/PagesList.cs @@ -8,7 +8,7 @@ namespace Example.Backend { public class PagesList : RemoteObjectBase, IPagesList { - public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule) + public PagesList(int id, IRepresentationModule representationModule,IEndPointContext context) : base(id, representationModule, context) { } diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 408f880..95f8c36 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -44,10 +44,7 @@ class Program builder.Build(); new RemoteTypeBinder(); - - TransmissionConfig.RealContextRepository = builder.GetModule()!; - TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule()!; - TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository(); + _ = builder.GetModule()!.Start(); var gateway = builder.GetModule(); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index e9cbf51..9abe3b1 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -37,21 +37,17 @@ class Program builder.Modules.Add(new CancellationRepository()); builder.Build(); - - - TransmissionConfig.RealContextRepository = builder.GetModule(); - TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule(); - + var frontendBridge = builder.GetModule()!; frontendBridge.Connect(); _ = builder.GetModule()!.StartExtraction(); _ = builder.GetModule().Start(serverEndPoint); - Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + Console.WriteLine(builder.GetModule().HostId); var context = builder.GetModule(); var factory = context.GetSingleObject(typeof(IPrinterFactory), - -TransmissionConfig.OwnershipRepository.GetHostOwnershipId()) as IPrinterFactory; + builder.GetModule()) as IPrinterFactory; using (var disposingPrinter = factory.Create("Test")) { @@ -89,7 +85,7 @@ class Program var names = factory.CollectAllNames(); Thread.Sleep(100); - Console.WriteLine(string.Join(", ", names)); + Console.WriteLine("Names: " + string.Join(", ", names)); var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter() .GetResult(); @@ -114,7 +110,7 @@ class Program DemoCheck.Dispose = true; - var loadSingleton = context.GetSingleObject(typeof(ILoadTest), 0) as ILoadTest; + var loadSingleton = context.GetSingleObject(typeof(ILoadTest), builder.GetModule()) as ILoadTest; var cts = new CancellationTokenSource(); diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 47d1fc0..425cbe3 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -216,10 +216,8 @@ namespace mROA.Cbor var generic = obj.GetType().GetInterfaces().FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i)); var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(generic); var so = - Activator.CreateInstance(sharedShell, obj) as + Activator.CreateInstance(sharedShell, obj, context) as ISharedObjectShell; - if (context != null) - so.EndPointContext = context; writer.WriteStartArray(1); writer.WriteUInt64(so.Identifier.Flat); diff --git a/mROA.Codegen/RemoteEndpoint.cstmpl b/mROA.Codegen/RemoteEndpoint.cstmpl index 8a2541a..0ee69af 100644 --- a/mROA.Codegen/RemoteEndpoint.cstmpl +++ b/mROA.Codegen/RemoteEndpoint.cstmpl @@ -10,8 +10,8 @@ namespace partial class : RemoteObjectBase, { - public (int id, IRepresentationModule representationModule) - : base(id, representationModule) + public (int id, IRepresentationModule representationModule, IEndPointContext context) + : base(id, representationModule, context) { } diff --git a/mROA.Codegen/RemoteTypeBinder.cstmpl b/mROA.Codegen/RemoteTypeBinder.cstmpl index be2bf42..bbef815 100644 --- a/mROA.Codegen/RemoteTypeBinder.cstmpl +++ b/mROA.Codegen/RemoteTypeBinder.cstmpl @@ -39,7 +39,7 @@ namespace mROA.Codegen Parameters = new object[] { } }; - module.PostCallMessageAsync(request.Id, EMessageType.EventRequest, request); + module.PostCallMessageAsync(request.Id, EMessageType.EventRequest, request, context); }; } diff --git a/mROA.Test/Identifier.cs b/mROA.Test/Identifier.cs new file mode 100644 index 0000000..6b929bc --- /dev/null +++ b/mROA.Test/Identifier.cs @@ -0,0 +1,23 @@ +using mROA.Implementation; + +namespace mROA.Test; + +[TestFixture] +public class Identifier +{ + [Test] + public void TestParse() + { + var id = new ComplexObjectIdentifier(-1, -1); + var flat = id.Flat; + var next = new ComplexObjectIdentifier { Flat = flat }; + if (id.Equals(next)) + { + Assert.Pass(); + } + else + { + Assert.Fail(); + } + } +} \ No newline at end of file diff --git a/mROA.sln b/mROA.sln index 2c090e8..40a367e 100644 --- a/mROA.sln +++ b/mROA.sln @@ -23,8 +23,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codegen", "Codegen", "{3DB22457-E65B-426F-B3DD-08C615132B3E}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +70,5 @@ Global {A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} {9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} {E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} - {3DB22457-E65B-426F-B3DD-08C615132B3E} = {EAE92F5A-664C-41AB-8811-5885524B5347} EndGlobalSection EndGlobal diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index c4d6c3e..f4857c7 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -7,9 +7,9 @@ namespace mROA.Abstract { int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); - void ClearObject(ComplexObjectIdentifier id); + void ClearObject(ComplexObjectIdentifier id, IEndPointContext context); T GetObject(ComplexObjectIdentifier id, IEndPointContext context); - object GetSingleObject(Type type, int ownerId); + object GetSingleObject(Type type, IEndPointContext context); int GetObjectIndex(object o, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Abstract/IRemoteObjectFactory.cs b/mROA/Abstract/IRemoteObjectFactory.cs index e68fb0f..1ae127f 100644 --- a/mROA/Abstract/IRemoteObjectFactory.cs +++ b/mROA/Abstract/IRemoteObjectFactory.cs @@ -4,6 +4,6 @@ namespace mROA.Abstract { public interface IRemoteObjectFactory : IInjectableModule { - T Produce(ComplexObjectIdentifier id); + T Produce(ComplexObjectIdentifier id, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BackendIdentityGenerator.cs b/mROA/Implementation/Backend/BackendIdentityGenerator.cs index dce88be..bf9fcdb 100644 --- a/mROA/Implementation/Backend/BackendIdentityGenerator.cs +++ b/mROA/Implementation/Backend/BackendIdentityGenerator.cs @@ -8,7 +8,7 @@ namespace mROA.Implementation.Backend public int GetNextIdentity() { - return ++_currentId; + return -++_currentId; } public void Inject(T dependency) diff --git a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs index b8e0f7c..57b5f65 100644 --- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs +++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs @@ -23,7 +23,6 @@ namespace mROA.Implementation.Backend { var repo = new ContextRepository(); repo.FillSingletons(assemblies); - TransmissionConfig.RealContextRepository = repo; builder.Modules.Add(repo); } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index f161e20..d5f3f09 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -79,7 +79,7 @@ namespace mROA.Implementation.Backend #if TRACE Console.WriteLine("Disposing object"); #endif - contextRepository.ClearObject(command.ObjectId); + contextRepository.ClearObject(command.ObjectId, endPointContext); } return result; @@ -100,7 +100,7 @@ namespace mROA.Implementation.Backend { var context = command.ObjectId.ContextId != -1 ? contextRepository.GetObject(command.ObjectId, endPointContext) - : contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId); + : contextRepository.GetSingleObject(invoker.SuitableType, endPointContext); return context; } @@ -205,14 +205,10 @@ namespace mROA.Implementation.Backend }; _cancellationRepo?.FreeCancelation(command.Id); - var multiClientOwnershipRepository = - TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; - - multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); + if (invoker.IsTrusted) representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, payload, context); - multiClientOwnershipRepository?.FreeOwnership(); }); return new AsyncCommandExecution @@ -254,13 +250,9 @@ namespace mROA.Implementation.Backend Result = finalResult }; _cancellationRepo!.FreeCancelation(command.Id); - - var multiClientOwnershipRepository = - TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; - multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); + representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, payload, context); - multiClientOwnershipRepository?.FreeOwnership(); }); return new AsyncCommandExecution diff --git a/mROA/Implementation/Backend/ConnectionHub.cs b/mROA/Implementation/Backend/ConnectionHub.cs index 34c7064..ddaf694 100644 --- a/mROA/Implementation/Backend/ConnectionHub.cs +++ b/mROA/Implementation/Backend/ConnectionHub.cs @@ -23,7 +23,7 @@ namespace mROA.Implementation.Backend public IChannelInteractionModule GetInteraction(int id) { - return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found"); + return _connections!.GetValueOrDefault(id, null) ?? _connections!.GetValueOrDefault(-id, null) ?? throw new Exception("No connection found"); } public event ConnectionHandler? OnConnected; diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 5448101..13541c5 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -39,7 +39,7 @@ namespace mROA.Implementation.Backend return last; } - public void ClearObject(ComplexObjectIdentifier id) + public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context) { _storage.Free(id.ContextId); } @@ -56,7 +56,7 @@ namespace mROA.Implementation.Backend return (T)value; } - public object GetSingleObject(Type type, int ownerId) + public object GetSingleObject(Type type, IEndPointContext context) { return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 9c0a2d3..7c35b33 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -57,16 +57,17 @@ namespace mROA.Implementation.Backend var extractor = new RequestExtractor(); var context = new EndPointContext { - HostId = 0, OwnerId = interaction.Id + HostId = 0, OwnerId = -interaction.Id }; extractor.Inject(interaction); - if (_contextRepository is IContextRepositoryHub contextHub) context.RealRepository = contextHub.GetRepository(interaction.Id); else context.RealRepository = _contextRepository!; context.RemoteRepository = _remoteContextRepository!; + + extractor.Inject(context); extractor.Inject(_methodRepository); extractor.Inject(_serializationToolkit); extractor.Inject(_executeModule); diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 370f105..8d63cd3 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -22,31 +22,31 @@ namespace mROA.Implementation.Backend public int ResisterObject(object o, IEndPointContext context) { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + var repository = GetRepositoryByClientId(context.OwnerId); return repository.ResisterObject(o, context); } - public void ClearObject(ComplexObjectIdentifier id) + public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context) { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - repository.ClearObject(id); + var repository = GetRepositoryByClientId(context.OwnerId); + repository.ClearObject(id, context); } public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + var repository = GetRepositoryByClientId(context.OwnerId); return repository.GetObject(id, context); } - public object GetSingleObject(Type type, int ownerId) + public object GetSingleObject(Type type, IEndPointContext context) { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetSingleObject(type, ownerId); + var repository = GetRepositoryByClientId(context.OwnerId); + return repository.GetSingleObject(type, context); } public int GetObjectIndex(object o, IEndPointContext context) { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + var repository = GetRepositoryByClientId(context.OwnerId); return repository.GetObjectIndex(o, context); } diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 7f19f32..8fe538c 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -94,11 +94,11 @@ namespace mROA.Implementation.Backend { case EMessageType.ClientConnect: context.HostId = 0; - context.OwnerId = interaction.ConnectionId; + context.OwnerId = -interaction.ConnectionId; Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token)); _ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token); interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!, - new IdAssignment { Id = -interaction.ConnectionId }, null)); + new IdAssignment { Id = interaction.ConnectionId }, null)); _extractorsCTS[interaction.ConnectionId] = cts; _hub!.RegisterInteraction(interaction); Console.WriteLine("Client registered"); @@ -108,7 +108,7 @@ namespace mROA.Implementation.Backend var recoveryRequest = _serialization!.Deserialize(connectionRequest.Data, null); var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id); - _extractorsCTS[recoveryRequest.Id].Cancel(); + _extractorsCTS[-recoveryRequest.Id].Cancel(); recoveryInteraction.IsConnected = () => streamExtractor.IsConnected; streamExtractor.MessageReceived = message => diff --git a/mROA/Implementation/ComplexContextRepository.cs b/mROA/Implementation/ComplexContextRepository.cs index bcd8285..b074da9 100644 --- a/mROA/Implementation/ComplexContextRepository.cs +++ b/mROA/Implementation/ComplexContextRepository.cs @@ -47,7 +47,7 @@ namespace mROA.Implementation return placedIndex; } - public void ClearObject(ComplexObjectIdentifier id) + public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context) { _storages.Find(i => i.Key == id.OwnerId).Value.Free(id.ContextId); } @@ -57,7 +57,7 @@ namespace mROA.Implementation throw new NotImplementedException(); } - public object GetSingleObject(Type type, int ownerId) + public object GetSingleObject(Type type, IEndPointContext context) { throw new NotImplementedException(); } diff --git a/mROA/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs index d95d378..ae2e4e0 100644 --- a/mROA/Implementation/ComplexObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -32,7 +32,7 @@ namespace mROA.Implementation public ulong Flat { - get => (ulong)OwnerId << 32 | (uint)ContextId; + get => (ulong)((long)OwnerId << 32 | (uint)ContextId); set { OwnerId = (int)(value >> 32); diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 049a108..2b287fa 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -73,7 +73,6 @@ namespace mROA.Implementation.Frontend var assignment = _serialization.Deserialize(idMessage.Data, _context); _interactionModule.ConnectionId = -assignment.Id; - TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); _context.HostId = assignment.Id; _context.OwnerId = assignment.Id; } diff --git a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index e2e7421..941ac08 100644 --- a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -46,7 +46,7 @@ namespace mROA.Implementation.Frontend var initMessage = new NetworkMessageHeader { MessageType = EMessageType.UntrustedConnect, Id = Guid.NewGuid(), - Data = BitConverter.GetBytes(Math.Abs(_channelInteractionModule.ConnectionId)) + Data = BitConverter.GetBytes(_channelInteractionModule.ConnectionId) }; var initParsed = _serializationToolkit.Serialize(initMessage, _context); diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index a6af325..9ab5dd8 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -18,7 +18,7 @@ namespace mROA.Implementation throw new NotSupportedException(); } - public void ClearObject(ComplexObjectIdentifier id) + public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context) { throw new NotSupportedException(); } @@ -33,7 +33,7 @@ namespace mROA.Implementation if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException(); var representationModule = - _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + _representationProducer.Produce(context.OwnerId); var remote = (T)Activator.CreateInstance(remoteType, id.ContextId, representationModule, context)!; @@ -42,16 +42,16 @@ namespace mROA.Implementation return remote; } - public object GetSingleObject(Type type, int ownerId) + public object GetSingleObject(Type type, IEndPointContext context) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); var representationModule = - _representationProducer.Produce(ownerId); + _representationProducer.Produce(context.OwnerId); _producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1, - representationModule) as RemoteObjectBase)!); + representationModule, context) as RemoteObjectBase)!); return _producedRemoteEndpoints.Last(); } diff --git a/mROA/Implementation/RemoteObjectFactory.cs b/mROA/Implementation/RemoteObjectFactory.cs index fad21e3..8fa0873 100644 --- a/mROA/Implementation/RemoteObjectFactory.cs +++ b/mROA/Implementation/RemoteObjectFactory.cs @@ -9,14 +9,14 @@ namespace mROA.Implementation public static Dictionary RemoteTypes = new(); private IRepresentationModuleProducer? _representationProducer; - public T Produce(ComplexObjectIdentifier id) + public T Produce(ComplexObjectIdentifier id, IEndPointContext context) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException(); var representationModule = - _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + _representationProducer.Produce(context.OwnerId); var remote = (T)Activator.CreateInstance(remoteType, id.ContextId, representationModule)!; return remote; diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 14db0fd..bb9d40c 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -55,7 +55,8 @@ namespace mROA.Implementation } public async IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream( - Predicate rule, IEndPointContext? context, [EnumeratorCancellation] CancellationToken token = default, + Predicate rule, IEndPointContext? context, + [EnumeratorCancellation] CancellationToken token = default, params Func[] converter) { var writer = _interaction?.ReceiveChanel.Writer; @@ -72,15 +73,14 @@ namespace mROA.Implementation yield return (deserialized, message.MessageType)!; } } - - public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload, - IEndPointContext? context) where T : notnull - { - await PostCallMessageAsync(id, eMessageType, payload, context); - } - public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, - IEndPointContext? context) + // public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload, + // IEndPointContext? context) where T : notnull + // { + // await this.PostCallMessageAsync(id, eMessageType, payload, context); + // } + + public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull { if (_interaction == null) throw new NullReferenceException("Interaction toolkit is not initialized"); @@ -92,7 +92,8 @@ namespace mROA.Implementation { Id = id, MessageType = eMessageType, Data = serialized }); } - public void PostCallMessage(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull + public void PostCallMessage(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) + where T : notnull { PostCallMessageAsync(id, eMessageType, payload, context).GetAwaiter().GetResult(); } diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index d595a23..01305db 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -4,7 +4,7 @@ using mROA.Abstract; using mROA.Implementation.Attributes; // ReSharper disable UnusedMember.Global -#pragma warning disable CS8618, CS9264 +// #pragma warning disable CS8618, CS9264 namespace mROA.Implementation { @@ -30,8 +30,9 @@ namespace mROA.Implementation // ReSharper disable once UnusedMember.Global // ReSharper disable once MemberCanBePrivate.Global - public SharedObjectShellShell(T value) + public SharedObjectShellShell(T value, IEndPointContext endPointContext) { + EndPointContext = endPointContext; Value = value; } @@ -57,15 +58,7 @@ namespace mROA.Implementation } } - [SerializationIgnore] - [JsonIgnore] - public IEndPointContext EndPointContext { get; set; } = new EndPointContext - { - RealRepository = TransmissionConfig.RealContextRepository, - RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, - HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), - OwnerId = 0 - }; + [SerializationIgnore] [JsonIgnore] public IEndPointContext EndPointContext { get; set; } public ComplexObjectIdentifier Identifier { @@ -96,7 +89,7 @@ namespace mROA.Implementation public static implicit operator T(SharedObjectShellShell value) => value.Value; - public static implicit operator SharedObjectShellShell(T value) => - new(value); + // public static implicit operator SharedObjectShellShell(T value) => + // new(value); } } \ No newline at end of file diff --git a/mROA/Implementation/TransmissionConfig.cs b/mROA/Implementation/TransmissionConfig.cs index 5302f9c..013995a 100644 --- a/mROA/Implementation/TransmissionConfig.cs +++ b/mROA/Implementation/TransmissionConfig.cs @@ -9,27 +9,27 @@ namespace mROA.Implementation #if TRACE public static int TotalTransmittedBytes { get; set; } #endif - private static IContextRepository? _realContextRepository; - private static IContextRepository? _remoteEndpointContextRepository; - private static IOwnershipRepository? _ownershipRepository; - - public static IContextRepository RealContextRepository - { - get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); - set => _realContextRepository = value; - } - - public static IContextRepository RemoteEndpointContextRepository - { - get => _remoteEndpointContextRepository ?? - throw new NullReferenceException("RemoteEndpointContextRepository is null"); - set => _remoteEndpointContextRepository = value; - } - - public static IOwnershipRepository OwnershipRepository - { - get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); - set => _ownershipRepository = value; - } + // private static IContextRepository? _realContextRepository; + // private static IContextRepository? _remoteEndpointContextRepository; + // private static IOwnershipRepository? _ownershipRepository; + // + // public static IContextRepository RealContextRepository + // { + // get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); + // set => _realContextRepository = value; + // } + // + // public static IContextRepository RemoteEndpointContextRepository + // { + // get => _remoteEndpointContextRepository ?? + // throw new NullReferenceException("RemoteEndpointContextRepository is null"); + // set => _remoteEndpointContextRepository = value; + // } + // + // public static IOwnershipRepository OwnershipRepository + // { + // get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); + // set => _ownershipRepository = value; + // } } } \ No newline at end of file From 82c1cf72a0e97ad19ee345db3762740ee4fbedb0 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Mon, 5 May 2025 16:34:57 +0300 Subject: [PATCH 20/32] Additional preprocessor changes --- Example.Frontend/Program.cs | 2 +- .../ChannelInteractionModule.cs | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 9abe3b1..f85e261 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -54,7 +54,7 @@ class Program DemoCheck.CreatingPrinter = true; disposingPrinter.OnPrint += (_, _) => { - Console.WriteLine("New page creater. Called from event!!!"); + Console.WriteLine("New page created. Called from event!!!"); DemoCheck.EventCallback = true; }; Console.WriteLine("Printer created"); diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index d8b999f..78bf915 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -20,6 +20,7 @@ namespace mROA.Implementation private bool _isActive = true; private TaskCompletionSource _reconnection; public IEndPointContext Context { get; set; } + public ChannelInteractionModule() { ReceiveChanel = Channel.CreateUnbounded(new UnboundedChannelOptions @@ -50,7 +51,7 @@ namespace mROA.Implementation public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; public Func IsConnected { get; set; } - + public void Inject(T dependency) { switch (dependency) @@ -100,7 +101,9 @@ namespace mROA.Implementation { if (withError) { +#if TRACE Console.WriteLine("Post again"); +#endif } if (await PostMessageInternal(messageHeader)) @@ -131,19 +134,24 @@ namespace mROA.Implementation await PostMessageAsync( new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), Context)); var ping = await ReceiveChanel.Reader.ReadAsync(); +#if TRACE Console.WriteLine($"Ping received {ping.Id}"); +#endif } else { await _trustedWriter.WriteAsync(new NetworkMessageHeader()); } +#if TRACE Console.WriteLine("Setting result for reconnection"); +#endif var setting = _reconnection.TrySetResult(null); // _isInReconnectionState = false; _isConnected = true; +#if true Console.WriteLine($"Set result for reconnection {setting}"); - +#endif _reconnection = new TaskCompletionSource(); } @@ -151,29 +159,40 @@ namespace mROA.Implementation { //TODO переделать реконнект +#if TRACE Console.WriteLine("Staring recovery from {0}", source); +#endif lock (_reconnection) { +#if TRACE Console.WriteLine("Got lock from {0}", source); Console.WriteLine("Call OnDisconnected from {0}", source); +#endif OnDisconnected?.Invoke(ConnectionId); } +#if TRACE Console.WriteLine("Waiting for reconnect from {0}", source); +#endif if (!_reconnection.Task.IsCompleted && !_isConnected) { +#if TRACE Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); +#endif await _reconnection.Task; } - +#if TRACE Console.WriteLine("Reconnect finished from {0}", source); +#endif } public void Dispose() { +#if TRACE Console.WriteLine("Interaction module disposed"); +#endif _isActive = false; if (_currentReceiving is { IsCompleted: true }) { @@ -191,7 +210,8 @@ namespace mROA.Implementation private IEndPointContext Context; public readonly int Id = new Random().Next(); - public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit, IEndPointContext context) + public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit, + IEndPointContext context) { _ioStream = ioStream; _serializationToolkit = serializationToolkit; @@ -250,7 +270,6 @@ namespace mROA.Implementation public async Task Send(NetworkMessageHeader message, CancellationToken token = default) { - try { var rawMessage = _serializationToolkit.Serialize(message, Context); From dae96c96742c85929e603a3a8f487d885bc051e2 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 6 May 2025 23:20:57 +0300 Subject: [PATCH 21/32] First Unity code equating session --- .../ChannelInteractionModule.cs | 82 ++----------------- 1 file changed, 5 insertions(+), 77 deletions(-) diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index 78bf915..e9f36e8 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -93,19 +93,10 @@ namespace mROA.Implementation { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - - // Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message)); - + bool withError = false; while (true) { - if (withError) - { -#if TRACE - Console.WriteLine("Post again"); -#endif - } - if (await PostMessageInternal(messageHeader)) break; @@ -134,65 +125,34 @@ namespace mROA.Implementation await PostMessageAsync( new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), Context)); var ping = await ReceiveChanel.Reader.ReadAsync(); -#if TRACE - Console.WriteLine($"Ping received {ping.Id}"); -#endif } else { await _trustedWriter.WriteAsync(new NetworkMessageHeader()); } -#if TRACE - Console.WriteLine("Setting result for reconnection"); -#endif var setting = _reconnection.TrySetResult(null); // _isInReconnectionState = false; _isConnected = true; -#if true - Console.WriteLine($"Set result for reconnection {setting}"); -#endif _reconnection = new TaskCompletionSource(); } private async Task MakeRecovery(string source) { //TODO переделать реконнект - -#if TRACE - Console.WriteLine("Staring recovery from {0}", source); -#endif - lock (_reconnection) { -#if TRACE - Console.WriteLine("Got lock from {0}", source); - - Console.WriteLine("Call OnDisconnected from {0}", source); -#endif OnDisconnected?.Invoke(ConnectionId); } -#if TRACE - Console.WriteLine("Waiting for reconnect from {0}", source); -#endif if (!_reconnection.Task.IsCompleted && !_isConnected) { -#if TRACE - Console.WriteLine("Current connection state {0} from {1}", _isConnected, source); -#endif await _reconnection.Task; } -#if TRACE - Console.WriteLine("Reconnect finished from {0}", source); -#endif } public void Dispose() { -#if TRACE - Console.WriteLine("Interaction module disposed"); -#endif _isActive = false; if (_currentReceiving is { IsCompleted: true }) { @@ -239,29 +199,17 @@ namespace mROA.Implementation public async Task SingleReceive(CancellationToken Token = default) { -#if TRACE - Console.WriteLine($"[{Id}] Single receive started"); -#endif var len = ReadMessageLength(); var localSpan = _buffer[..len]; await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); var message = _serializationToolkit.Deserialize(localSpan, Context); -#if TRACE - Console.WriteLine( - $"{DateTime.Now.TimeOfDay} [{Id}] Received Message {message.Id} - {message.MessageType}"); - TransmissionConfig.TotalTransmittedBytes += len; - Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); -#endif MessageReceived(message); } public async Task LoopedReceive(CancellationToken token = default) { -#if TRACE - Console.WriteLine("LoopedReceive started"); -#endif while (token.IsCancellationRequested == false && IsConnected) { await SingleReceive(token); @@ -270,31 +218,11 @@ namespace mROA.Implementation public async Task Send(NetworkMessageHeader message, CancellationToken token = default) { - try - { - var rawMessage = _serializationToolkit.Serialize(message, Context); - var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); + var rawMessage = _serializationToolkit.Serialize(message, Context); + var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); -#if TRACE - Console.WriteLine( - $"{DateTime.Now.TimeOfDay} [{Id}] Posting Message {message.Id} - {message.MessageType}"); - TransmissionConfig.TotalTransmittedBytes += rawMessage.Length; - Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}"); -#endif - - await _ioStream.WriteAsync(header, token); - await _ioStream.WriteAsync(rawMessage, token); -#if TRACE - Console.WriteLine( - $"{DateTime.Now.TimeOfDay} [{Id}] Posting finished {message.Id} - {message.MessageType}"); - -#endif - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } + await _ioStream.WriteAsync(header, token); + await _ioStream.WriteAsync(rawMessage, token); } public async Task SendFromChannel(ChannelReader channel, From 2155c8f0d8c25d4851503f7e7683bb158103ee09 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 6 May 2025 23:25:52 +0300 Subject: [PATCH 22/32] Second Unity code equating session --- .../Backend/BasicExecutionModule.cs | 13 +--------- .../Backend/NetworkGatewayModule.cs | 24 +++++++------------ .../Frontend/NetworkFrontendBridge.cs | 3 --- .../Frontend/RequestExtractor.cs | 22 ----------------- .../Frontend/UdpUntrustedInteraction.cs | 8 ++----- 5 files changed, 11 insertions(+), 59 deletions(-) diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index d5f3f09..5848de9 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -30,18 +30,12 @@ namespace mROA.Implementation.Backend public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, IRepresentationModule representationModule, IEndPointContext endPointContext) { -#if TRACE - Console.WriteLine(command.GetType().Name); -#endif try { ThrowIfNotInjected(contextRepository); if (command is CancelRequest) { -#if TRACE - Console.WriteLine("Final cancelling request"); -#endif return CancelExecution(command); } @@ -76,9 +70,6 @@ namespace mROA.Implementation.Backend var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); if (command.CommandId == -1) { -#if TRACE - Console.WriteLine("Disposing object"); -#endif contextRepository.ClearObject(command.ObjectId, endPointContext); } @@ -189,9 +180,7 @@ namespace mROA.Implementation.Backend var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); var token = tokenSource.Token; -#if TRACE - token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}")); -#endif + try { invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ => diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 8fe538c..5fc2548 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -33,15 +33,6 @@ namespace mROA.Implementation.Backend Console.WriteLine("Enter Backspace to stop"); Task.Run(HandleIncomingConnections); - - while (true) - { - var key = Console.ReadKey(); - if (key.Key == ConsoleKey.Backspace) - break; - } - - Console.WriteLine("Stopping"); } public void Dispose() @@ -62,13 +53,13 @@ namespace mROA.Implementation.Backend } } - private void HandleIncomingConnections() + private async Task HandleIncomingConnections() { ThrowIfNotInjected(); while (true) { - var client = _tcpListener.AcceptTcpClient(); + var client = await _tcpListener.AcceptTcpClientAsync(); Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); var interaction = Activator.CreateInstance(_interactionModuleType!) as IChannelInteractionModule; @@ -84,10 +75,12 @@ namespace mROA.Implementation.Backend var streamExtractor = new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization, context); interaction.IsConnected = () => streamExtractor.IsConnected; - streamExtractor.MessageReceived = message => { interaction.ReceiveChanel.Writer.WriteAsync(message); }; - streamExtractor.SingleReceive(); - var connectionRequest = interaction.GetNextMessageReceiving(false) - .GetAwaiter().GetResult()!; + streamExtractor.MessageReceived = async message => + { + await interaction.ReceiveChanel.Writer.WriteAsync(message); + }; + Task.Run(() => streamExtractor.SingleReceive()); + var connectionRequest = await interaction.ReceiveChanel.Reader.ReadAsync(); var cts = new CancellationTokenSource(); switch (connectionRequest.MessageType) @@ -121,7 +114,6 @@ namespace mROA.Implementation.Backend recoveryInteraction.Restart(false); - Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id); break; } default: diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 2b287fa..04d6248 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -1,10 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; using Exception = System.Exception; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 3311ca6..3edccaf 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,7 +1,4 @@ using System; -#if TRACE -using System.Diagnostics; -#endif using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -16,8 +13,6 @@ namespace mROA.Implementation.Frontend private IMethodRepository? _methodRepository; - // private IContextRepository? _realContextRepository; - // private IContextRepository? _remoteContextRepository; private IRepresentationModule? _representationModule; private IContextualSerializationToolKit? _serializationToolkit; private IEndPointContext _context; @@ -51,9 +46,6 @@ namespace mROA.Implementation.Frontend try { -#if TRACE - var sw = new Stopwatch(); -#endif var streamTokenSource = new CancellationTokenSource(); @@ -69,20 +61,6 @@ namespace mROA.Implementation.Frontend await foreach (var command in query) { -#if TRACE - Console.WriteLine("Waiting for request..."); - if (sw.IsRunning) - { - sw.Stop(); - Console.WriteLine( - $"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds."); - } -#endif - -#if TRACE - Console.WriteLine("Request received"); - sw.Restart(); -#endif switch (command.originalType) { case EMessageType.CallRequest: diff --git a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs index 941ac08..5d4d4cf 100644 --- a/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs +++ b/mROA/Implementation/Frontend/UdpUntrustedInteraction.cs @@ -60,13 +60,9 @@ namespace mROA.Implementation.Frontend continue; var serialized = _serializationToolkit.Serialize(post, _context); -#if TRACE - Console.WriteLine("Untrusted write start"); -#endif + await udpClient.SendAsync(serialized, serialized.Length); -#if TRACE - Console.WriteLine("Untrusted write finished"); -#endif + } } From 99015a3d5efc20212376983da527bcd86756998f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 6 May 2025 23:28:00 +0300 Subject: [PATCH 23/32] Server ReadLine changes --- Example.Backend/Program.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 95f8c36..88a9490 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using System.Net; using Example.Backend; using mROA.Abstract; @@ -44,10 +45,12 @@ class Program builder.Build(); new RemoteTypeBinder(); - + _ = builder.GetModule()!.Start(); var gateway = builder.GetModule(); gateway.Run(); + + Console.ReadLine(); } } \ No newline at end of file From 2f65fb24c0165f0a4ab730839fda53fb7ccaf33c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Wed, 7 May 2025 09:03:20 +0300 Subject: [PATCH 24/32] Event binding bug found --- Example.Frontend/Program.cs | 9 ++++----- mROA.Cbor/CborSerializationToolkit.cs | 3 ++- mROA/Abstract/IFrontendBridge.cs | 3 ++- mROA/Implementation/Backend/ContextRepository.cs | 6 +++--- mROA/Implementation/Frontend/NetworkFrontendBridge.cs | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index f85e261..129e91d 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -16,11 +16,11 @@ using mROA.Implementation.Frontend; class Program { - public static void Main(string[] args) + public static async Task Main(string[] args) { var builder = new FullMixBuilder(); new RemoteTypeBinder(); - // builder.Modules.Add(new JsonSerializationToolkit()); + builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new EndPointContext()); builder.Modules.Add(new RemoteContextRepository()); @@ -39,7 +39,7 @@ class Program builder.Build(); var frontendBridge = builder.GetModule()!; - frontendBridge.Connect(); + await frontendBridge.Connect(); _ = builder.GetModule()!.StartExtraction(); _ = builder.GetModule().Start(serverEndPoint); Console.WriteLine(builder.GetModule().HostId); @@ -87,8 +87,7 @@ class Program Console.WriteLine("Names: " + string.Join(", ", names)); - var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter() - .GetResult(); + var page = await disposingPrinter.Print("Test Page", false, default, CancellationToken.None); Console.WriteLine("Page printed"); DemoCheck.TaskExecution = true; Console.WriteLine(page.ToString()); diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 425cbe3..672f38d 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -213,7 +213,8 @@ namespace mROA.Cbor if (obj is IShared) { - var generic = obj.GetType().GetInterfaces().FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i)); + var interfaces = obj.GetType().GetInterfaces(); + var generic = interfaces.FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i)); var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(generic); var so = Activator.CreateInstance(sharedShell, obj, context) as diff --git a/mROA/Abstract/IFrontendBridge.cs b/mROA/Abstract/IFrontendBridge.cs index 53217d7..7ce7460 100644 --- a/mROA/Abstract/IFrontendBridge.cs +++ b/mROA/Abstract/IFrontendBridge.cs @@ -1,10 +1,11 @@ using System; +using System.Threading.Tasks; namespace mROA.Abstract { public interface IFrontendBridge : IInjectableModule, IDisposable { - void Connect(); + Task Connect(); void Obstacle(); void Disconnect(); } diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 13541c5..8b7e738 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -32,9 +32,9 @@ namespace mROA.Implementation.Backend public int ResisterObject(object o, IEndPointContext context) { var last = _storage.Place(o); - - EventBinders.OfType>().FirstOrDefault() - ?.BindEvents((T)o, context, _representationModuleProducer!, last); + + var binder = EventBinders.OfType>().FirstOrDefault(); + binder?.BindEvents((T)o, context, _representationModuleProducer!, last); return last; } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 04d6248..8611418 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -40,7 +40,7 @@ namespace mROA.Implementation.Frontend } } - public void Connect() + public async Task Connect() { if (_interactionModule is null) throw new Exception("Interaction module was not injected"); @@ -57,7 +57,7 @@ namespace mROA.Implementation.Frontend .Wait(); _currentExtractor.SingleReceive(); - var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult(); + var idMessage = await _interactionModule.GetNextMessageReceiving(false); if (idMessage.MessageType != EMessageType.IdAssigning) { From bc74a97b1468ba9b38e859693501f78c29a5c9db Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Wed, 7 May 2025 09:55:15 +0300 Subject: [PATCH 25/32] Event binding system update --- mROA.Cbor/CborSerializationToolkit.cs | 4 +--- mROA/Abstract/IEventBinder.cs | 14 +++++++++++++- mROA/Implementation/Backend/ContextRepository.cs | 10 ++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 672f38d..5fc81a5 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -213,9 +213,7 @@ namespace mROA.Cbor if (obj is IShared) { - var interfaces = obj.GetType().GetInterfaces(); - var generic = interfaces.FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i)); - var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(generic); + var sharedShell = typeof(SharedObjectShellShell); var so = Activator.CreateInstance(sharedShell, obj, context) as ISharedObjectShell; diff --git a/mROA/Abstract/IEventBinder.cs b/mROA/Abstract/IEventBinder.cs index 737bfd2..51b11a5 100644 --- a/mROA/Abstract/IEventBinder.cs +++ b/mROA/Abstract/IEventBinder.cs @@ -1,8 +1,20 @@ namespace mROA.Abstract { - public interface IEventBinder + public interface IEventBinder : IEventBinder { public void BindEvents(T source, IEndPointContext context, IRepresentationModuleProducer representationModuleProducer, int index); + + void IEventBinder.BindEvents(object source, IEndPointContext context, IRepresentationModuleProducer representationModuleProducer, + int index) + { + BindEvents((T)source, context, representationModuleProducer, index); + } + } + + public interface IEventBinder + { + public void BindEvents(object source, IEndPointContext context, + IRepresentationModuleProducer representationModuleProducer, int index); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 8b7e738..a18d15c 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -32,9 +32,15 @@ namespace mROA.Implementation.Backend public int ResisterObject(object o, IEndPointContext context) { var last = _storage.Place(o); + + var sharedType = typeof(IShared); + var interfaces = o.GetType().GetInterfaces(); + var generic = interfaces.Where(i => sharedType.IsAssignableFrom(i) && i != sharedType) + .Select(i => typeof(IEventBinder<>).MakeGenericType(i)); - var binder = EventBinders.OfType>().FirstOrDefault(); - binder?.BindEvents((T)o, context, _representationModuleProducer!, last); + var binders = EventBinders.Where(i => generic.Any(g => g.IsAssignableFrom(i.GetType()))); + foreach (var binder in binders) + ((IEventBinder)binder).BindEvents(o, context, _representationModuleProducer!, last); return last; } From 323e9c90035d44978c264d7120f9f596a6765897 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Wed, 7 May 2025 23:34:12 +0300 Subject: [PATCH 26/32] ChannelInteractionModule.cs refactor --- mROA/Abstract/IChannelInteractionModule.cs | 1 - .../ChannelInteractionModule.cs | 42 +++++++------------ 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/mROA/Abstract/IChannelInteractionModule.cs b/mROA/Abstract/IChannelInteractionModule.cs index 1abdb10..e9030d1 100644 --- a/mROA/Abstract/IChannelInteractionModule.cs +++ b/mROA/Abstract/IChannelInteractionModule.cs @@ -9,7 +9,6 @@ namespace mROA.Abstract public interface IChannelInteractionModule : IInjectableModule, IDisposable { int ConnectionId { get; set; } - IEndPointContext Context { get; set; } Channel ReceiveChanel { get; } ChannelReader TrustedPostChanel { get; } ChannelReader UntrustedPostChanel { get; } diff --git a/mROA/Implementation/ChannelInteractionModule.cs b/mROA/Implementation/ChannelInteractionModule.cs index e9f36e8..fcec7bd 100644 --- a/mROA/Implementation/ChannelInteractionModule.cs +++ b/mROA/Implementation/ChannelInteractionModule.cs @@ -14,12 +14,11 @@ namespace mROA.Implementation private readonly ChannelWriter _untrustedWriter; private readonly Channel _outputTrustedChannel; private readonly Channel _outputUntrustedChannel; - private Task? _currentReceiving; private IContextualSerializationToolKit? _serialization; private bool _isConnected = true; private bool _isActive = true; private TaskCompletionSource _reconnection; - public IEndPointContext Context { get; set; } + private IEndPointContext? _context; public ChannelInteractionModule() { @@ -50,7 +49,7 @@ namespace mROA.Implementation public ChannelReader TrustedPostChanel => _outputTrustedChannel.Reader; public ChannelReader UntrustedPostChanel => _outputUntrustedChannel.Reader; - public Func IsConnected { get; set; } + public Func IsConnected { get; set; } = () => false; public void Inject(T dependency) { @@ -63,7 +62,7 @@ namespace mROA.Implementation ConnectionId = identityGenerator.GetNextIdentity(); break; case IEndPointContext endpointContext: - Context = endpointContext; + _context = endpointContext; break; } } @@ -93,8 +92,7 @@ namespace mROA.Implementation { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - - bool withError = false; + while (true) { if (await PostMessageInternal(messageHeader)) @@ -106,8 +104,7 @@ namespace mROA.Implementation } _isConnected = false; - withError = true; - await MakeRecovery("OUT"); + await MakeRecovery(); } } @@ -123,23 +120,21 @@ namespace mROA.Implementation if (sendRecovery) { await PostMessageAsync( - new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), Context)); - var ping = await ReceiveChanel.Reader.ReadAsync(); + new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), _context)); + await ReceiveChanel.Reader.ReadAsync(); } else { await _trustedWriter.WriteAsync(new NetworkMessageHeader()); } - var setting = _reconnection.TrySetResult(null); - // _isInReconnectionState = false; + _reconnection.TrySetResult(Stream.Null); _isConnected = true; _reconnection = new TaskCompletionSource(); } - private async Task MakeRecovery(string source) + private async Task MakeRecovery() { - //TODO переделать реконнект lock (_reconnection) { OnDisconnected?.Invoke(ConnectionId); @@ -154,10 +149,6 @@ namespace mROA.Implementation public void Dispose() { _isActive = false; - if (_currentReceiving is { IsCompleted: true }) - { - _currentReceiving?.Dispose(); - } } public class StreamExtractor @@ -167,15 +158,14 @@ namespace mROA.Implementation private const int BufferSize = ushort.MaxValue; private readonly Memory _buffer = new byte[BufferSize]; private bool _manualConnectionState = true; - private IEndPointContext Context; - public readonly int Id = new Random().Next(); + private readonly IEndPointContext _context; public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit, IEndPointContext context) { _ioStream = ioStream; _serializationToolkit = serializationToolkit; - Context = context; + _context = context; } public Action MessageReceived = _ => { }; @@ -197,14 +187,14 @@ namespace mROA.Implementation return len; } - public async Task SingleReceive(CancellationToken Token = default) + public async Task SingleReceive(CancellationToken token = default) { var len = ReadMessageLength(); var localSpan = _buffer[..len]; - await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: Token); + await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: token); - var message = _serializationToolkit.Deserialize(localSpan, Context); + var message = _serializationToolkit.Deserialize(localSpan, _context); MessageReceived(message); } @@ -216,9 +206,9 @@ namespace mROA.Implementation } } - public async Task Send(NetworkMessageHeader message, CancellationToken token = default) + private async Task Send(NetworkMessageHeader message, CancellationToken token = default) { - var rawMessage = _serializationToolkit.Serialize(message, Context); + var rawMessage = _serializationToolkit.Serialize(message, _context); var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); await _ioStream.WriteAsync(header, token); From dbde8c3d30bc211f2b263863847f353910506f5f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Wed, 7 May 2025 23:50:15 +0300 Subject: [PATCH 27/32] Renaming context repository to instance repository --- Example.Backend/Program.cs | 6 ++-- Example.Frontend/Program.cs | 4 +-- mROA/Abstract/IContextRepositoryHub.cs | 2 +- mROA/Abstract/IEndPointContext.cs | 4 +-- mROA/Abstract/IExecuteModule.cs | 2 +- ...xtRepository.cs => IInstanceRepository.cs} | 2 +- .../Backend/BasicConfigurationExtensions.cs | 2 +- .../Backend/BasicExecutionModule.cs | 18 +++++----- .../Backend/HubRequestExtractor.cs | 12 +++---- ...extRepository.cs => InstanceRepository.cs} | 4 +-- ...ry.cs => MultiClientInstanceRepository.cs} | 12 +++---- ...sitory.cs => ComplexInstanceRepository.cs} | 2 +- mROA/Implementation/EndPointContext.cs | 8 ++--- ...ository.cs => RemoteInstanceRepository.cs} | 2 +- mROA/Implementation/SharedObjectShell.cs | 10 +++--- mROA/Implementation/TransmissionConfig.cs | 35 ------------------- 16 files changed, 46 insertions(+), 79 deletions(-) rename mROA/Abstract/{IContextRepository.cs => IInstanceRepository.cs} (88%) rename mROA/Implementation/Backend/{ContextRepository.cs => InstanceRepository.cs} (97%) rename mROA/Implementation/Backend/{MultiClientContextRepository.cs => MultiClientInstanceRepository.cs} (79%) rename mROA/Implementation/{ComplexContextRepository.cs => ComplexInstanceRepository.cs} (97%) rename mROA/Implementation/{RemoteContextRepository.cs => RemoteInstanceRepository.cs} (97%) delete mode 100644 mROA/Implementation/TransmissionConfig.cs diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 88a9490..15e0604 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -30,11 +30,11 @@ class Program builder.Modules.Add(new CreativeRepresentationModuleProducer( new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); - builder.Modules.Add(new RemoteContextRepository()); + builder.Modules.Add(new RemoteInstanceRepository()); // builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly); - builder.Modules.Add(new MultiClientContextRepository(i => + builder.Modules.Add(new MultiClientInstanceRepository(i => { - var repo = new ContextRepository(); + var repo = new InstanceRepository(); repo.FillSingletons(typeof(PrinterFactory).Assembly); repo.Inject(builder.Modules.OfType().First()); return repo; diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 129e91d..20758fb 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -23,7 +23,7 @@ class Program builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new EndPointContext()); - builder.Modules.Add(new RemoteContextRepository()); + builder.Modules.Add(new RemoteInstanceRepository()); builder.Modules.Add(new ChannelInteractionModule()); builder.Modules.Add(new UdpUntrustedInteraction()); builder.Modules.Add(new RepresentationModule()); @@ -43,7 +43,7 @@ class Program _ = builder.GetModule()!.StartExtraction(); _ = builder.GetModule().Start(serverEndPoint); Console.WriteLine(builder.GetModule().HostId); - var context = builder.GetModule(); + var context = builder.GetModule(); var factory = context.GetSingleObject(typeof(IPrinterFactory), diff --git a/mROA/Abstract/IContextRepositoryHub.cs b/mROA/Abstract/IContextRepositoryHub.cs index 19a7987..ca2e205 100644 --- a/mROA/Abstract/IContextRepositoryHub.cs +++ b/mROA/Abstract/IContextRepositoryHub.cs @@ -2,7 +2,7 @@ namespace mROA.Abstract { public interface IContextRepositoryHub { - IContextRepository GetRepository(int clientId); + IInstanceRepository GetRepository(int clientId); void FreeRepository(int clientId); } } \ No newline at end of file diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs index 44db796..8b5db20 100644 --- a/mROA/Abstract/IEndPointContext.cs +++ b/mROA/Abstract/IEndPointContext.cs @@ -2,8 +2,8 @@ { public interface IEndPointContext : IInjectableModule { - IContextRepository RealRepository { get; } - IContextRepository RemoteRepository { get; } + IInstanceRepository RealRepository { get; } + IInstanceRepository RemoteRepository { get; } int HostId { get; set; } int OwnerId { get; set; } } diff --git a/mROA/Abstract/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs index abf76d6..ea87f0d 100644 --- a/mROA/Abstract/IExecuteModule.cs +++ b/mROA/Abstract/IExecuteModule.cs @@ -4,7 +4,7 @@ namespace mROA.Abstract { public interface IExecuteModule : IInjectableModule { - ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, + ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository, IRepresentationModule representationModule, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IInstanceRepository.cs similarity index 88% rename from mROA/Abstract/IContextRepository.cs rename to mROA/Abstract/IInstanceRepository.cs index f4857c7..2e3ef2f 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IInstanceRepository.cs @@ -3,7 +3,7 @@ using mROA.Implementation; namespace mROA.Abstract { - public interface IContextRepository : IInjectableModule + public interface IInstanceRepository : IInjectableModule { int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); diff --git a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs index 57b5f65..a10bdd3 100644 --- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs +++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs @@ -21,7 +21,7 @@ namespace mROA.Implementation.Backend public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies) { - var repo = new ContextRepository(); + var repo = new InstanceRepository(); repo.FillSingletons(assemblies); builder.Modules.Add(repo); } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 5848de9..69ceee4 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -27,13 +27,13 @@ namespace mROA.Implementation.Backend } } - public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, + public ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository, IRepresentationModule representationModule, IEndPointContext endPointContext) { try { - ThrowIfNotInjected(contextRepository); + ThrowIfNotInjected(instanceRepository); if (command is CancelRequest) { return CancelExecution(command); @@ -43,7 +43,7 @@ namespace mROA.Implementation.Backend if (invoker == null) throw new Exception($"Command {command.CommandId} not found"); - var context = GetContext(command, contextRepository, invoker, endPointContext); + var context = GetContext(command, instanceRepository, invoker, endPointContext); if (context == null) throw new NullReferenceException("Instance can't be null"); @@ -70,7 +70,7 @@ namespace mROA.Implementation.Backend var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); if (command.CommandId == -1) { - contextRepository.ClearObject(command.ObjectId, endPointContext); + instanceRepository.ClearObject(command.ObjectId, endPointContext); } return result; @@ -86,12 +86,12 @@ namespace mROA.Implementation.Backend } } - private static object GetContext(ICallRequest command, IContextRepository contextRepository, + private static object GetContext(ICallRequest command, IInstanceRepository instanceRepository, IMethodInvoker invoker, IEndPointContext endPointContext) { var context = command.ObjectId.ContextId != -1 - ? contextRepository.GetObject(command.ObjectId, endPointContext) - : contextRepository.GetSingleObject(invoker.SuitableType, endPointContext); + ? instanceRepository.GetObject(command.ObjectId, endPointContext) + : instanceRepository.GetSingleObject(invoker.SuitableType, endPointContext); return context; } @@ -106,7 +106,7 @@ namespace mROA.Implementation.Backend return castedParams; } - private void ThrowIfNotInjected(IContextRepository contextRepository) + private void ThrowIfNotInjected(IInstanceRepository instanceRepository) { if (_cancellationRepo is null) throw new NullReferenceException("Method repository was not defined"); @@ -114,7 +114,7 @@ namespace mROA.Implementation.Backend if (_methodRepo is null) throw new NullReferenceException("Method repository was not defined"); - if (contextRepository is null) + if (instanceRepository is null) throw new NullReferenceException("Context repository was not defined"); } diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 7c35b33..7a51339 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -7,8 +7,8 @@ namespace mROA.Implementation.Backend { private IConnectionHub? _hub; - private IContextRepository? _contextRepository; - private IContextRepository? _remoteContextRepository; + private IInstanceRepository? _contextRepository; + private IInstanceRepository? _remoteContextRepository; private IMethodRepository? _methodRepository; private IContextualSerializationToolKit? _serializationToolkit; private IExecuteModule? _executeModule; @@ -21,11 +21,11 @@ namespace mROA.Implementation.Backend _hub = connectionHub; _hub.OnConnected += HubOnOnConnected; break; - case MultiClientContextRepository: - case ContextRepository: - _contextRepository = dependency as IContextRepository; + case MultiClientInstanceRepository: + case InstanceRepository: + _contextRepository = dependency as IInstanceRepository; break; - case RemoteContextRepository remoteContextRepository: + case RemoteInstanceRepository remoteContextRepository: _remoteContextRepository = remoteContextRepository; break; case IMethodRepository methodRepository: diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/InstanceRepository.cs similarity index 97% rename from mROA/Implementation/Backend/ContextRepository.cs rename to mROA/Implementation/Backend/InstanceRepository.cs index a18d15c..9b71859 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/InstanceRepository.cs @@ -8,7 +8,7 @@ using mROA.Implementation.Attributes; namespace mROA.Implementation.Backend { - public class ContextRepository : IContextRepository + public class InstanceRepository : IInstanceRepository { public static object[] EventBinders = { }; @@ -22,7 +22,7 @@ namespace mROA.Implementation.Backend private IStorage _storage; - public ContextRepository() + public InstanceRepository() { _storage = new ExtensibleStorage(); } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs similarity index 79% rename from mROA/Implementation/Backend/MultiClientContextRepository.cs rename to mROA/Implementation/Backend/MultiClientInstanceRepository.cs index 8d63cd3..520e4cb 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs @@ -4,12 +4,12 @@ using mROA.Abstract; namespace mROA.Implementation.Backend { - public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub + public class MultiClientInstanceRepository : IInstanceRepository, IContextRepositoryHub { - private readonly Func _produceRepository; - private readonly Dictionary _repositories = new(); + private readonly Func _produceRepository; + private readonly Dictionary _repositories = new(); - public MultiClientContextRepository(Func produceRepository) + public MultiClientInstanceRepository(Func produceRepository) { _produceRepository = produceRepository; } @@ -50,7 +50,7 @@ namespace mROA.Implementation.Backend return repository.GetObjectIndex(o, context); } - public IContextRepository GetRepository(int clientId) + public IInstanceRepository GetRepository(int clientId) { var repository = GetRepositoryByClientId(clientId); return repository; @@ -61,7 +61,7 @@ namespace mROA.Implementation.Backend _repositories.Remove(clientId); } - private IContextRepository GetRepositoryByClientId(int clientId) + private IInstanceRepository GetRepositoryByClientId(int clientId) { if (_repositories.TryGetValue(clientId, out var repository)) return repository; diff --git a/mROA/Implementation/ComplexContextRepository.cs b/mROA/Implementation/ComplexInstanceRepository.cs similarity index 97% rename from mROA/Implementation/ComplexContextRepository.cs rename to mROA/Implementation/ComplexInstanceRepository.cs index b074da9..09be507 100644 --- a/mROA/Implementation/ComplexContextRepository.cs +++ b/mROA/Implementation/ComplexInstanceRepository.cs @@ -5,7 +5,7 @@ using mROA.Abstract; namespace mROA.Implementation { - public class ComplexContextRepository : IContextRepository + public class ComplexInstanceRepository : IInstanceRepository { private List>> _storages = new(); public static object[] EventBinders = { }; diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index 6962f86..1978f2c 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -6,8 +6,8 @@ namespace mROA.Implementation { public class EndPointContext : IEndPointContext { - public IContextRepository RealRepository { get; set; } - public IContextRepository RemoteRepository { get; set; } + public IInstanceRepository RealRepository { get; set; } + public IInstanceRepository RemoteRepository { get; set; } public int HostId { get; set; } public int OwnerId { get; set; } @@ -16,10 +16,10 @@ namespace mROA.Implementation { switch (dependency) { - case RemoteContextRepository remoteRepository: + case RemoteInstanceRepository remoteRepository: RemoteRepository = remoteRepository; break; - case ContextRepository realRepository: + case InstanceRepository realRepository: RealRepository = realRepository; break; } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteInstanceRepository.cs similarity index 97% rename from mROA/Implementation/RemoteContextRepository.cs rename to mROA/Implementation/RemoteInstanceRepository.cs index 9ab5dd8..1d00f42 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteInstanceRepository.cs @@ -5,7 +5,7 @@ using mROA.Abstract; namespace mROA.Implementation { - public class RemoteContextRepository : IContextRepository + public class RemoteInstanceRepository : IInstanceRepository { private List _producedRemoteEndpoints = new(); public static Dictionary RemoteTypes = new(); diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 01305db..a9f5246 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -20,12 +20,14 @@ namespace mROA.Implementation { private ComplexObjectIdentifier _identifier = ComplexObjectIdentifier.Null; - private T _value; + private T? _value; // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once UnusedMember.Global public SharedObjectShellShell() { + _value = default; + EndPointContext = new EndPointContext(); } // ReSharper disable once UnusedMember.Global @@ -41,7 +43,7 @@ namespace mROA.Implementation // ReSharper disable once MemberCanBePrivate.Global public T Value { - get => _value; + get => _value!; set { _value = value; @@ -76,11 +78,11 @@ namespace mROA.Implementation public object UniversalValue { - get => _value; + get => _value!; set => _value = (T)value; } - private IContextRepository GetDefaultContextRepository() => + private IInstanceRepository GetDefaultContextRepository() => (_identifier.OwnerId == EndPointContext.HostId ? EndPointContext.RealRepository : EndPointContext.RemoteRepository) ?? diff --git a/mROA/Implementation/TransmissionConfig.cs b/mROA/Implementation/TransmissionConfig.cs deleted file mode 100644 index 013995a..0000000 --- a/mROA/Implementation/TransmissionConfig.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using mROA.Abstract; - -namespace mROA.Implementation -{ -#pragma warning disable CS8618, CS9264 - public static class TransmissionConfig - { -#if TRACE - public static int TotalTransmittedBytes { get; set; } -#endif - // private static IContextRepository? _realContextRepository; - // private static IContextRepository? _remoteEndpointContextRepository; - // private static IOwnershipRepository? _ownershipRepository; - // - // public static IContextRepository RealContextRepository - // { - // get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); - // set => _realContextRepository = value; - // } - // - // public static IContextRepository RemoteEndpointContextRepository - // { - // get => _remoteEndpointContextRepository ?? - // throw new NullReferenceException("RemoteEndpointContextRepository is null"); - // set => _remoteEndpointContextRepository = value; - // } - // - // public static IOwnershipRepository OwnershipRepository - // { - // get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); - // set => _ownershipRepository = value; - // } - } -} \ No newline at end of file From 5a0357c42e0b5af1d028080c3dfa5ae5f2e1ae0c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 8 May 2025 00:04:53 +0300 Subject: [PATCH 28/32] Some interfaces cleanup --- Example.Frontend/Program.cs | 1 - mROA.Codegen/RemoteTypeBinder.cstmpl | 4 +- mROA/Abstract/IChannelInteractionModule.cs | 1 - mROA/Abstract/IInstanceRepository.cs | 1 - mROA/Abstract/ISerializationToolkit.cs | 4 +- mROA/Abstract/IUntrustedGateway.cs | 1 - .../Backend/InstanceRepository.cs | 1 - .../Backend/NetworkGatewayModule.cs | 1 - mROA/Implementation/Backend/UdpGateway.cs | 1 - mROA/Implementation/EndPointContext.cs | 1 - mROA/Implementation/EventBinder.cs | 5 +- .../JsonSerializationToolkit.cs | 61 ------------------- mROA/Implementation/MethodInvoker.cs | 2 +- mROA/Implementation/NetworkMessageHeader.cs | 14 +---- mROA/Implementation/RemoteObjectBase.cs | 1 - mROA/Implementation/RepresentationModule.cs | 1 + 16 files changed, 9 insertions(+), 91 deletions(-) delete mode 100644 mROA/Implementation/JsonSerializationToolkit.cs diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 20758fb..07d7ff4 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -1,6 +1,5 @@ using System; using System.Net; -using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; diff --git a/mROA.Codegen/RemoteTypeBinder.cstmpl b/mROA.Codegen/RemoteTypeBinder.cstmpl index bbef815..69eff9c 100644 --- a/mROA.Codegen/RemoteTypeBinder.cstmpl +++ b/mROA.Codegen/RemoteTypeBinder.cstmpl @@ -11,11 +11,11 @@ namespace mROA.Codegen public sealed class RemoteTypeBinder { static RemoteTypeBinder(){ - RemoteContextRepository.RemoteTypes = new Dictionary { + RemoteInstanceRepository.RemoteTypes = new Dictionary { , }; - ContextRepository.EventBinders = new object[] { + InstanceRepository.EventBinders = new object[] { new EventBinder<> diff --git a/mROA/Abstract/IChannelInteractionModule.cs b/mROA/Abstract/IChannelInteractionModule.cs index e9030d1..2c59de3 100644 --- a/mROA/Abstract/IChannelInteractionModule.cs +++ b/mROA/Abstract/IChannelInteractionModule.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Threading.Channels; using System.Threading.Tasks; using mROA.Implementation; diff --git a/mROA/Abstract/IInstanceRepository.cs b/mROA/Abstract/IInstanceRepository.cs index 2e3ef2f..7086178 100644 --- a/mROA/Abstract/IInstanceRepository.cs +++ b/mROA/Abstract/IInstanceRepository.cs @@ -5,7 +5,6 @@ namespace mROA.Abstract { public interface IInstanceRepository : IInjectableModule { - int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); void ClearObject(ComplexObjectIdentifier id, IEndPointContext context); T GetObject(ComplexObjectIdentifier id, IEndPointContext context); diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs index 92b806a..6761e10 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -1,6 +1,4 @@ -using System; - -namespace mROA.Abstract +namespace mROA.Abstract { // public interface IContextualSerializationToolKit : IInjectableModule // { diff --git a/mROA/Abstract/IUntrustedGateway.cs b/mROA/Abstract/IUntrustedGateway.cs index 9cb5fee..1c6f25c 100644 --- a/mROA/Abstract/IUntrustedGateway.cs +++ b/mROA/Abstract/IUntrustedGateway.cs @@ -1,5 +1,4 @@ using System; -using System.Net; using System.Threading.Tasks; namespace mROA.Abstract diff --git a/mROA/Implementation/Backend/InstanceRepository.cs b/mROA/Implementation/Backend/InstanceRepository.cs index 9b71859..4c7c9e5 100644 --- a/mROA/Implementation/Backend/InstanceRepository.cs +++ b/mROA/Implementation/Backend/InstanceRepository.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; -using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.Attributes; diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 5fc2548..f4e9d3c 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; diff --git a/mROA/Implementation/Backend/UdpGateway.cs b/mROA/Implementation/Backend/UdpGateway.cs index d2642bb..1945e0f 100644 --- a/mROA/Implementation/Backend/UdpGateway.cs +++ b/mROA/Implementation/Backend/UdpGateway.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; -using System.Threading.Channels; using System.Threading.Tasks; using mROA.Abstract; using static mROA.Implementation.EMessageType; diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index 1978f2c..5694614 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -1,4 +1,3 @@ -using System; using mROA.Abstract; using mROA.Implementation.Backend; diff --git a/mROA/Implementation/EventBinder.cs b/mROA/Implementation/EventBinder.cs index 8354c4f..429a882 100644 --- a/mROA/Implementation/EventBinder.cs +++ b/mROA/Implementation/EventBinder.cs @@ -1,10 +1,11 @@ using System; +using mROA.Abstract; -namespace mROA.Abstract +namespace mROA.Implementation { public class EventBinder : IEventBinder { - public Action BindAction { get; set; } + public Action BindAction { get; set; } = (_, _, _, _) => { }; public void BindEvents(T source, IEndPointContext context, IRepresentationModuleProducer representationModuleProducer, int index) diff --git a/mROA/Implementation/JsonSerializationToolkit.cs b/mROA/Implementation/JsonSerializationToolkit.cs deleted file mode 100644 index 38f8c19..0000000 --- a/mROA/Implementation/JsonSerializationToolkit.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.Text.Json; -using mROA.Abstract; - -namespace mROA.Implementation -{ - // public class JsonSerializationToolkit : IContextualSerializationToolKit - // { - // public byte[] Serialize(T objectToSerialize) - // { - // return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize); - // } - // - // public byte[] Serialize(object objectToSerialize, Type type) - // { - // return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type); - // } - // - // public T? Deserialize(byte[] rawData) - // { - // return JsonSerializer.Deserialize(rawData); - // } - // - // public object? Deserialize(byte[] rawData, Type type) - // { - // return JsonSerializer.Deserialize(rawData, type); - // } - // - // public T? Deserialize(Span rawData) - // { - // return JsonSerializer.Deserialize(rawData); - // } - // - // public object? Deserialize(Span rawData, Type type) - // { - // return JsonSerializer.Deserialize(rawData, type); - // } - // - // public T Cast(object nonCasted) - // { - // return nonCasted switch - // { - // JsonElement jsonElement => jsonElement.Deserialize()!, - // T casted => casted, - // _ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName) - // }; - // } - // - // public object Cast(object nonCasted, Type type) - // { - // if (nonCasted is JsonElement jsonElement) - // return jsonElement.Deserialize(type)!; - // - // throw new JsonException("Cannot cast object to type " + type.FullName); - // } - // - // public void Inject(T dependency) - // { - // } - // } -} \ No newline at end of file diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index ff713db..4f1e26c 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -36,7 +36,7 @@ namespace mROA.Implementation public bool IsTrusted { get; set; } = true; public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } - public Type SuitableType { get; set; } + public Type SuitableType { get; set; } = typeof(object); public Action> Invoking { get; set; } = (_, _, _, post) => { post.Invoke(null); }; diff --git a/mROA/Implementation/NetworkMessageHeader.cs b/mROA/Implementation/NetworkMessageHeader.cs index cb31c3e..0a0a271 100644 --- a/mROA/Implementation/NetworkMessageHeader.cs +++ b/mROA/Implementation/NetworkMessageHeader.cs @@ -1,7 +1,5 @@ using System; -using System.Text.Json.Serialization; using mROA.Abstract; -using mROA.Implementation.Attributes; // ReSharper disable UnusedMember.Global @@ -9,7 +7,7 @@ namespace mROA.Implementation { public class NetworkMessageHeader { - protected bool Equals(NetworkMessageHeader other) + private bool Equals(NetworkMessageHeader other) { return Id.Equals(other.Id) && MessageType == other.MessageType; } @@ -22,11 +20,6 @@ namespace mROA.Implementation return Equals((NetworkMessageHeader)obj); } - public override int GetHashCode() - { - return HashCode.Combine(Id, (int)MessageType); - } - public static readonly NetworkMessageHeader Null = new(); public NetworkMessageHeader() { @@ -43,13 +36,8 @@ namespace mROA.Implementation } public Guid Id { get; set; } - [JsonConverter(typeof(JsonStringEnumConverter))] public EMessageType MessageType { get; set; } public byte[] Data { get; set; } - - [JsonIgnore] - [SerializationIgnore] - public object Parced { get; set; } } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index efcbeed..3410e97 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -1,5 +1,4 @@ using System; -using System.Net; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index bb9d40c..d406d59 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -5,6 +5,7 @@ using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; +#pragma warning disable CS8602 // Dereference of a possibly null reference. namespace mROA.Implementation { From 56d82ecdef095ab208603455cc64d1d4bfee5135 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 8 May 2025 00:11:24 +0300 Subject: [PATCH 29/32] Load test back --- Example.Frontend/Program.cs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 07d7ff4..0434e06 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Net; using System.Text; using System.Threading; @@ -120,23 +121,25 @@ class Program Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}"); DemoCheck.TaskCancelation = true; + const int iterations = 10000; + var timer = Stopwatch.StartNew(); + var x = 0; + for (int i = 0; i < iterations; i++) + { + x = loadSingleton.Next(x); + } + + timer.Stop(); + Console.WriteLine("X is {0}", x); + Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds); + Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms"); + frontendBridge.Disconnect(); DemoCheck.Show(); Console.ReadKey(); - // - // const int iterations = 10000; - // var timer = Stopwatch.StartNew(); - // var x = 0; - // for (int i = 0; i < iterations; i++) - // { - // x = loadSingleton.Next(x); - // } - // - // timer.Stop(); - // Console.WriteLine("X is {0}", x); - // Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds); - // Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms"); + + } } \ No newline at end of file From d48ac20f7d1e25779a771969b93fe011a2493e34 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Wed, 14 May 2025 12:58:14 +0300 Subject: [PATCH 30/32] Cbor bug fixes --- Example.Backend/Printer.cs | 6 ++++++ Example.Frontend/ClientBasedPrinter.cs | 5 +++++ Example.Frontend/Program.cs | 5 +++++ Example.Shared/IPrinter.cs | 1 + mROA.Cbor/PreParsedValue.cs | 15 +++++++++++++++ mROA.Cbor/mROA.Cbor.csproj | 3 +++ 6 files changed, 35 insertions(+) diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index dba9a98..9e9bb07 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -15,6 +15,12 @@ namespace Example.Backend Console.WriteLine(humanName + " is approaching"); } + public Task SetFingerPrint(int[] fingerPrint) + { + Console.WriteLine(fingerPrint.Length); + return Task.CompletedTask; + } + public void OnPrintExternal(IPage p0, RequestContext ro) { OnPrint?.Invoke(p0, ro); diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 1233514..1c4f0cb 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -13,6 +13,11 @@ namespace Example.Frontend return Task.CompletedTask; } + public Task SetFingerPrint(int[] fingerPrint) + { + return Task.CompletedTask; + } + public void OnPrintExternal(IPage p0, RequestContext ro) { } diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 129e91d..b118593 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -51,6 +51,11 @@ class Program using (var disposingPrinter = factory.Create("Test")) { + disposingPrinter.SetFingerPrint(new[] { 1, 2, 3 }).ContinueWith(r => + { + Console.WriteLine(r.Status); + }); + DemoCheck.CreatingPrinter = true; disposingPrinter.OnPrint += (_, _) => { diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 505d614..e34b889 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -15,5 +15,6 @@ namespace Example.Shared event Action OnPrint; [Untrusted] Task SomeoneIsApproaching(string humanName); + Task SetFingerPrint(int[] fingerPrint); } } \ No newline at end of file diff --git a/mROA.Cbor/PreParsedValue.cs b/mROA.Cbor/PreParsedValue.cs index 9737b7e..c1b1575 100644 --- a/mROA.Cbor/PreParsedValue.cs +++ b/mROA.Cbor/PreParsedValue.cs @@ -1,5 +1,7 @@ using System; +using System.Collections; using System.Collections.Generic; +using System.Linq; using mROA.Abstract; using mROA.Implementation; @@ -34,6 +36,19 @@ namespace mROA.Cbor return so.UniversalValue; } + + if (type is { IsArray: true }) + { + var elementType = type.GetElementType(); + var array = Array.CreateInstance(elementType, _properties.Count); + Array.Copy(_properties.Select(i => Convert.ChangeType(i,elementType)).ToArray(), array, _properties.Count); + return array; + } + + + if (typeof(IList).IsAssignableFrom(type)) + return Convert.ChangeType(_properties.Select(i => Convert.ChangeType(i, type.GetElementType())).ToList(), type); + var instance = Activator.CreateInstance(type); if (instance == null) return null; diff --git a/mROA.Cbor/mROA.Cbor.csproj b/mROA.Cbor/mROA.Cbor.csproj index a2dbaf9..e59df81 100644 --- a/mROA.Cbor/mROA.Cbor.csproj +++ b/mROA.Cbor/mROA.Cbor.csproj @@ -3,6 +3,9 @@ netstandard2.1 enable + true + 2.0.1 + 9 From 46386923054bc58e2a7e23a4b21fba88a7c709a5 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Wed, 14 May 2025 14:25:45 +0300 Subject: [PATCH 31/32] SharedObjectShell bug fix --- Example.Frontend/Program.cs | 1 + mROA.Cbor/mROA.Cbor.csproj | 2 +- mROA/Implementation/SharedObjectShell.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index c892c90..28957ce 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -76,6 +76,7 @@ class Program Console.WriteLine("Approaching detected"); factory.Register(new ClientBasedPrinter()); + factory.Register(disposingPrinter); DemoCheck.ClientBasedImplementation = true; Console.WriteLine("Registered printer"); Thread.Sleep(100); diff --git a/mROA.Cbor/mROA.Cbor.csproj b/mROA.Cbor/mROA.Cbor.csproj index e59df81..1950f08 100644 --- a/mROA.Cbor/mROA.Cbor.csproj +++ b/mROA.Cbor/mROA.Cbor.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable true - 2.0.1 + 2.0.2 9 diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index a9f5246..e6783c6 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -83,7 +83,7 @@ namespace mROA.Implementation } private IInstanceRepository GetDefaultContextRepository() => - (_identifier.OwnerId == EndPointContext.HostId + (_identifier.OwnerId == EndPointContext.OwnerId ? EndPointContext.RealRepository : EndPointContext.RemoteRepository) ?? throw new NullReferenceException( From 8e37eda0aef8882b5b05f796f217b257248dac46 Mon Sep 17 00:00:00 2001 From: Mihail Mitrovanov Date: Thu, 15 May 2025 08:20:32 +0300 Subject: [PATCH 32/32] Client useful method in instance repository added --- Example.Frontend/Program.cs | 6 +- mROA.Codegen/mROA.Codegen.csproj | 2 +- mROA.Codegen/mROASourceGenerator.cs | 19 ++--- mROA/Abstract/IInstanceRepository.cs | 3 +- .../Backend/BasicExecutionModule.cs | 2 +- .../Backend/InstanceRepository.cs | 8 ++- .../Backend/MultiClientInstanceRepository.cs | 10 ++- .../ComplexInstanceRepository.cs | 70 ------------------- .../RemoteInstanceRepository.cs | 7 +- mROA/mROA.csproj | 2 +- 10 files changed, 40 insertions(+), 89 deletions(-) delete mode 100644 mROA/Implementation/ComplexInstanceRepository.cs diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 28957ce..5e1b7a7 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -46,8 +46,8 @@ class Program var context = builder.GetModule(); var factory = - context.GetSingleObject(typeof(IPrinterFactory), - builder.GetModule()) as IPrinterFactory; + context.GetSingletonObject( + builder.GetModule()); using (var disposingPrinter = factory.Create("Test")) { @@ -115,7 +115,7 @@ class Program DemoCheck.Dispose = true; - var loadSingleton = context.GetSingleObject(typeof(ILoadTest), builder.GetModule()) as ILoadTest; + var loadSingleton = context.GetSingletonObject(builder.GetModule()); var cts = new CancellationTokenSource(); diff --git a/mROA.Codegen/mROA.Codegen.csproj b/mROA.Codegen/mROA.Codegen.csproj index 765f637..0b91fce 100644 --- a/mROA.Codegen/mROA.Codegen.csproj +++ b/mROA.Codegen/mROA.Codegen.csproj @@ -17,7 +17,7 @@ https://github.com/YaslePoy/mROA git True - 2.0.1 + 2.0.3 diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index b2b9f26..8e3fafc 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -411,9 +411,11 @@ namespace mROA.Codegen var parametersDeclaration = string.Join(", ", JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i))); + + int pi = 0; var transferParameters = - JoinWithComa(parameters.Where(i => !ParameterFilterForType(i)) - .Select(i => "p" + parameters.IndexOf(i))); + JoinWithComa(parameters.Select(i => (i, pi++)).Where(i => !ParameterFilterForType(i.i)) + .Select(i => "p" + i.Item2)); var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); if (requestIndex != -1) @@ -440,15 +442,16 @@ namespace mROA.Codegen { var level = "\t\t\t"; - var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments; - var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList(); + int pi = 0; + var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments.Select(i => (i, pi++)).ToImmutableArray(); + var parsingParameters = parameters.RemoveAll(i => ParameterFilterForType(i.i)).ToList(); var parameterTypes = string.Join(", ", - $"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToUnityString()})"))}"); + $"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.i.ToUnityString()})"))}"); var parametersInsertList = new List(); foreach (var parameter in parameters) - switch (parameter.Name) + switch (parameter.i.Name) { case "CancellationToken": parametersInsertList.Add("(CancellationToken)special[1]"); @@ -457,8 +460,8 @@ namespace mROA.Codegen parametersInsertList.Add("special[0] as RequestContext"); break; default: - parametersInsertList.Add(Caster(parameter, - $"parameters[{parameters.IndexOf(parameter)}]")); + parametersInsertList.Add(Caster(parameter.i, + $"parameters[{parameter.Item2}]")); break; } diff --git a/mROA/Abstract/IInstanceRepository.cs b/mROA/Abstract/IInstanceRepository.cs index 7086178..53d949d 100644 --- a/mROA/Abstract/IInstanceRepository.cs +++ b/mROA/Abstract/IInstanceRepository.cs @@ -8,7 +8,8 @@ namespace mROA.Abstract int ResisterObject(object o, IEndPointContext context); void ClearObject(ComplexObjectIdentifier id, IEndPointContext context); T GetObject(ComplexObjectIdentifier id, IEndPointContext context); - object GetSingleObject(Type type, IEndPointContext context); + T GetSingletonObject(IEndPointContext context) where T : class, IShared; + object GetSingletonObject(Type type, IEndPointContext context); int GetObjectIndex(object o, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 69ceee4..0387bf1 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -91,7 +91,7 @@ namespace mROA.Implementation.Backend { var context = command.ObjectId.ContextId != -1 ? instanceRepository.GetObject(command.ObjectId, endPointContext) - : instanceRepository.GetSingleObject(invoker.SuitableType, endPointContext); + : instanceRepository.GetSingletonObject(invoker.SuitableType, endPointContext); return context; } diff --git a/mROA/Implementation/Backend/InstanceRepository.cs b/mROA/Implementation/Backend/InstanceRepository.cs index 4c7c9e5..dbece06 100644 --- a/mROA/Implementation/Backend/InstanceRepository.cs +++ b/mROA/Implementation/Backend/InstanceRepository.cs @@ -61,7 +61,13 @@ namespace mROA.Implementation.Backend return (T)value; } - public object GetSingleObject(Type type, IEndPointContext context) + public T GetSingletonObject(IEndPointContext context) where T : class, IShared + { + return GetSingletonObject(typeof(T), context) as T ?? + throw new ArgumentException("Unregistered singleton type"); + } + + public object GetSingletonObject(Type type, IEndPointContext context) { return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); diff --git a/mROA/Implementation/Backend/MultiClientInstanceRepository.cs b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs index 520e4cb..8cfc9d2 100644 --- a/mROA/Implementation/Backend/MultiClientInstanceRepository.cs +++ b/mROA/Implementation/Backend/MultiClientInstanceRepository.cs @@ -38,10 +38,16 @@ namespace mROA.Implementation.Backend return repository.GetObject(id, context); } - public object GetSingleObject(Type type, IEndPointContext context) + public T GetSingletonObject(IEndPointContext context) where T : class, IShared { var repository = GetRepositoryByClientId(context.OwnerId); - return repository.GetSingleObject(type, context); + return repository.GetSingletonObject(context); + } + + public object GetSingletonObject(Type type, IEndPointContext context) + { + var repository = GetRepositoryByClientId(context.OwnerId); + return repository.GetSingletonObject(type, context); } public int GetObjectIndex(object o, IEndPointContext context) diff --git a/mROA/Implementation/ComplexInstanceRepository.cs b/mROA/Implementation/ComplexInstanceRepository.cs deleted file mode 100644 index 09be507..0000000 --- a/mROA/Implementation/ComplexInstanceRepository.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using mROA.Abstract; - -namespace mROA.Implementation -{ - public class ComplexInstanceRepository : IInstanceRepository - { - private List>> _storages = new(); - public static object[] EventBinders = { }; - - private IRemoteObjectFactory? _remoteObjectFactory; - private IRepresentationModuleProducer? _representationModuleProducer; - - public void Inject(T dependency) - { - if (dependency is IRemoteObjectFactory remoteObjectFactory) - { - _remoteObjectFactory = remoteObjectFactory; - } - - if (dependency is IRepresentationModuleProducer moduleProducer) - { - _representationModuleProducer = moduleProducer; - } - } - - public int HostId { get; set; } - - public int ResisterObject(object o, IEndPointContext context) - { - var storageIndex = _storages.FindIndex(i => i.Key == context.OwnerId); - if (storageIndex == -1) - { - _storages.Add( - new KeyValuePair>(context.OwnerId, new ExtensibleStorage())); - storageIndex = _storages.Count - 1; - } - - var storage = _storages[storageIndex].Value; - - var placedIndex = storage.Place(o); - EventBinders.OfType>().FirstOrDefault() - ?.BindEvents((T)o, context, _representationModuleProducer!, placedIndex); - - return placedIndex; - } - - public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context) - { - _storages.Find(i => i.Key == id.OwnerId).Value.Free(id.ContextId); - } - - public T GetObject(ComplexObjectIdentifier id, IEndPointContext context) - { - throw new NotImplementedException(); - } - - public object GetSingleObject(Type type, IEndPointContext context) - { - throw new NotImplementedException(); - } - - public int GetObjectIndex(object o, IEndPointContext context) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/mROA/Implementation/RemoteInstanceRepository.cs b/mROA/Implementation/RemoteInstanceRepository.cs index 1d00f42..39ae9ef 100644 --- a/mROA/Implementation/RemoteInstanceRepository.cs +++ b/mROA/Implementation/RemoteInstanceRepository.cs @@ -42,7 +42,12 @@ namespace mROA.Implementation return remote; } - public object GetSingleObject(Type type, IEndPointContext context) + public T GetSingletonObject(IEndPointContext context) where T : class, IShared + { + return GetSingletonObject(typeof(T), context) as T; + } + + public object GetSingletonObject(Type type, IEndPointContext context) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 3c172de..6c53c78 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -4,7 +4,7 @@ netstandard2.1 enable mROA - 2.0.0 + 2.0.1 YaslePoy Fast and easy RPC with contex https://github.com/YaslePoy/mROA