Refactoring and prepare for interaction module reconnection
This commit is contained in:
@@ -40,6 +40,7 @@ namespace Example.Backend
|
|||||||
Console.WriteLine("Waiting canceled");
|
Console.WriteLine("Waiting canceled");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Waiting...");
|
Console.WriteLine("Waiting...");
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace Example.Backend
|
|||||||
public class Page : IPage
|
public class Page : IPage
|
||||||
{
|
{
|
||||||
public string Text;
|
public string Text;
|
||||||
|
|
||||||
public byte[] GetData()
|
public byte[] GetData()
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetBytes(Text);
|
return Encoding.UTF8.GetBytes(Text);
|
||||||
|
|||||||
@@ -39,14 +39,14 @@ class Program
|
|||||||
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
||||||
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
||||||
|
|
||||||
builder.GetModule<IFrontendBridge>()!.Connect();
|
var frontendBridge = builder.GetModule<IFrontendBridge>()!;
|
||||||
|
frontendBridge.Connect();
|
||||||
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
||||||
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
||||||
var context = builder.GetModule<RemoteContextRepository>();
|
var context = builder.GetModule<RemoteContextRepository>();
|
||||||
|
|
||||||
var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory;
|
var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory;
|
||||||
|
|
||||||
//правильный порядок команд 8-5-10-7
|
|
||||||
using (var disposingPrinter = factory.Create("Test"))
|
using (var disposingPrinter = factory.Create("Test"))
|
||||||
{
|
{
|
||||||
DemoCheck.CreatingPrinter = true;
|
DemoCheck.CreatingPrinter = true;
|
||||||
@@ -58,6 +58,7 @@ class Program
|
|||||||
Console.WriteLine("Printer created");
|
Console.WriteLine("Printer created");
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
|
|
||||||
|
// frontendBridge.Obstacle();
|
||||||
var name = disposingPrinter.GetName();
|
var name = disposingPrinter.GetName();
|
||||||
DemoCheck.BasicNonParamsCall = true;
|
DemoCheck.BasicNonParamsCall = true;
|
||||||
Console.WriteLine("Printer name : {0}", name);
|
Console.WriteLine("Printer name : {0}", name);
|
||||||
@@ -114,6 +115,9 @@ class Program
|
|||||||
cts.Cancel();
|
cts.Cancel();
|
||||||
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
|
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
|
||||||
DemoCheck.TaskCancelation = true;
|
DemoCheck.TaskCancelation = true;
|
||||||
|
|
||||||
|
frontendBridge.Disconnect();
|
||||||
|
|
||||||
DemoCheck.Show();
|
DemoCheck.Show();
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -3,5 +3,6 @@ namespace mROA.Abstract
|
|||||||
public interface IContextRepositoryHub
|
public interface IContextRepositoryHub
|
||||||
{
|
{
|
||||||
IContextRepository GetRepository(int clientId);
|
IContextRepository GetRepository(int clientId);
|
||||||
|
void FreeRepository(int clientId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace mROA.Abstract
|
|||||||
NetworkMessageHeader[] UnhandledMessages { get; }
|
NetworkMessageHeader[] UnhandledMessages { get; }
|
||||||
NetworkMessageHeader? FirstByFilter(Predicate<NetworkMessageHeader> predicate);
|
NetworkMessageHeader? FirstByFilter(Predicate<NetworkMessageHeader> predicate);
|
||||||
event Action<int> OnDisconected;
|
event Action<int> OnDisconected;
|
||||||
Task Restart();
|
Task Restart(bool sendRecovery);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,15 +10,11 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
public class ContextRepository : IContextRepository
|
public class ContextRepository : IContextRepository
|
||||||
{
|
{
|
||||||
private const int StartupSize = 1024;
|
|
||||||
private const int GrowSize = 128;
|
|
||||||
public static object[] EventBinders = { };
|
public static object[] EventBinders = { };
|
||||||
|
|
||||||
private static int LastDebugId = -1;
|
private static int LastDebugId = -1;
|
||||||
private int _debugId = -1;
|
private int _debugId = -1;
|
||||||
|
|
||||||
private Task<int> _lastIndexFinder = Task.FromResult(0);
|
|
||||||
|
|
||||||
private IRepresentationModuleProducer? _representationModuleProducer;
|
private IRepresentationModuleProducer? _representationModuleProducer;
|
||||||
|
|
||||||
// [CanBeNull]
|
// [CanBeNull]
|
||||||
|
|||||||
@@ -49,7 +49,13 @@ namespace mROA.Implementation.Backend
|
|||||||
private void HubOnOnConnected(IRepresentationModule interaction)
|
private void HubOnOnConnected(IRepresentationModule interaction)
|
||||||
{
|
{
|
||||||
var extractor = CreateExtractor(interaction);
|
var extractor = CreateExtractor(interaction);
|
||||||
_ = extractor.StartExtraction();
|
extractor.StartExtraction().ContinueWith(t => OnDisconnected(interaction));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisconnected(IRepresentationModule representationModule)
|
||||||
|
{
|
||||||
|
if (_contextRepository is IContextRepositoryHub contextHub)
|
||||||
|
contextHub.FreeRepository(representationModule.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ namespace mROA.Implementation.Backend
|
|||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FreeRepository(int clientId)
|
||||||
|
{
|
||||||
|
_repositories.Remove(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
private IContextRepository GetRepositoryByClientId(int clientId)
|
private IContextRepository GetRepositoryByClientId(int clientId)
|
||||||
{
|
{
|
||||||
if (_repositories.TryGetValue(clientId, out var repository))
|
if (_repositories.TryGetValue(clientId, out var repository))
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ namespace mROA.Implementation.Backend
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var client = _tcpListener.AcceptTcpClient();
|
var client = _tcpListener.AcceptTcpClient();
|
||||||
|
|
||||||
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
||||||
var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule;
|
var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule;
|
||||||
foreach (var injectableModule in _injectableModules!)
|
foreach (var injectableModule in _injectableModules!)
|
||||||
@@ -77,19 +78,26 @@ namespace mROA.Implementation.Backend
|
|||||||
|
|
||||||
var connectionRequest = interaction.GetNextMessageReceiving().GetAwaiter().GetResult()!;
|
var connectionRequest = interaction.GetNextMessageReceiving().GetAwaiter().GetResult()!;
|
||||||
|
|
||||||
if (connectionRequest.MessageType == EMessageType.ClientConnect)
|
switch (connectionRequest.MessageType)
|
||||||
{
|
{
|
||||||
|
case EMessageType.ClientConnect:
|
||||||
interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!,
|
interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!,
|
||||||
new IdAssignment { Id = -interaction.ConnectionId }));
|
new IdAssignment { Id = -interaction.ConnectionId }));
|
||||||
_hub!.RegisterInteraction(interaction);
|
_hub!.RegisterInteraction(interaction);
|
||||||
Console.WriteLine("Client registered");
|
Console.WriteLine("Client registered");
|
||||||
}else if (connectionRequest.MessageType == EMessageType.ClientRecovery)
|
break;
|
||||||
|
case EMessageType.ClientRecovery:
|
||||||
{
|
{
|
||||||
var recoveryRequest = _serialization!.Deserialize<ClientRecovery>(connectionRequest.Data)!;
|
var recoveryRequest = _serialization!.Deserialize<ClientRecovery>(connectionRequest.Data)!;
|
||||||
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
||||||
recoveryInteraction.BaseStream = client.GetStream();
|
recoveryInteraction.BaseStream = client.GetStream();
|
||||||
recoveryInteraction.Restart();
|
recoveryInteraction.Restart(false);
|
||||||
Console.WriteLine($"Client {recoveryRequest.Id} reconnected");
|
Console.WriteLine($"Client {recoveryRequest.Id} reconnected");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
client.Close();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ namespace mROA.Implementation.Frontend
|
|||||||
|
|
||||||
_interactionModule.BaseStream = _tcpClient.GetStream();
|
_interactionModule.BaseStream = _tcpClient.GetStream();
|
||||||
|
|
||||||
_interactionModule.OnDisconected += async id =>
|
_interactionModule.OnDisconected += id =>
|
||||||
{
|
{
|
||||||
await Reconnect();
|
Reconnect();
|
||||||
};
|
};
|
||||||
_ = _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect()));
|
_ = _interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect()));
|
||||||
var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
|
var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
|
||||||
@@ -66,7 +66,7 @@ namespace mROA.Implementation.Frontend
|
|||||||
_tcpClient = new TcpClient();
|
_tcpClient = new TcpClient();
|
||||||
_tcpClient.Connect(_serverEndPoint);
|
_tcpClient.Connect(_serverEndPoint);
|
||||||
_interactionModule.BaseStream = _tcpClient.GetStream();
|
_interactionModule.BaseStream = _tcpClient.GetStream();
|
||||||
await _interactionModule.Restart();
|
await _interactionModule.Restart(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Obstacle()
|
public void Obstacle()
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
public class ClientRecovery : INetworkMessage
|
public class ClientRecovery : INetworkMessage
|
||||||
{
|
{
|
||||||
|
public ClientRecovery()
|
||||||
|
{
|
||||||
|
Id = 0;
|
||||||
|
}
|
||||||
public ClientRecovery(int id)
|
public ClientRecovery(int id)
|
||||||
{
|
{
|
||||||
Id = id;
|
Id = id;
|
||||||
|
|||||||
@@ -10,14 +10,23 @@ namespace mROA.Implementation
|
|||||||
{
|
{
|
||||||
public class NextGenerationInteractionModule : INextGenerationInteractionModule
|
public class NextGenerationInteractionModule : INextGenerationInteractionModule
|
||||||
{
|
{
|
||||||
|
private int DebugId = new Random().Next();
|
||||||
private const int BufferSize = ushort.MaxValue;
|
private const int BufferSize = ushort.MaxValue;
|
||||||
private readonly Memory<byte> _buffer = new byte[BufferSize];
|
private readonly Memory<byte> _buffer = new byte[BufferSize];
|
||||||
private readonly List<NetworkMessageHeader> _messageBuffer = new(128);
|
private readonly List<NetworkMessageHeader> _messageBuffer = new(128);
|
||||||
private Task<NetworkMessageHeader>? _currentReceiving;
|
private Task<NetworkMessageHeader>? _currentReceiving;
|
||||||
private ISerializationToolkit? _serialization;
|
private ISerializationToolkit? _serialization;
|
||||||
private Stream? _baseStream;
|
private Stream? _baseStream;
|
||||||
|
private bool _isRecovering;
|
||||||
|
private event Action OnReconnected;
|
||||||
|
|
||||||
private TaskCompletionSource<Stream> _reconection = new();
|
private TaskCompletionSource<Stream> _reconection;
|
||||||
|
|
||||||
|
public NextGenerationInteractionModule()
|
||||||
|
{
|
||||||
|
_reconection = new TaskCompletionSource<Stream>();
|
||||||
|
_reconection.SetResult(Stream.Null);
|
||||||
|
}
|
||||||
|
|
||||||
public int ConnectionId { get; set; }
|
public int ConnectionId { get; set; }
|
||||||
|
|
||||||
@@ -54,6 +63,25 @@ namespace mROA.Implementation
|
|||||||
_currentReceiving = Task.Run(async () => await GetNextMessage());
|
_currentReceiving = Task.Run(async () => await GetNextMessage());
|
||||||
return _currentReceiving;
|
return _currentReceiving;
|
||||||
}
|
}
|
||||||
|
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||||
|
private async ValueTask<bool> 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)
|
||||||
|
return false;
|
||||||
|
await BaseStream.WriteAsync(header);
|
||||||
|
await BaseStream.WriteAsync(rawMessage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||||
|
|
||||||
|
|
||||||
public async Task PostMessageAsync(NetworkMessageHeader messageHeader)
|
public async Task PostMessageAsync(NetworkMessageHeader messageHeader)
|
||||||
{
|
{
|
||||||
@@ -65,12 +93,35 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
// Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message));
|
// Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message));
|
||||||
|
|
||||||
|
bool withError = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (withError)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Post again");
|
||||||
|
}
|
||||||
|
|
||||||
var rawMessage = _serialization.Serialize(messageHeader);
|
if (await PostMessageInternal(messageHeader))
|
||||||
var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort));
|
break;
|
||||||
|
|
||||||
await BaseStream.WriteAsync(header);
|
// Console.WriteLine("Try to get lock from post");
|
||||||
await BaseStream.WriteAsync(rawMessage);
|
// lock (_reconection)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine("Got lock from post");
|
||||||
|
// if (!_isRecovering)
|
||||||
|
// {
|
||||||
|
// _isRecovering = true;
|
||||||
|
// Console.WriteLine("Disconnect invoke for post");
|
||||||
|
// OnDisconected?.Invoke(ConnectionId);
|
||||||
|
// Console.WriteLine("Disconnect invoked for post");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// withError = true;
|
||||||
|
// Console.WriteLine("Start waiting for recovery from post");
|
||||||
|
// _ = await _reconection.Task;
|
||||||
|
// Console.WriteLine("Connection recovered from post");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleMessage(NetworkMessageHeader messageHeader)
|
public void HandleMessage(NetworkMessageHeader messageHeader)
|
||||||
@@ -95,16 +146,40 @@ namespace mROA.Implementation
|
|||||||
if (_serialization == null)
|
if (_serialization == null)
|
||||||
throw new NullReferenceException("Serialization toolkit is null");
|
throw new NullReferenceException("Serialization toolkit is null");
|
||||||
|
|
||||||
|
bool withError = false;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
if (withError)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Recieve again");
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return await Receive();
|
return await Receive();
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
OnDisconected!.Invoke(ConnectionId);
|
// Console.WriteLine("Try to get lock from receive");
|
||||||
_ = await _reconection.Task;
|
// lock (_reconection)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine("Got lock from receive");
|
||||||
|
//
|
||||||
|
// if (!_isRecovering)
|
||||||
|
// {
|
||||||
|
// _isRecovering = true;
|
||||||
|
// Console.WriteLine("Disconnect invoke");
|
||||||
|
// OnDisconected?.Invoke(ConnectionId);
|
||||||
|
// Console.WriteLine("Disconnect invoked for receive");
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// withError = true;
|
||||||
|
// Console.WriteLine("Start waiting for recovery from receive");
|
||||||
|
// _ = await _reconection.Task;
|
||||||
|
// Console.WriteLine("Connection recovered");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -119,7 +194,7 @@ namespace mROA.Implementation
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<NetworkMessageHeader> Receive()
|
private async ValueTask<NetworkMessageHeader> Receive()
|
||||||
{
|
{
|
||||||
var len = ReadMessageLength();
|
var len = ReadMessageLength();
|
||||||
var localSpan = _buffer[..len];
|
var localSpan = _buffer[..len];
|
||||||
@@ -128,9 +203,9 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
var message = _serialization.Deserialize<NetworkMessageHeader>(localSpan.Span);
|
var message = _serialization.Deserialize<NetworkMessageHeader>(localSpan.Span);
|
||||||
#if TRACE
|
#if TRACE
|
||||||
Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.SchemaId}");
|
Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.MessageType}");
|
||||||
TransmissionConfig.TotalTransmittedBytes += len;
|
TransmissionConfig.TotalTransmittedBytes += len;
|
||||||
Console.WriteLine($"Total recieced bytes are {TransmissionConfig.TotalTransmittedBytes}");
|
Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}");
|
||||||
#endif
|
#endif
|
||||||
_messageBuffer.Add(message);
|
_messageBuffer.Add(message);
|
||||||
_currentReceiving = Task.Run(async () => await GetNextMessage());
|
_currentReceiving = Task.Run(async () => await GetNextMessage());
|
||||||
@@ -138,10 +213,15 @@ namespace mROA.Implementation
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Restart()
|
public async Task Restart(bool sendRecovery)
|
||||||
{
|
{
|
||||||
await PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId))));
|
if (sendRecovery)
|
||||||
|
await PostMessageAsync(
|
||||||
|
new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId))));
|
||||||
|
_isRecovering = false;
|
||||||
_reconection.SetResult(BaseStream!);
|
_reconection.SetResult(BaseStream!);
|
||||||
|
_reconection = new TaskCompletionSource<Stream>();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -21,7 +21,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<DefineConstants></DefineConstants>
|
<DefineConstants>TRACE;</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
Reference in New Issue
Block a user