Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd971cdecc | ||
|
|
304811c964 | ||
|
|
2cbcc6b201 | ||
|
|
0818ed6a5a | ||
|
|
3aa723c2ca | ||
|
|
dea464d251 | ||
|
|
4dca13b85b | ||
|
|
9425f25081 | ||
|
|
965c8eb823 | ||
|
|
6c55567d3f | ||
|
|
bb3c4887df | ||
|
|
be12f1da65 | ||
|
|
31d4102dac | ||
|
|
14ec6abd8d | ||
|
|
f8998178ff | ||
|
|
5cbfb4d2b1 | ||
|
|
83391bd55e | ||
|
|
e4d6709a77 | ||
|
|
c7c5b1637c | ||
|
|
79d0e4b5b1 | ||
|
|
0c648f0af0 | ||
|
|
85cf1bc48a | ||
|
|
153272a1fa | ||
|
|
17a6d3aad6 |
+10
-13
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Example.Backend;
|
||||
using Example.Shared;
|
||||
@@ -10,24 +9,26 @@ using mROA.Implementation;
|
||||
using mROA.Implementation.Backend;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var builder = Host.CreateApplicationBuilder();
|
||||
builder.Services.AddLogging(l => l.AddConsole());
|
||||
builder.Services.AddSingleton<IContextualSerializationToolKit, CborSerializationToolkit>();
|
||||
builder.Services.AddSingleton<IIdentityGenerator, BackendIdentityGenerator>();
|
||||
builder.Services.AddSingleton<IGatewayModule, NetworkGatewayModule>();
|
||||
builder.Services.AddSingleton<IUntrustedGateway, UdpGateway>();
|
||||
builder.Services.AddSingleton<IConnectionHub, ConnectionHub>();
|
||||
|
||||
builder.Services.AddOptions();
|
||||
var listening = new IPEndPoint(IPAddress.Any, 4567);
|
||||
|
||||
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = listening);
|
||||
|
||||
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.ExtractorFirst);
|
||||
|
||||
builder.Services.AddSingleton<HubRequestExtractor>();
|
||||
|
||||
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
|
||||
builder.Services.AddSingleton<IRepresentationModuleProducer, CreativeRepresentationModuleProducer>();
|
||||
builder.Services.AddSingleton<IInstanceRepository, RemoteInstanceRepository>();
|
||||
@@ -51,17 +52,13 @@ class Program
|
||||
builder.Services.AddSingleton<ICancellationRepository, CancellationRepository>();
|
||||
|
||||
var host = builder.Build();
|
||||
host.Services.GetService<HubRequestExtractor>();
|
||||
//
|
||||
// builder.Build();
|
||||
new RemoteTypeBinder();
|
||||
new RemoteTypeBinder();
|
||||
//
|
||||
//
|
||||
_ = host.Services.GetService<IUntrustedGateway>()!.Start();
|
||||
var gateway = host.Services.GetService<IGatewayModule>();
|
||||
gateway.Run();
|
||||
|
||||
Console.ReadLine();
|
||||
_ = host.Services.GetService<IUntrustedGateway>()!.Start();
|
||||
var gateway = host.Services.GetService<IGatewayModule>();
|
||||
gateway.Run();
|
||||
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using Example.Frontend;
|
||||
using Example.Shared;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using mROA.Abstract;
|
||||
using mROA.Cbor;
|
||||
using mROA.Codegen;
|
||||
@@ -23,6 +24,8 @@ class Program
|
||||
new RemoteTypeBinder();
|
||||
|
||||
var builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings { DisableDefaults = true });
|
||||
builder.Services.AddLogging(l => l.SetMinimumLevel(LogLevel.Trace).AddConsole());
|
||||
|
||||
builder.Services.AddSingleton<IContextualSerializationToolKit, CborSerializationToolkit>();
|
||||
builder.Services.AddSingleton<IEndPointContext, EndPointContext>();
|
||||
builder.Services.AddSingleton<IRealStoreInstanceRepository, InstanceRepository>(provider =>
|
||||
@@ -39,8 +42,11 @@ class Program
|
||||
builder.Services.AddSingleton<IRepresentationModule, RepresentationModule>();
|
||||
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 4567);
|
||||
builder.Services.AddSingleton<IFrontendBridge, NetworkFrontendBridge>();
|
||||
|
||||
builder.Services.AddOptions();
|
||||
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint);
|
||||
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.Channeled);
|
||||
|
||||
builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>();
|
||||
builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>();
|
||||
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
|
||||
|
||||
+53
-48
@@ -1,6 +1,5 @@
|
||||
using System.Net;
|
||||
using Example.Shared;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using mROA.Abstract;
|
||||
@@ -32,69 +31,76 @@ Console.WriteLine("End waiting");
|
||||
var totalRequests = tasks.Sum(i => i.Result);
|
||||
Console.WriteLine($"Total requests: {totalRequests:N0}");
|
||||
Console.WriteLine($"Results: {totalRequests / time.TotalSeconds:N} RPS");
|
||||
|
||||
File.AppendAllText("results.txt", $"[FAST ID] {totalRequests}\r\n");
|
||||
|
||||
async Task<List<ILoadTest>> GetLoadEndpoints(int count)
|
||||
{
|
||||
var loads = new List<ILoadTest>();
|
||||
for (int i = 0; i < count; i++)
|
||||
try
|
||||
{
|
||||
var builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings { DisableDefaults = true });
|
||||
builder.Services.AddSingleton<IContextualSerializationToolKit, CborSerializationToolkit>();
|
||||
builder.Services.AddSingleton<IEndPointContext, EndPointContext>();
|
||||
builder.Services.AddSingleton<IRealStoreInstanceRepository, InstanceRepository>(provider =>
|
||||
var loads = new List<ILoadTest>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var repo = new InstanceRepository(provider.GetService<IRepresentationModuleProducer>());
|
||||
repo.FillSingletons(typeof(Program).Assembly);
|
||||
return repo;
|
||||
});
|
||||
var builder = Host.CreateApplicationBuilder(new HostApplicationBuilderSettings { DisableDefaults = true });
|
||||
builder.Services.AddSingleton<IContextualSerializationToolKit, CborSerializationToolkit>();
|
||||
builder.Services.AddSingleton<IEndPointContext, EndPointContext>();
|
||||
builder.Services.AddSingleton<IRealStoreInstanceRepository, InstanceRepository>(provider =>
|
||||
{
|
||||
var repo = new InstanceRepository(provider.GetService<IRepresentationModuleProducer>());
|
||||
repo.FillSingletons(typeof(Program).Assembly);
|
||||
return repo;
|
||||
});
|
||||
|
||||
builder.Services.AddSingleton<IInstanceRepository, RemoteInstanceRepository>();
|
||||
builder.Services.AddSingleton<IChannelInteractionModule, ChannelInteractionModule>();
|
||||
// builder.Services.AddSingleton<IUntrustedInteractionModule, UdpUntrustedInteraction>();
|
||||
builder.Services.AddSingleton<IRepresentationModule, RepresentationModule>();
|
||||
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 4567);
|
||||
builder.Services.AddSingleton<IFrontendBridge, NetworkFrontendBridge>();
|
||||
builder.Services.AddOptions();
|
||||
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint);
|
||||
builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>();
|
||||
// builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>();
|
||||
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
|
||||
builder.Services.AddSingleton<IInstanceRepository, RemoteInstanceRepository>();
|
||||
builder.Services.AddSingleton<IChannelInteractionModule, ChannelInteractionModule>();
|
||||
// builder.Services.AddSingleton<IUntrustedInteractionModule, UdpUntrustedInteraction>();
|
||||
builder.Services.AddSingleton<IRepresentationModule, RepresentationModule>();
|
||||
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 4567);
|
||||
builder.Services.AddSingleton<IFrontendBridge, NetworkFrontendBridge>();
|
||||
builder.Services.AddOptions();
|
||||
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint);
|
||||
builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>();
|
||||
// builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>();
|
||||
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
|
||||
|
||||
builder.Services.AddSingleton<IMethodRepository, CollectableMethodRepository>(p =>
|
||||
{
|
||||
var methodRepo = new CollectableMethodRepository();
|
||||
methodRepo.AppendInvokers(new GeneratedInvokersCollection());
|
||||
return methodRepo;
|
||||
});
|
||||
builder.Services.AddSingleton<ICallIndexProvider, GeneratedCallIndexProvider>();
|
||||
builder.Services.AddSingleton<ICancellationRepository, CancellationRepository>();
|
||||
builder.Services.AddSingleton<IMethodRepository, CollectableMethodRepository>(p =>
|
||||
{
|
||||
var methodRepo = new CollectableMethodRepository();
|
||||
methodRepo.AppendInvokers(new GeneratedInvokersCollection());
|
||||
return methodRepo;
|
||||
});
|
||||
builder.Services.AddSingleton<ICallIndexProvider, GeneratedCallIndexProvider>();
|
||||
builder.Services.AddSingleton<ICancellationRepository, CancellationRepository>();
|
||||
|
||||
var app = builder.Build();
|
||||
var app = builder.Build();
|
||||
|
||||
var frontendBridge = app.Services.GetService<IFrontendBridge>()!;
|
||||
await frontendBridge.Connect();
|
||||
// _ = app.Services.GetService<IRequestExtractor>()!.StartExtraction();
|
||||
// _ = app.Services.GetService<IUntrustedInteractionModule>().Start(serverEndPoint);
|
||||
var context = app.Services.GetService<IInstanceRepository>();
|
||||
var frontendBridge = app.Services.GetService<IFrontendBridge>()!;
|
||||
await frontendBridge.Connect();
|
||||
// _ = app.Services.GetService<IRequestExtractor>()!.StartExtraction();
|
||||
// _ = app.Services.GetService<IUntrustedInteractionModule>().Start(serverEndPoint);
|
||||
var context = app.Services.GetService<IInstanceRepository>();
|
||||
|
||||
var singletonObject =
|
||||
context.GetSingletonObject<ILoadTest>(
|
||||
app.Services.GetService<IEndPointContext>());
|
||||
loads.Add(singletonObject);
|
||||
}
|
||||
|
||||
var singletonObject =
|
||||
context.GetSingletonObject<ILoadTest>(
|
||||
app.Services.GetService<IEndPointContext>());
|
||||
loads.Add(singletonObject);
|
||||
return loads;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
return loads;
|
||||
}
|
||||
|
||||
async Task<int> Requests(CancellationToken token, int id, ILoadTest load)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
int count = 0;
|
||||
while (true){
|
||||
while (true)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
@@ -102,9 +108,8 @@ async Task<int> Requests(CancellationToken token, int id, ILoadTest load)
|
||||
|
||||
await load.Next(2);
|
||||
count++;
|
||||
}
|
||||
|
||||
Console.WriteLine(id);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation;
|
||||
using mROA.Implementation.Attributes;
|
||||
|
||||
namespace Example.Shared
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation;
|
||||
using mROA.Implementation.Attributes;
|
||||
|
||||
namespace Example.Shared
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation;
|
||||
using mROA.Implementation.Attributes;
|
||||
|
||||
namespace Example.Shared
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Formats.Cbor;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using mROA.Implementation;
|
||||
|
||||
public static class CborExtensions
|
||||
{
|
||||
public static unsafe void WriteToCbor(this RequestId id, CborWriter writer)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
MemoryMarshal.Write(span, ref id);
|
||||
writer.WriteByteString(span);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteToCborInline(this RequestId id, CborWriter writer)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
MemoryMarshal.Write(span, ref id);
|
||||
writer.WriteByteString(span);
|
||||
}
|
||||
|
||||
public static void WriteToDest(this RequestId id, Span<byte> destination)
|
||||
{
|
||||
MemoryMarshal.Write(destination, ref id);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe void WriteToCborOpt(this RequestId id, CborWriter writer)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
MemoryMarshal.Write(span, ref id);
|
||||
writer.WriteByteString(span);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.Formats.Cbor;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
|
||||
namespace mROA.Benchmark;
|
||||
|
||||
|
||||
[MemoryDiagnoser]
|
||||
public class CborTest
|
||||
{
|
||||
private CborWriter _writer;
|
||||
private CborReader _reader;
|
||||
|
||||
private Memory<byte> FlatEncoded;
|
||||
private Memory<byte> ArrayEncoded;
|
||||
public CborTest()
|
||||
{
|
||||
_writer = new CborWriter(initialCapacity:512);
|
||||
|
||||
_writer.WriteStartArray(2);
|
||||
_writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
_writer.WriteStartArray(2);
|
||||
_writer.WriteInt32(12);
|
||||
_writer.WriteTextString("tralala");
|
||||
_writer.WriteEndArray();
|
||||
_writer.WriteEndArray();
|
||||
|
||||
ArrayEncoded = _writer.Encode();
|
||||
|
||||
_writer.Reset();
|
||||
|
||||
_writer.WriteStartArray(3);
|
||||
_writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
_writer.WriteInt32(12);
|
||||
_writer.WriteTextString("tralala");
|
||||
_writer.WriteEndArray();
|
||||
FlatEncoded = _writer.Encode();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int FlatWrite()
|
||||
{
|
||||
_writer.Reset();
|
||||
_writer.WriteStartArray(3);
|
||||
_writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
_writer.WriteInt32(12);
|
||||
_writer.WriteTextString("tralala");
|
||||
_writer.WriteEndArray();
|
||||
var len = _writer.Encode(FlatEncoded.Span);
|
||||
return len;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int ArrayWrite()
|
||||
{
|
||||
_writer.Reset();
|
||||
_writer.WriteStartArray(2);
|
||||
_writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
_writer.WriteStartArray(2);
|
||||
_writer.WriteInt32(12);
|
||||
_writer.WriteTextString("tralala");
|
||||
_writer.WriteEndArray();
|
||||
_writer.WriteEndArray();
|
||||
var len = _writer.Encode(ArrayEncoded.Span);
|
||||
return len;
|
||||
}
|
||||
[Benchmark]
|
||||
public int FlatRead()
|
||||
{
|
||||
var reader = new CborReader(FlatEncoded);
|
||||
reader.ReadStartArray();
|
||||
var arr = reader.ReadByteString();
|
||||
var i = reader.ReadInt32();
|
||||
var text = reader.ReadTextString();
|
||||
reader.ReadEndArray();
|
||||
|
||||
return arr.Length;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int ArrayRead()
|
||||
{
|
||||
var reader = new CborReader(ArrayEncoded);
|
||||
reader.ReadStartArray();
|
||||
var arr = reader.ReadByteString();
|
||||
reader.ReadStartArray();
|
||||
var i = reader.ReadInt32();
|
||||
var text = reader.ReadTextString();
|
||||
reader.ReadEndArray();
|
||||
reader.ReadEndArray();
|
||||
|
||||
return arr.Length;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Benchmark;
|
||||
|
||||
public class IdGeneration
|
||||
{
|
||||
public static int X = 0;
|
||||
|
||||
[Benchmark]
|
||||
public Guid GuidGeneration()
|
||||
{
|
||||
return Guid.NewGuid();
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public RequestId ReqIdGeneration()
|
||||
{
|
||||
return RequestId.Generate();
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public RequestId ReqIdIfGeneration()
|
||||
{
|
||||
var reqId = RequestId.Generate();
|
||||
if (++X % 2 == 0)
|
||||
{
|
||||
reqId.P0 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
reqId.P1 = 0;
|
||||
}
|
||||
return reqId;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,51 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
|
||||
namespace mROA.Benchmark
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
// Console.WriteLine("Hello, World!");
|
||||
// var summary = BenchmarkRunner.Run<CollectionsSpeed>();
|
||||
}
|
||||
}
|
||||
using BenchmarkDotNet.Running;
|
||||
using mROA.Benchmark;
|
||||
|
||||
public class CollectionsSpeed
|
||||
{
|
||||
private const int N = 1000;
|
||||
|
||||
private readonly List<int> _immutable;
|
||||
private readonly int[] _array;
|
||||
Console.WriteLine("Hello, World!");
|
||||
|
||||
public CollectionsSpeed()
|
||||
{
|
||||
_array = Enumerable.Range(0, N).ToArray();
|
||||
// _immutable = [.._array];
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int DefaultArray()
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
sum += _array[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int ImmutableArray()
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
sum += _immutable[i];
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
BenchmarkRunner.Run<IdGeneration>();
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Formats.Cbor;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using mROA.Implementation;
|
||||
|
||||
[MemoryDiagnoser]
|
||||
public class RequestWriter
|
||||
{
|
||||
private const int N = 1000;
|
||||
public RequestId Id = RequestId.Generate();
|
||||
private CborWriter _writer;
|
||||
|
||||
public RequestWriter()
|
||||
{
|
||||
_writer = new CborWriter(initialCapacity: 512);
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public int DefaultCbor()
|
||||
{
|
||||
_writer.Reset();
|
||||
_writer.WriteByteString(Id.ToByteArray());
|
||||
return _writer.BytesWritten;
|
||||
}
|
||||
[Benchmark]
|
||||
public int DirectCbor()
|
||||
{
|
||||
_writer.Reset();
|
||||
Id.WriteToCbor(_writer);
|
||||
return _writer.BytesWritten;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int Stackalloc()
|
||||
{
|
||||
_writer.Reset();
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
Id.WriteToDest(span);
|
||||
_writer.WriteByteString(span);
|
||||
return _writer.BytesWritten;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int DirectCborInline()
|
||||
{
|
||||
_writer.Reset();
|
||||
Id.WriteToCborInline(_writer);
|
||||
return _writer.BytesWritten;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public int DirectCborOpt()
|
||||
{
|
||||
_writer.Reset();
|
||||
Id.WriteToCborOpt(_writer);
|
||||
return _writer.BytesWritten;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Benchmark;
|
||||
|
||||
public class VirtualOverhead
|
||||
{
|
||||
private CallRequest _directRequest;
|
||||
private RawCallRequest _rawRequest;
|
||||
|
||||
[GlobalSetup]
|
||||
public void Setup() {
|
||||
_directRequest = new CallRequest
|
||||
{
|
||||
CommandId = 5, Id = new RequestId(), ObjectId = ComplexObjectIdentifier.Null, Parameters = null
|
||||
};
|
||||
_rawRequest = new RawCallRequest
|
||||
{
|
||||
CommandId = _directRequest.CommandId, Id = _directRequest.Id, ObjectId = _directRequest.ObjectId,
|
||||
Parameters = null
|
||||
};
|
||||
}
|
||||
|
||||
[Benchmark(Baseline = true)]
|
||||
public long DirectUsage()
|
||||
{
|
||||
var req = _directRequest;
|
||||
long acc = 0;
|
||||
acc += req.CommandId;
|
||||
acc += (long)(req.Id.P1 + req.Id.P0);
|
||||
acc += req.ObjectId.ContextId + req.ObjectId.OwnerId;
|
||||
acc += (req.Parameters ?? []).Length;
|
||||
return acc;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public long RawUsage()
|
||||
{
|
||||
var req = _rawRequest;
|
||||
long acc = 0;
|
||||
acc += req.CommandId;
|
||||
acc += (long)(req.Id.P1 + req.Id.P0);
|
||||
acc += req.ObjectId.ContextId + req.ObjectId.OwnerId;
|
||||
acc += (req.Parameters ?? []).Length;
|
||||
return acc;
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public long ParamUsage()
|
||||
{
|
||||
return Call(_directRequest);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public long ParamInUsage()
|
||||
{
|
||||
return CallIn(in _directRequest);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public long Call(CallRequest req)
|
||||
{
|
||||
long acc = 0;
|
||||
acc += req.CommandId;
|
||||
acc += (long)(req.Id.P1 + req.Id.P0);
|
||||
acc += req.ObjectId.ContextId + req.ObjectId.OwnerId;
|
||||
acc += (req.Parameters ?? []).Length;
|
||||
return acc;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public long CallIn(in CallRequest req)
|
||||
{
|
||||
long acc = 0;
|
||||
acc += req.CommandId;
|
||||
acc += (long)(req.Id.P1 + req.Id.P0);
|
||||
acc += req.ObjectId.ContextId + req.ObjectId.OwnerId;
|
||||
acc += (req.Parameters ?? []).Length;
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
|
||||
public struct RawCallRequest
|
||||
{
|
||||
public RequestId Id;
|
||||
public int CommandId;
|
||||
public ComplexObjectIdentifier ObjectId;
|
||||
|
||||
public object?[]? Parameters;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||
}
|
||||
}
|
||||
@@ -2,13 +2,24 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.14.0" />
|
||||
<ProjectReference Include="..\mROA\mROA.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Formats.Cbor">
|
||||
<HintPath>..\..\..\..\.nuget\packages\system.formats.cbor\9.0.7\lib\net9.0\System.Formats.Cbor.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Formats.Cbor;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Cbor
|
||||
{
|
||||
public static class CborExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteToCborInline(this RequestId id, CborWriter writer)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[16];
|
||||
MemoryMarshal.Write(span, ref id);
|
||||
writer.WriteByteString(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,59 +14,62 @@ namespace mROA.Cbor
|
||||
{
|
||||
public class CborSerializationToolkit : IContextualSerializationToolKit
|
||||
{
|
||||
private readonly IOrdinaryStructureParser[] _parsers = {
|
||||
new NetworkMessageHeaderParser(), new DefaultCallRequestParser(), new FinalCommandExecutionParser(),
|
||||
private readonly CborWriter _writer = new(initialCapacity: 2048);
|
||||
|
||||
private readonly IOrdinaryStructureParser[] _parsers =
|
||||
{
|
||||
new CallRequestParser(), new FinalCommandExecutionParser(),
|
||||
new FinalCommandExecutionResultlessParser()
|
||||
};
|
||||
// private Dictionary<Type, IOrdinaryStructureParser> _parsers = new(){{typeof(NetworkMessageHeader), new NetworkMessageHeaderParser()}, {typeof(DefaultCallRequest), new DefaultCallRequestParser()}, {typeof(FinalCommandExecution<object>), new FinalCommandExecutionParser()}, {typeof(FinalCommandExecution), new FinalCommandExecutionResultlessParser()}}; //
|
||||
private Dictionary<Type, List<PropertyInfo>> _propertiesCache = new();
|
||||
|
||||
private readonly Dictionary<Type, List<PropertyInfo>> _propertiesCache = new();
|
||||
public static TimeSpan SerializationTime = TimeSpan.Zero;
|
||||
|
||||
private bool FindParser(Type t, out IOrdinaryStructureParser parser)
|
||||
{
|
||||
if (t == typeof(NetworkMessageHeader))
|
||||
if (t == typeof(CallRequest))
|
||||
{
|
||||
parser = _parsers[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t == typeof(DefaultCallRequest))
|
||||
if (t == typeof(FinalCommandExecution<object>))
|
||||
{
|
||||
parser = _parsers[1];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t == typeof(FinalCommandExecution<object>))
|
||||
{
|
||||
parser = _parsers[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t == typeof(FinalCommandExecution))
|
||||
{
|
||||
parser = _parsers[3];
|
||||
parser = _parsers[2];
|
||||
return true;
|
||||
}
|
||||
|
||||
parser = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public byte[] Serialize(object objectToSerialize, IEndPointContext context)
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
var writer = new CborWriter(initialCapacity:64);
|
||||
WriteData(objectToSerialize, writer, context);
|
||||
var result = writer.Encode();
|
||||
sw.Stop();
|
||||
SerializationTime = SerializationTime.Add(sw.Elapsed);
|
||||
byte[] result;
|
||||
lock (_writer)
|
||||
{
|
||||
_writer.Reset();
|
||||
WriteData(objectToSerialize, _writer, context);
|
||||
result = _writer.Encode();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public int Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext context)
|
||||
{
|
||||
var writer = new CborWriter(initialCapacity:64);
|
||||
WriteData(objectToSerialize, writer, context);
|
||||
return writer.Encode(destination);
|
||||
lock (_writer)
|
||||
{
|
||||
_writer.Reset();
|
||||
WriteData(objectToSerialize, _writer, context);
|
||||
return _writer.Encode(destination);
|
||||
}
|
||||
}
|
||||
|
||||
public T Deserialize<T>(byte[] rawData, IEndPointContext? context)
|
||||
@@ -107,56 +110,17 @@ namespace mROA.Cbor
|
||||
return preParsed.ToObject(type, context);
|
||||
|
||||
|
||||
if (type == typeof(Guid))
|
||||
if (type == typeof(RequestId))
|
||||
{
|
||||
return new Guid((byte[])nonCasted);
|
||||
return new RequestId((byte[])nonCasted);
|
||||
}
|
||||
|
||||
return Convert.ChangeType(nonCasted, type);
|
||||
}
|
||||
|
||||
public void Inject(object dependency)
|
||||
public IContextualSerializationToolKit Clone()
|
||||
{
|
||||
}
|
||||
|
||||
public byte[] Serialize<T>(T objectToSerialize)
|
||||
{
|
||||
return Serialize(objectToSerialize, typeof(T));
|
||||
}
|
||||
|
||||
public byte[] Serialize(object objectToSerialize, Type type)
|
||||
{
|
||||
return Serialize(objectToSerialize, context: null);
|
||||
}
|
||||
|
||||
public T Deserialize<T>(byte[] rawData)
|
||||
{
|
||||
return Deserialize<T>(rawData: rawData, context: null);
|
||||
}
|
||||
|
||||
public object? Deserialize(byte[] rawData, Type type)
|
||||
{
|
||||
return Deserialize(rawData: rawData, type, context: null);
|
||||
}
|
||||
|
||||
public T Deserialize<T>(Span<byte> rawData)
|
||||
{
|
||||
return Deserialize<T>(rawData.ToArray().AsMemory(), context: null);
|
||||
}
|
||||
|
||||
public object? Deserialize(Span<byte> rawData, Type type)
|
||||
{
|
||||
return Deserialize(rawData: rawData.ToArray(), type: type);
|
||||
}
|
||||
|
||||
public T Cast<T>(object nonCasted)
|
||||
{
|
||||
return Cast<T>(nonCasted: nonCasted, context: null);
|
||||
}
|
||||
|
||||
public object Cast(object nonCasted, Type type)
|
||||
{
|
||||
return Cast(nonCasted: nonCasted, type: type, context: null);
|
||||
return new CborSerializationToolkit();
|
||||
}
|
||||
|
||||
public void WriteData(object? obj, CborWriter writer, IEndPointContext? context)
|
||||
@@ -166,7 +130,7 @@ namespace mROA.Cbor
|
||||
parser.Write(writer, obj, context, this);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (obj)
|
||||
{
|
||||
case int i:
|
||||
@@ -199,8 +163,9 @@ namespace mROA.Cbor
|
||||
case DateTimeOffset dto:
|
||||
writer.WriteDateTimeOffset(dto);
|
||||
break;
|
||||
case Guid g:
|
||||
writer.WriteByteString(g.ToByteArray());
|
||||
case RequestId g:
|
||||
// writer.WriteByteString(g.ToByteArray());
|
||||
g.WriteToCborInline(writer);
|
||||
break;
|
||||
case byte[] bytes:
|
||||
writer.WriteByteString(bytes);
|
||||
@@ -288,6 +253,7 @@ namespace mROA.Cbor
|
||||
{
|
||||
return parser.Read(reader, context, this);
|
||||
}
|
||||
|
||||
var state = reader.PeekState();
|
||||
switch (state)
|
||||
{
|
||||
@@ -301,13 +267,11 @@ namespace mROA.Cbor
|
||||
return reader.ReadInt64();
|
||||
if (type == typeof(uint))
|
||||
return reader.ReadUInt32();
|
||||
if (type == typeof(ulong))
|
||||
return reader.ReadUInt64();
|
||||
|
||||
return reader.ReadUInt64();
|
||||
case CborReaderState.ByteString:
|
||||
if (type == typeof(Guid))
|
||||
return new Guid(reader.ReadByteString());
|
||||
if (type == typeof(RequestId))
|
||||
return new RequestId(reader.ReadByteString());
|
||||
return reader.ReadByteString();
|
||||
case CborReaderState.TextString:
|
||||
return reader.ReadTextString();
|
||||
@@ -481,15 +445,15 @@ namespace mROA.Cbor
|
||||
public static List<PropertyInfo> FilterProperties(PropertyInfo[] properties)
|
||||
{
|
||||
var finalProperties = new List<PropertyInfo>(properties.Length);
|
||||
|
||||
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var property = properties[i];
|
||||
if (property is not { CanRead: true, CanWrite: true } || property.GetCustomAttribute<SerializationIgnoreAttribute>() != null)
|
||||
if (property is not { CanRead: true, CanWrite: true } ||
|
||||
property.GetCustomAttribute<SerializationIgnoreAttribute>() != null)
|
||||
continue;
|
||||
|
||||
|
||||
finalProperties.Add(property);
|
||||
|
||||
}
|
||||
|
||||
return finalProperties;
|
||||
|
||||
@@ -12,38 +12,14 @@ namespace mROA.Cbor
|
||||
object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization);
|
||||
}
|
||||
|
||||
public class NetworkMessageHeaderParser : IOrdinaryStructureParser
|
||||
public class CallRequestParser : IOrdinaryStructureParser
|
||||
{
|
||||
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization)
|
||||
{
|
||||
var v = value as NetworkMessageHeader;
|
||||
writer.WriteStartArray(3);
|
||||
writer.WriteByteString(v.Id.ToByteArray());
|
||||
writer.WriteInt32((int)v.MessageType);
|
||||
writer.WriteByteString(v.Data);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
public object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization)
|
||||
{
|
||||
reader.ReadStartArray();
|
||||
var value = new NetworkMessageHeader
|
||||
{
|
||||
Id = new Guid(reader.ReadByteString()),
|
||||
MessageType = (EMessageType)reader.ReadInt32(),
|
||||
Data = reader.ReadByteString()
|
||||
};
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public class DefaultCallRequestParser : IOrdinaryStructureParser
|
||||
{
|
||||
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization)
|
||||
{
|
||||
var v = (DefaultCallRequest)value;
|
||||
var v = (CallRequest)value;
|
||||
writer.WriteStartArray(4);
|
||||
writer.WriteByteString(v.Id.ToByteArray());
|
||||
v.Id.WriteToCborInline(writer);
|
||||
// writer.WriteByteString(v.Id.ToByteArray());
|
||||
writer.WriteInt32(v.CommandId);
|
||||
writer.WriteStartArray(1);
|
||||
writer.WriteUInt64(v.ObjectId.Flat);
|
||||
@@ -55,9 +31,9 @@ namespace mROA.Cbor
|
||||
public object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization)
|
||||
{
|
||||
reader.ReadStartArray();
|
||||
var value = new DefaultCallRequest
|
||||
var value = new CallRequest
|
||||
{
|
||||
Id = new Guid(reader.ReadByteString()),
|
||||
Id = new RequestId(reader.ReadByteString()),
|
||||
CommandId = reader.ReadInt32(),
|
||||
ObjectId = (ComplexObjectIdentifier)ComplexObjectIdentifierParser.Instance.Read(reader, context, serialization),
|
||||
Parameters = serialization.ReadData(reader, typeof(object[]), context) as object[]
|
||||
@@ -92,7 +68,8 @@ namespace mROA.Cbor
|
||||
{
|
||||
var v = (FinalCommandExecution<object>)value;
|
||||
writer.WriteStartArray(2);
|
||||
writer.WriteByteString(v.Id.ToByteArray());
|
||||
// writer.WriteByteString(v.Id.ToByteArray());
|
||||
v.Id.WriteToCborInline(writer);
|
||||
serialization.WriteData(v.Result, writer, context);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
@@ -102,7 +79,7 @@ namespace mROA.Cbor
|
||||
reader.ReadStartArray();
|
||||
var result = new FinalCommandExecution<object>
|
||||
{
|
||||
Id = new Guid(reader.ReadByteString()),
|
||||
Id = new RequestId(reader.ReadByteString()),
|
||||
Result = serialization.ReadData(reader, typeof(object), context),
|
||||
};
|
||||
reader.ReadEndArray();
|
||||
@@ -116,7 +93,8 @@ namespace mROA.Cbor
|
||||
{
|
||||
var v = (FinalCommandExecution)value;
|
||||
writer.WriteStartArray(1);
|
||||
writer.WriteByteString(v.Id.ToByteArray());
|
||||
// writer.WriteByteString(v.Id.ToByteArray());
|
||||
v.Id.WriteToCborInline(writer);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
@@ -125,7 +103,7 @@ namespace mROA.Cbor
|
||||
reader.ReadStartArray();
|
||||
var result = new FinalCommandExecution
|
||||
{
|
||||
Id = new Guid(reader.ReadByteString())
|
||||
Id = new RequestId(reader.ReadByteString())
|
||||
};
|
||||
reader.ReadEndArray();
|
||||
return result;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<Version>2.0.7</Version>
|
||||
<LangVersion>9</LangVersion>
|
||||
<PackageIcon>mroaLogo.png</PackageIcon>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
@@ -21,10 +22,6 @@
|
||||
<ProjectReference Include="..\mROA\mROA.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Formats.Cbor" Version="9.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="mroaLogo.png">
|
||||
<Pack>True</Pack>
|
||||
@@ -32,4 +29,8 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Formats.Cbor" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -29,9 +29,9 @@ namespace mROA.Codegen
|
||||
Console.WriteLine($"Try to send to {ownerId} with hash code {context.GetHashCode()}");
|
||||
<!I callFilter>
|
||||
Console.WriteLine("Sending event...");
|
||||
var request = new DefaultCallRequest
|
||||
var request = new CallRequest
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Id = RequestId.Generate(),
|
||||
CommandId = <!L commandId>,
|
||||
ObjectId = new ComplexObjectIdentifier(index, ownerId),
|
||||
Parameters = new object[] { <!L transferParameters> }
|
||||
|
||||
@@ -11,7 +11,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Microsoft.CodeAnalysis.Text;
|
||||
using mROA.Codegen.Templates;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable.
|
||||
|
||||
namespace mROA.Codegen
|
||||
{
|
||||
@@ -324,7 +323,7 @@ namespace mROA.Codegen
|
||||
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||
break;
|
||||
case "RequestContext":
|
||||
parametersInsertList.Add("special[0] as RequestContext");
|
||||
parametersInsertList.Add("(RequestContext)special[0]");
|
||||
break;
|
||||
default:
|
||||
parametersInsertList.Add(CodegenUtilities.Caster(parameter.Type,
|
||||
@@ -430,7 +429,7 @@ namespace mROA.Codegen
|
||||
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||
break;
|
||||
case "RequestContext":
|
||||
parametersInsertList.Add("special[0] as RequestContext");
|
||||
parametersInsertList.Add("(RequestContext)special[0]");
|
||||
break;
|
||||
default:
|
||||
parametersInsertList.Add(CodegenUtilities.Caster(parameter.i,
|
||||
|
||||
@@ -20,4 +20,28 @@ public class Identifier
|
||||
Assert.Fail();
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RequestIdTest()
|
||||
{
|
||||
var id = RequestId.Generate();
|
||||
Assert.Pass(id.ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EqualsTest()
|
||||
{
|
||||
var id = RequestId.Generate();
|
||||
var id2 = new RequestId { P0 = id.P0, P1 = id.P1 };
|
||||
Assert.That(id2, Is.EqualTo(id));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ByteString()
|
||||
{
|
||||
var id = RequestId.Generate();
|
||||
var binary = id.ToByteArray();
|
||||
var reverced = new RequestId(binary);
|
||||
Assert.That(reverced, Is.EqualTo(id));
|
||||
}
|
||||
}
|
||||
@@ -17,8 +17,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Shared", "Example.S
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example.Frontend\Example.Frontend.csproj", "{9BD25A13-3165-47C0-9EAA-5C59EC490E32}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA.Cbor.csproj", "{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}"
|
||||
@@ -31,6 +29,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Functionality.Shared", "Fun
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C20901F-B416-4ABC-8AA4-9059646B081B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{E021E8B3-56C2-400E-A05E-523CF7831189}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -61,10 +61,6 @@ Global
|
||||
{9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9BD25A13-3165-47C0-9EAA-5C59EC490E32}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -81,6 +77,10 @@ Global
|
||||
{D9D28596-E10C-4A98-A2AA-573219467506}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface ICancellationRepository
|
||||
{
|
||||
void RegisterCancellation(Guid id, CancellationTokenSource cts);
|
||||
CancellationTokenSource? GetCancellation(Guid id);
|
||||
void FreeCancelation(Guid id);
|
||||
void RegisterCancellation(RequestId id, CancellationTokenSource cts);
|
||||
CancellationTokenSource? GetCancellation(RequestId id);
|
||||
void FreeCancellation(RequestId id);
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,13 @@ namespace mROA.Abstract
|
||||
{
|
||||
int ConnectionId { get; set; }
|
||||
IEndPointContext Context { get; set; }
|
||||
Channel<NetworkMessageHeader> ReceiveChanel { get; }
|
||||
ChannelReader<NetworkMessageHeader> TrustedPostChanel { get; }
|
||||
ChannelReader<NetworkMessageHeader> UntrustedPostChanel { get; }
|
||||
Channel<NetworkMessage> ReceiveChanel { get; }
|
||||
ChannelReader<NetworkMessage> TrustedPostChanel { get; }
|
||||
ChannelReader<NetworkMessage> UntrustedPostChanel { get; }
|
||||
Func<bool> IsConnected { get; set; }
|
||||
ValueTask<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true);
|
||||
Task PostMessageAsync(NetworkMessageHeader messageHeader);
|
||||
Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader);
|
||||
ValueTask<NetworkMessage> GetNextMessageReceiving();
|
||||
Task PostMessageAsync(NetworkMessage message);
|
||||
Task PostMessageUntrustedAsync(NetworkMessage message);
|
||||
event Action<int> OnDisconnected;
|
||||
Task Restart(bool sendRecovery);
|
||||
void PassReconnection();
|
||||
|
||||
@@ -5,6 +5,6 @@ namespace mROA.Abstract
|
||||
{
|
||||
public interface ICommandExecution : INetworkMessage
|
||||
{
|
||||
Guid Id { get; set; }
|
||||
RequestId Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,8 @@
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public delegate void ConnectionHandler(IRepresentationModule representationModule);
|
||||
|
||||
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
|
||||
|
||||
public interface IConnectionHub
|
||||
{
|
||||
void RegisterInteraction(IChannelInteractionModule interaction);
|
||||
IChannelInteractionModule GetInteraction(int id);
|
||||
event ConnectionHandler? OnConnected;
|
||||
event DisconnectionHandler? OnDisconnected;
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,7 @@ namespace mROA.Abstract
|
||||
T Deserialize<T>(byte[] rawData, IEndPointContext? context);
|
||||
object? Deserialize(byte[] rawData, Type type, IEndPointContext? context);
|
||||
T Deserialize<T>(ReadOnlyMemory<byte> rawMemory, IEndPointContext? context);
|
||||
object? Deserialize(ReadOnlyMemory<byte> rawMemory, Type type, IEndPointContext? context);
|
||||
T Cast<T>(object nonCasted, IEndPointContext? context);
|
||||
object? Cast(object? nonCasted, Type type, IEndPointContext? context);
|
||||
IContextualSerializationToolKit Clone();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface IEventBinder<T> : IEventBinder
|
||||
public interface IEventBinder<in T> : IEventBinder
|
||||
{
|
||||
public void BindEvents(T source, IEndPointContext context,
|
||||
IRepresentationModuleProducer representationModuleProducer, int index);
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using mROA.Implementation;
|
||||
using mROA.Implementation.CommandExecution;
|
||||
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface IExecuteModule
|
||||
{
|
||||
ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository,
|
||||
ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository,
|
||||
IRepresentationModule representationModule, IEndPointContext context);
|
||||
ICommandExecution Cancel(CancelRequest command);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface IOwnershipRepository
|
||||
{
|
||||
int GetOwnershipId();
|
||||
int GetHostOwnershipId();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,5 @@ namespace mROA.Abstract
|
||||
{
|
||||
public interface IRealStoreInstanceRepository : IInstanceRepository
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface IRemoteObjectFactory
|
||||
{
|
||||
T Produce<T>(ComplexObjectIdentifier id, IEndPointContext context);
|
||||
}
|
||||
}
|
||||
@@ -11,21 +11,21 @@ namespace mROA.Abstract
|
||||
int Id { get; }
|
||||
IEndPointContext Context { get; }
|
||||
|
||||
Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate<NetworkMessageHeader> rule,
|
||||
Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate<NetworkMessage> rule,
|
||||
IEndPointContext? context, CancellationToken token = default,
|
||||
params Func<NetworkMessageHeader, Type?>[] converter);
|
||||
params Func<NetworkMessage, Type?>[] converter);
|
||||
|
||||
IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate<NetworkMessageHeader> rule,
|
||||
IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate<NetworkMessage> rule,
|
||||
IEndPointContext? context, CancellationToken token = default,
|
||||
params Func<NetworkMessageHeader, Type?>[] converter);
|
||||
params Func<NetworkMessage, Type?>[] converter);
|
||||
|
||||
Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
Task PostCallMessageAsync<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
where T : notnull;
|
||||
|
||||
void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
void PostCallMessage<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
where T : notnull;
|
||||
|
||||
Task PostCallMessageUntrustedAsync<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
Task PostCallMessageUntrustedAsync<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
where T : notnull;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,14 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using mROA.Implementation;
|
||||
|
||||
namespace mROA.Abstract
|
||||
{
|
||||
public interface IRequestExtractor
|
||||
{
|
||||
Task StartExtraction();
|
||||
void PushMessage(object parced, EMessageType originalType);
|
||||
Predicate<NetworkMessage> Rule { get; }
|
||||
Func<NetworkMessage, Type?>[] Converters { get; }
|
||||
}
|
||||
}
|
||||
@@ -11,31 +11,27 @@ namespace mROA.Implementation.Backend
|
||||
private readonly IMethodRepository _methodRepo;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
|
||||
public BasicExecutionModule(ICancellationRepository cancellationRepo, IMethodRepository methodRepo, IContextualSerializationToolKit serialization)
|
||||
public BasicExecutionModule(ICancellationRepository cancellationRepo, IMethodRepository methodRepo,
|
||||
IContextualSerializationToolKit serialization)
|
||||
{
|
||||
_cancellationRepo = cancellationRepo;
|
||||
_methodRepo = methodRepo;
|
||||
_serialization = serialization;
|
||||
}
|
||||
|
||||
public ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository,
|
||||
public ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository,
|
||||
IRepresentationModule representationModule, IEndPointContext endPointContext)
|
||||
{
|
||||
// _logger.LogInformation("Executing {0}", command.Id);
|
||||
try
|
||||
{
|
||||
ThrowIfNotInjected(instanceRepository);
|
||||
if (command is CancelRequest)
|
||||
{
|
||||
return CancelExecution(command);
|
||||
}
|
||||
|
||||
var invoker = _methodRepo.GetMethod(command.CommandId);
|
||||
if (invoker == null)
|
||||
throw new Exception($"Command {command.CommandId} not found");
|
||||
|
||||
var context = GetContext(command, instanceRepository, invoker, endPointContext);
|
||||
var instance = GetInstance(command, instanceRepository, invoker, endPointContext);
|
||||
|
||||
if (context == null)
|
||||
if (instance is null)
|
||||
throw new NullReferenceException("Instance can't be null");
|
||||
|
||||
|
||||
@@ -47,24 +43,10 @@ namespace mROA.Implementation.Backend
|
||||
|
||||
var execContext = new RequestContext(command.Id, representationModule.Id);
|
||||
|
||||
switch (invoker)
|
||||
{
|
||||
case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker:
|
||||
return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command,
|
||||
_cancellationRepo,
|
||||
representationModule, execContext, endPointContext);
|
||||
case AsyncMethodInvoker asyncMethodInvoker:
|
||||
return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo,
|
||||
representationModule, execContext, endPointContext);
|
||||
default:
|
||||
var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext);
|
||||
if (command.CommandId == -1)
|
||||
{
|
||||
instanceRepository.ClearObject(command.ObjectId, endPointContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
var executionResult = ExecuteRequest(command, instanceRepository, representationModule, endPointContext,
|
||||
invoker,
|
||||
instance, castedParams, execContext);
|
||||
return executionResult;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -76,16 +58,41 @@ namespace mROA.Implementation.Backend
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetContext(ICallRequest command, IInstanceRepository instanceRepository,
|
||||
private ICommandExecution? ExecuteRequest(CallRequest command, IInstanceRepository instanceRepository,
|
||||
IRepresentationModule representationModule, IEndPointContext endPointContext, IMethodInvoker invoker,
|
||||
object context, object?[]? castedParams, RequestContext execContext)
|
||||
{
|
||||
switch (invoker)
|
||||
{
|
||||
case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker:
|
||||
return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command,
|
||||
_cancellationRepo,
|
||||
representationModule, execContext, endPointContext);
|
||||
case AsyncMethodInvoker asyncMethodInvoker:
|
||||
return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo,
|
||||
representationModule, execContext, endPointContext);
|
||||
default:
|
||||
var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext);
|
||||
if (command.CommandId == -1)
|
||||
{
|
||||
instanceRepository.ClearObject(command.ObjectId, endPointContext);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetInstance(CallRequest command, IInstanceRepository instanceRepository,
|
||||
IMethodInvoker invoker, IEndPointContext endPointContext)
|
||||
{
|
||||
var context = command.ObjectId.ContextId != -1
|
||||
? instanceRepository.GetObject<object>(command.ObjectId, endPointContext)
|
||||
: instanceRepository.GetSingletonObject(invoker.SuitableType, endPointContext);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker, IEndPointContext context)
|
||||
private object?[] CastedParams(CallRequest command, IMethodInvoker invoker, IEndPointContext context)
|
||||
{
|
||||
object?[] castedParams = new object[invoker.ParameterTypes.Length];
|
||||
for (var i = 0; i < castedParams.Length; i++)
|
||||
@@ -96,25 +103,13 @@ namespace mROA.Implementation.Backend
|
||||
return castedParams;
|
||||
}
|
||||
|
||||
private void ThrowIfNotInjected(IInstanceRepository instanceRepository)
|
||||
{
|
||||
if (_cancellationRepo is null)
|
||||
throw new NullReferenceException("Method repository was not defined");
|
||||
|
||||
if (_methodRepo is null)
|
||||
throw new NullReferenceException("Method repository was not defined");
|
||||
|
||||
if (instanceRepository is null)
|
||||
throw new NullReferenceException("Context repository was not defined");
|
||||
}
|
||||
|
||||
private FinalCommandExecution CancelExecution(ICallRequest command)
|
||||
public ICommandExecution Cancel(CancelRequest command)
|
||||
{
|
||||
var cts = _cancellationRepo.GetCancellation(command.Id);
|
||||
if (cts == null)
|
||||
throw new NullReferenceException("Can't find cancellation for this request");
|
||||
cts.Cancel();
|
||||
_cancellationRepo.FreeCancelation(command.Id);
|
||||
_cancellationRepo.FreeCancellation(command.Id);
|
||||
|
||||
return new FinalCommandExecution
|
||||
{
|
||||
@@ -122,131 +117,84 @@ namespace mROA.Implementation.Backend
|
||||
};
|
||||
}
|
||||
|
||||
private static ICommandExecution Execute(MethodInvoker invoker, object instance, object?[] parameter,
|
||||
ICallRequest command, RequestContext executionContext)
|
||||
private static ICommandExecution? Execute(MethodInvoker invoker, object instance, object?[] parameter,
|
||||
CallRequest command, RequestContext executionContext)
|
||||
{
|
||||
try
|
||||
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||
|
||||
if (!invoker.IsTrusted)
|
||||
{
|
||||
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||
|
||||
if (!invoker.IsTrusted)
|
||||
{
|
||||
return new AsyncCommandExecution();
|
||||
}
|
||||
|
||||
if (invoker.IsVoid)
|
||||
{
|
||||
return new FinalCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
|
||||
return new FinalCommandExecution<object>
|
||||
{
|
||||
Result = finalResult,
|
||||
Id = command.Id
|
||||
};
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
if (invoker.IsVoid)
|
||||
{
|
||||
if (invoker.IsTrusted)
|
||||
return new ExceptionCommandExecution
|
||||
{
|
||||
Id = command.Id,
|
||||
Exception = e.ToString()
|
||||
};
|
||||
return new AsyncCommandExecution
|
||||
return new FinalCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
|
||||
return new FinalCommandExecution<object>
|
||||
{
|
||||
Result = finalResult,
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
|
||||
private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||
private ICommandExecution? ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
CallRequest command, ICancellationRepository cancellationRepository,
|
||||
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||
var token = tokenSource.Token;
|
||||
|
||||
try
|
||||
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
|
||||
{
|
||||
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
var payload = new FinalCommandExecution
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
Id = command.Id
|
||||
};
|
||||
_cancellationRepo.FreeCancellation(command.Id);
|
||||
|
||||
var payload = new FinalCommandExecution
|
||||
|
||||
if (invoker.IsTrusted)
|
||||
representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
|
||||
payload, context);
|
||||
});
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ICommandExecution? TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
CallRequest command, ICancellationRepository cancellationRepository,
|
||||
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||
|
||||
var token = tokenSource.Token;
|
||||
|
||||
invoker.Invoke(instance, parameters, new object[] { executionContext, token },
|
||||
finalResult =>
|
||||
{
|
||||
var payload = new FinalCommandExecution<object>
|
||||
{
|
||||
Id = command.Id
|
||||
Id = command.Id,
|
||||
Result = finalResult
|
||||
};
|
||||
_cancellationRepo?.FreeCancelation(command.Id);
|
||||
_cancellationRepo.FreeCancellation(command.Id);
|
||||
|
||||
|
||||
if (invoker.IsTrusted)
|
||||
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution,
|
||||
payload, context);
|
||||
representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
|
||||
payload, context);
|
||||
});
|
||||
|
||||
return new AsyncCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (invoker.IsTrusted)
|
||||
return new ExceptionCommandExecution
|
||||
{
|
||||
Id = command.Id,
|
||||
Exception = e.ToString()
|
||||
};
|
||||
return new AsyncCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||
|
||||
var token = tokenSource.Token;
|
||||
try
|
||||
{
|
||||
invoker.Invoke(instance, parameters, new object[] { executionContext, token },
|
||||
finalResult =>
|
||||
{
|
||||
var payload = new FinalCommandExecution<object>
|
||||
{
|
||||
Id = command.Id,
|
||||
Result = finalResult
|
||||
};
|
||||
_cancellationRepo.FreeCancelation(command.Id);
|
||||
|
||||
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution,
|
||||
payload, context);
|
||||
});
|
||||
|
||||
return new AsyncCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return new ExceptionCommandExecution
|
||||
{
|
||||
Id = command.Id,
|
||||
Exception = e.ToString()
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,18 +7,10 @@ namespace mROA.Implementation.Backend
|
||||
public class ConnectionHub : IConnectionHub
|
||||
{
|
||||
private readonly Dictionary<int, IChannelInteractionModule> _connections = new();
|
||||
private readonly IContextualSerializationToolKit _serializationToolkit;
|
||||
|
||||
public ConnectionHub(IContextualSerializationToolKit serializationToolkit)
|
||||
{
|
||||
_serializationToolkit = serializationToolkit;
|
||||
}
|
||||
|
||||
public void RegisterInteraction(IChannelInteractionModule interaction)
|
||||
{
|
||||
_connections.Add(interaction.ConnectionId, interaction);
|
||||
var module = new RepresentationModule(interaction, _serializationToolkit);
|
||||
OnConnected?.Invoke(module);
|
||||
}
|
||||
|
||||
public IChannelInteractionModule GetInteraction(int id)
|
||||
@@ -26,8 +18,5 @@ namespace mROA.Implementation.Backend
|
||||
return _connections!.GetValueOrDefault(id, null) ?? _connections!.GetValueOrDefault(-id, null) ??
|
||||
throw new Exception("No connection found");
|
||||
}
|
||||
|
||||
public event ConnectionHandler? OnConnected;
|
||||
public event DisconnectionHandler? OnDisconnected;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Options;
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation.Frontend;
|
||||
|
||||
@@ -5,28 +7,34 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
public class HubRequestExtractor
|
||||
{
|
||||
private IRealStoreInstanceRepository _contextRepository;
|
||||
private IInstanceRepository _remoteContextRepository;
|
||||
private IMethodRepository _methodRepository;
|
||||
private IContextualSerializationToolKit _serializationToolkit;
|
||||
private IExecuteModule _executeModule;
|
||||
private readonly IRealStoreInstanceRepository _contextRepository;
|
||||
private readonly IInstanceRepository _remoteContextRepository;
|
||||
private readonly IExecuteModule _executeModule;
|
||||
private readonly DistributionOptions _mode;
|
||||
private readonly Dictionary<int, IRequestExtractor> _producedExtractors = new();
|
||||
|
||||
public HubRequestExtractor(IConnectionHub hub, IRealStoreInstanceRepository contextRepository,
|
||||
IInstanceRepository remoteContextRepository, IMethodRepository methodRepository,
|
||||
IContextualSerializationToolKit serializationToolkit, IExecuteModule executeModule)
|
||||
public HubRequestExtractor(IRealStoreInstanceRepository contextRepository,
|
||||
IInstanceRepository remoteContextRepository, IExecuteModule executeModule,
|
||||
IOptions<DistributionOptions> mode)
|
||||
{
|
||||
hub.OnConnected += HubOnOnConnected;
|
||||
_contextRepository = contextRepository;
|
||||
_remoteContextRepository = remoteContextRepository;
|
||||
_methodRepository = methodRepository;
|
||||
_serializationToolkit = serializationToolkit;
|
||||
_executeModule = executeModule;
|
||||
_mode = mode.Value;
|
||||
}
|
||||
|
||||
private void HubOnOnConnected(IRepresentationModule interaction)
|
||||
public IRequestExtractor this[int id] => _producedExtractors[id];
|
||||
|
||||
public IRequestExtractor HubOnOnConnected(IRepresentationModule representationModule)
|
||||
{
|
||||
var extractor = CreateExtractor(interaction);
|
||||
extractor.StartExtraction().ContinueWith(_ => OnDisconnected(interaction));
|
||||
var extractor = CreateExtractor(representationModule);
|
||||
if (_mode.DistributionType == EDistributionType.Channeled)
|
||||
{
|
||||
extractor.StartExtraction().ContinueWith(_ => OnDisconnected(representationModule));
|
||||
}
|
||||
|
||||
_producedExtractors[representationModule.Id] = extractor;
|
||||
return extractor;
|
||||
}
|
||||
|
||||
private void OnDisconnected(IRepresentationModule representationModule)
|
||||
@@ -37,7 +45,7 @@ namespace mROA.Implementation.Backend
|
||||
|
||||
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
||||
{
|
||||
var extractor = new RequestExtractor(_executeModule, _methodRepository, interaction, _serializationToolkit, interaction.Context);
|
||||
var extractor = new RequestExtractor(_executeModule, interaction, interaction.Context);
|
||||
var context = interaction.Context;
|
||||
if (_contextRepository is IContextRepositoryHub contextHub)
|
||||
context.RealRepository = contextHub.GetRepository(interaction.Id);
|
||||
@@ -45,7 +53,7 @@ namespace mROA.Implementation.Backend
|
||||
context.RealRepository = _contextRepository;
|
||||
|
||||
context.RemoteRepository = _remoteContextRepository;
|
||||
|
||||
|
||||
return extractor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
public static object[] EventBinders = { };
|
||||
|
||||
private IRepresentationModuleProducer _representationModuleProducer;
|
||||
private readonly IRepresentationModuleProducer _representationModuleProducer;
|
||||
|
||||
private Dictionary<int, object?> _singletons = new();
|
||||
private readonly IStorage<object> _storage;
|
||||
@@ -22,8 +22,6 @@ namespace mROA.Implementation.Backend
|
||||
_storage = new ExtensibleStorage<object>();
|
||||
}
|
||||
|
||||
public int HostId { get; set; }
|
||||
|
||||
public int ResisterObject<T>(object o, IEndPointContext context)
|
||||
{
|
||||
var last = _storage.Place(o);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation.Backend
|
||||
@@ -14,8 +15,6 @@ namespace mROA.Implementation.Backend
|
||||
_produceRepository = produceRepository;
|
||||
}
|
||||
|
||||
public int HostId { get; set; }
|
||||
|
||||
public int ResisterObject<T>(object o, IEndPointContext context)
|
||||
{
|
||||
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||
|
||||
@@ -11,21 +11,26 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
public class NetworkGatewayModule : IGatewayModule
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly TcpListener _tcpListener;
|
||||
private readonly IConnectionHub _hub;
|
||||
private readonly HubRequestExtractor _hre;
|
||||
private readonly DistributionOptions _distribution;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
private readonly Dictionary<int, CancellationTokenSource> _extractorsCTS = new();
|
||||
private ICallIndexProvider _callIndexProvider;
|
||||
private readonly Dictionary<int, CancellationTokenSource> _extractorsTokenSources = new();
|
||||
private readonly ICallIndexProvider _callIndexProvider;
|
||||
private readonly IIdentityGenerator _identityGenerator;
|
||||
public NetworkGatewayModule(IOptions<GatewayOptions> options, IServiceProvider service, IIdentityGenerator identityGenerator, IContextualSerializationToolKit serialization, ICallIndexProvider callIndexProvider, IConnectionHub hub)
|
||||
|
||||
public NetworkGatewayModule(IOptions<GatewayOptions> options, IIdentityGenerator identityGenerator,
|
||||
IContextualSerializationToolKit serialization, ICallIndexProvider callIndexProvider, IConnectionHub hub,
|
||||
IOptions<DistributionOptions> distribution, HubRequestExtractor hre)
|
||||
{
|
||||
_tcpListener = new(options.Value.Endpoint);
|
||||
_serviceProvider = service;
|
||||
_identityGenerator = identityGenerator;
|
||||
_serialization = serialization;
|
||||
_callIndexProvider = callIndexProvider;
|
||||
_hub = hub;
|
||||
_hre = hre;
|
||||
_distribution = distribution.Value;
|
||||
}
|
||||
|
||||
public void Run()
|
||||
@@ -47,67 +52,123 @@ namespace mROA.Implementation.Backend
|
||||
while (true)
|
||||
{
|
||||
var client = await _tcpListener.AcceptTcpClientAsync();
|
||||
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
||||
var interaction = new ChannelInteractionModule(_serialization, _identityGenerator);
|
||||
|
||||
var context = new EndPointContext(null, null);
|
||||
context.CallIndexProvider = _callIndexProvider;
|
||||
var streamExtractor =
|
||||
new ChannelInteractionModule.StreamExtractor(client.GetStream(), _serialization, context);
|
||||
interaction.IsConnected = () => streamExtractor.IsConnected;
|
||||
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();
|
||||
_ = HandleConnection(client);
|
||||
}
|
||||
}
|
||||
|
||||
switch (connectionRequest.MessageType)
|
||||
private async Task HandleConnection(TcpClient client)
|
||||
{
|
||||
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
||||
var interaction = new ChannelInteractionModule(_serialization, _identityGenerator);
|
||||
|
||||
var context = new EndPointContext(null, null)
|
||||
{
|
||||
CallIndexProvider = _callIndexProvider
|
||||
};
|
||||
var streamExtractor =
|
||||
new ChannelInteractionModule.StreamExtractor(client.GetStream());
|
||||
interaction.IsConnected = () => streamExtractor.IsConnected;
|
||||
streamExtractor.MessageReceived = async message =>
|
||||
{
|
||||
await interaction.ReceiveChanel.Writer.WriteAsync(message).ConfigureAwait(false);
|
||||
};
|
||||
_ = Task.Run(() => streamExtractor.SingleReceive());
|
||||
var connectionRequest = await interaction.ReceiveChanel.Reader.ReadAsync();
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
switch (connectionRequest.MessageType)
|
||||
{
|
||||
case EMessageType.ClientConnect:
|
||||
|
||||
HandleNewClient(context, interaction, streamExtractor, cts, connectionRequest);
|
||||
break;
|
||||
case EMessageType.ClientRecovery:
|
||||
{
|
||||
case EMessageType.ClientConnect:
|
||||
context.HostId = 0;
|
||||
context.OwnerId = -interaction.ConnectionId;
|
||||
interaction.Context = context;
|
||||
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));
|
||||
_extractorsCTS[interaction.ConnectionId] = cts;
|
||||
_hub!.RegisterInteraction(interaction);
|
||||
Console.WriteLine("Client registered");
|
||||
break;
|
||||
case EMessageType.ClientRecovery:
|
||||
RecoverDisconnectedClient(connectionRequest, streamExtractor, cts);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
client.Close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleNewClient(EndPointContext context, ChannelInteractionModule interaction,
|
||||
ChannelInteractionModule.StreamExtractor streamExtractor, CancellationTokenSource cts, NetworkMessage connection)
|
||||
{
|
||||
context.HostId = 0;
|
||||
context.OwnerId = -interaction.ConnectionId;
|
||||
interaction.Context = context;
|
||||
Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token));
|
||||
_ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token);
|
||||
interaction.PostMessageAsync(new NetworkMessage(_serialization,
|
||||
new IdAssignment { Id = interaction.ConnectionId }, null));
|
||||
_extractorsTokenSources[interaction.ConnectionId] = cts;
|
||||
|
||||
_hub.RegisterInteraction(interaction);
|
||||
var requestExtractor = _hre.HubOnOnConnected(new RepresentationModule(interaction, _serialization.Clone()));
|
||||
|
||||
if (_distribution.DistributionType != EDistributionType.Channeled)
|
||||
{
|
||||
BindRequestFirstDistribution(context, interaction, streamExtractor, requestExtractor);
|
||||
}
|
||||
}
|
||||
|
||||
private void BindRequestFirstDistribution(IEndPointContext context, IChannelInteractionModule interaction,
|
||||
ChannelInteractionModule.StreamExtractor streamExtractor, IRequestExtractor requestExtractor)
|
||||
{
|
||||
var converters = requestExtractor.Converters;
|
||||
streamExtractor.MessageReceived = message =>
|
||||
{
|
||||
if (requestExtractor.Rule(message))
|
||||
{
|
||||
for (var i = 0; i < converters.Length; i++)
|
||||
{
|
||||
var recoveryRequest = _serialization!.Deserialize<ClientRecovery>(connectionRequest.Data, null);
|
||||
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
||||
|
||||
_extractorsCTS[-recoveryRequest.Id].Cancel();
|
||||
|
||||
recoveryInteraction.IsConnected = () => streamExtractor.IsConnected;
|
||||
streamExtractor.MessageReceived = message =>
|
||||
{
|
||||
recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message);
|
||||
};
|
||||
_ = streamExtractor.SendFromChannel(recoveryInteraction.TrustedPostChanel, cts.Token);
|
||||
|
||||
Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token));
|
||||
|
||||
|
||||
recoveryInteraction.Restart(false);
|
||||
var func = converters[i];
|
||||
if (func(message) is not { } t) continue;
|
||||
|
||||
var deserialized = _serialization.Deserialize(message.Data, t, context);
|
||||
Task.Run(() => requestExtractor.PushMessage(deserialized, message.MessageType));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
client.Close();
|
||||
break;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
interaction.ReceiveChanel.Writer.WriteAsync(message).ConfigureAwait(false);
|
||||
};
|
||||
}
|
||||
|
||||
private void RecoverDisconnectedClient(NetworkMessage connectionRequest,
|
||||
ChannelInteractionModule.StreamExtractor streamExtractor,
|
||||
CancellationTokenSource cts)
|
||||
{
|
||||
var recoveryRequest = _serialization.Deserialize<ClientRecovery>(connectionRequest.Data, null);
|
||||
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
||||
|
||||
_extractorsTokenSources[-recoveryRequest.Id].Cancel();
|
||||
|
||||
recoveryInteraction.IsConnected = () => streamExtractor.IsConnected;
|
||||
streamExtractor.MessageReceived = message =>
|
||||
{
|
||||
recoveryInteraction.ReceiveChanel.Writer.WriteAsync(message).ConfigureAwait(false);
|
||||
};
|
||||
_ = streamExtractor.SendFromChannel(recoveryInteraction.TrustedPostChanel, cts.Token);
|
||||
|
||||
if (_distribution.DistributionType == EDistributionType.ExtractorFirst)
|
||||
{
|
||||
BindRequestFirstDistribution(recoveryInteraction.Context, recoveryInteraction, streamExtractor,
|
||||
_hre[recoveryInteraction.ConnectionId]);
|
||||
}
|
||||
|
||||
Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token).ConfigureAwait(false));
|
||||
|
||||
recoveryInteraction.Restart(false);
|
||||
}
|
||||
}
|
||||
|
||||
public class GatewayOptions
|
||||
{
|
||||
public IPEndPoint Endpoint { get; set; }
|
||||
public Type InteractionModuleType { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,14 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
public class UdpGateway : IUntrustedGateway
|
||||
{
|
||||
private IConnectionHub _hub;
|
||||
private UdpClient _client;
|
||||
private Dictionary<IPEndPoint, int> _reservedPorts = new();
|
||||
private CancellationTokenSource _tokenSource = new();
|
||||
private IContextualSerializationToolKit _serializationToolkit;
|
||||
private readonly IConnectionHub _hub;
|
||||
private readonly UdpClient _client;
|
||||
private readonly Dictionary<IPEndPoint, int> _reservedPorts = new();
|
||||
private readonly CancellationTokenSource _tokenSource = new();
|
||||
private readonly IContextualSerializationToolKit _serializationToolkit;
|
||||
|
||||
public UdpGateway(IOptions<GatewayOptions> options, IConnectionHub hub, IContextualSerializationToolKit serializationToolkit)
|
||||
public UdpGateway(IOptions<GatewayOptions> options, IConnectionHub hub,
|
||||
IContextualSerializationToolKit serializationToolkit)
|
||||
{
|
||||
_hub = hub;
|
||||
_serializationToolkit = serializationToolkit;
|
||||
@@ -40,7 +41,7 @@ namespace mROA.Implementation.Backend
|
||||
while (token.IsCancellationRequested == false)
|
||||
{
|
||||
var incoming = await _client.ReceiveAsync();
|
||||
var parsed = _serializationToolkit.Deserialize<NetworkMessageHeader>(incoming.Buffer, null);
|
||||
var parsed = _serializationToolkit.Deserialize<NetworkMessage>(incoming.Buffer, null);
|
||||
try
|
||||
{
|
||||
int channelId;
|
||||
@@ -72,7 +73,7 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
await foreach (var post in interaction.UntrustedPostChanel.ReadAllAsync())
|
||||
{
|
||||
if (post.MessageType is not (CallRequest or EMessageType.CancelRequest
|
||||
if (post.MessageType is not (EMessageType.CallRequest or EMessageType.CancelRequest
|
||||
or EventRequest))
|
||||
continue;
|
||||
|
||||
|
||||
@@ -1,21 +1,12 @@
|
||||
using System;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public interface ICallRequest
|
||||
{
|
||||
Guid Id { get; }
|
||||
int CommandId { get; }
|
||||
ComplexObjectIdentifier ObjectId { get; }
|
||||
object?[]? Parameters { get; }
|
||||
}
|
||||
|
||||
public struct DefaultCallRequest : ICallRequest
|
||||
|
||||
public struct CallRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public RequestId Id { get; set; }
|
||||
public int CommandId { get; set; }
|
||||
public ComplexObjectIdentifier ObjectId { get; set; }
|
||||
|
||||
@@ -27,16 +18,8 @@ namespace mROA.Implementation
|
||||
}
|
||||
}
|
||||
|
||||
public class CancelRequest : ICallRequest
|
||||
public struct CancelRequest
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public int CommandId { get; set; } = -2;
|
||||
public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null;
|
||||
public object?[]? Parameters { get; set; } = null;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||
}
|
||||
public RequestId Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -8,19 +8,19 @@ namespace mROA.Implementation
|
||||
{
|
||||
public class CancellationRepository : ICancellationRepository
|
||||
{
|
||||
private readonly ConcurrentDictionary<Guid, CancellationTokenSource> _cancellations = new();
|
||||
private readonly ConcurrentDictionary<RequestId, CancellationTokenSource> _cancellations = new();
|
||||
|
||||
public void RegisterCancellation(Guid id, CancellationTokenSource cts)
|
||||
public void RegisterCancellation(RequestId id, CancellationTokenSource cts)
|
||||
{
|
||||
_cancellations.TryAdd(id, cts);
|
||||
}
|
||||
|
||||
public CancellationTokenSource? GetCancellation(Guid id)
|
||||
public CancellationTokenSource? GetCancellation(RequestId id)
|
||||
{
|
||||
return _cancellations.GetValueOrDefault(id);
|
||||
}
|
||||
|
||||
public void FreeCancelation(Guid id)
|
||||
public void FreeCancellation(RequestId id)
|
||||
{
|
||||
_cancellations.Remove(id, out _);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
@@ -10,11 +10,11 @@ namespace mROA.Implementation
|
||||
{
|
||||
public class ChannelInteractionModule : IChannelInteractionModule
|
||||
{
|
||||
private readonly ChannelReader<NetworkMessageHeader> _receiveReader;
|
||||
private readonly ChannelWriter<NetworkMessageHeader> _trustedWriter;
|
||||
private readonly ChannelWriter<NetworkMessageHeader> _untrustedWriter;
|
||||
private readonly Channel<NetworkMessageHeader> _outputTrustedChannel;
|
||||
private readonly Channel<NetworkMessageHeader> _outputUntrustedChannel;
|
||||
private readonly ChannelReader<NetworkMessage> _receiveReader;
|
||||
private readonly ChannelWriter<NetworkMessage> _trustedWriter;
|
||||
private readonly ChannelWriter<NetworkMessage> _untrustedWriter;
|
||||
private readonly Channel<NetworkMessage> _outputTrustedChannel;
|
||||
private readonly Channel<NetworkMessage> _outputUntrustedChannel;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
private bool _isConnected = true;
|
||||
private bool _isActive = true;
|
||||
@@ -29,19 +29,19 @@ namespace mROA.Implementation
|
||||
public ChannelInteractionModule(IContextualSerializationToolKit serialization)
|
||||
{
|
||||
_serialization = serialization;
|
||||
ReceiveChanel = Channel.CreateUnbounded<NetworkMessageHeader>(new UnboundedChannelOptions
|
||||
ReceiveChanel = Channel.CreateUnbounded<NetworkMessage>(new UnboundedChannelOptions
|
||||
{
|
||||
SingleReader = false,
|
||||
SingleWriter = false,
|
||||
});
|
||||
_receiveReader = ReceiveChanel.Reader;
|
||||
_outputTrustedChannel = Channel.CreateUnbounded<NetworkMessageHeader>(new UnboundedChannelOptions
|
||||
_outputTrustedChannel = Channel.CreateUnbounded<NetworkMessage>(new UnboundedChannelOptions
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = true
|
||||
});
|
||||
_trustedWriter = _outputTrustedChannel.Writer;
|
||||
_outputUntrustedChannel = Channel.CreateUnbounded<NetworkMessageHeader>(new UnboundedChannelOptions
|
||||
_outputUntrustedChannel = Channel.CreateUnbounded<NetworkMessage>(new UnboundedChannelOptions
|
||||
{
|
||||
SingleReader = true,
|
||||
SingleWriter = true,
|
||||
@@ -49,45 +49,37 @@ namespace mROA.Implementation
|
||||
_untrustedWriter = _outputUntrustedChannel.Writer;
|
||||
_reconnection = new TaskCompletionSource<Stream>();
|
||||
}
|
||||
|
||||
|
||||
public int ConnectionId { get; set; }
|
||||
|
||||
public IEndPointContext Context { get; set; }
|
||||
public Channel<NetworkMessageHeader> ReceiveChanel { get; }
|
||||
public Channel<NetworkMessage> ReceiveChanel { get; }
|
||||
|
||||
public ChannelReader<NetworkMessageHeader> TrustedPostChanel => _outputTrustedChannel.Reader;
|
||||
public ChannelReader<NetworkMessageHeader> UntrustedPostChanel => _outputUntrustedChannel.Reader;
|
||||
public ChannelReader<NetworkMessage> TrustedPostChanel => _outputTrustedChannel.Reader;
|
||||
public ChannelReader<NetworkMessage> UntrustedPostChanel => _outputUntrustedChannel.Reader;
|
||||
public Func<bool> IsConnected { get; set; } = () => false;
|
||||
|
||||
public ValueTask<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true)
|
||||
public ValueTask<NetworkMessage> GetNextMessageReceiving()
|
||||
{
|
||||
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<bool> PostMessageInternal(NetworkMessageHeader messageHeader)
|
||||
|
||||
private async ValueTask<bool> PostMessageInternal(NetworkMessage message)
|
||||
{
|
||||
if (!IsConnected())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await _trustedWriter.WriteAsync(messageHeader);
|
||||
await _trustedWriter.WriteAsync(message);
|
||||
return true;
|
||||
}
|
||||
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||
|
||||
|
||||
public async Task PostMessageAsync(NetworkMessageHeader messageHeader)
|
||||
public async Task PostMessageAsync(NetworkMessage message)
|
||||
{
|
||||
if (_serialization == null)
|
||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (await PostMessageInternal(messageHeader))
|
||||
if (await PostMessageInternal(message))
|
||||
break;
|
||||
|
||||
if (!_isActive)
|
||||
@@ -100,9 +92,9 @@ namespace mROA.Implementation
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader)
|
||||
public async Task PostMessageUntrustedAsync(NetworkMessage message)
|
||||
{
|
||||
await _untrustedWriter.WriteAsync(messageHeader);
|
||||
await _untrustedWriter.WriteAsync(message);
|
||||
}
|
||||
|
||||
public event Action<int>? OnDisconnected;
|
||||
@@ -112,12 +104,12 @@ namespace mROA.Implementation
|
||||
if (sendRecovery)
|
||||
{
|
||||
await PostMessageAsync(
|
||||
new NetworkMessageHeader(_serialization, new ClientRecovery(Math.Abs(ConnectionId)), Context));
|
||||
new NetworkMessage(_serialization, new ClientRecovery(Math.Abs(ConnectionId)), Context));
|
||||
await ReceiveChanel.Reader.ReadAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
await _trustedWriter.WriteAsync(new NetworkMessageHeader());
|
||||
await _trustedWriter.WriteAsync(new NetworkMessage());
|
||||
}
|
||||
|
||||
PassReconnection();
|
||||
@@ -150,41 +142,34 @@ namespace mROA.Implementation
|
||||
|
||||
public class StreamExtractor
|
||||
{
|
||||
private const int BufferSize = ushort.MaxValue;
|
||||
private const int BufferSize = ushort.MaxValue + 19;
|
||||
|
||||
private readonly Stream _ioStream;
|
||||
private readonly IContextualSerializationToolKit _serializationToolkit;
|
||||
private readonly Memory<byte> _buffer = new byte[BufferSize];
|
||||
private readonly IEndPointContext _context;
|
||||
private readonly byte[] _lenBuffer;
|
||||
|
||||
public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit,
|
||||
IEndPointContext context)
|
||||
public StreamExtractor(Stream ioStream)
|
||||
{
|
||||
_ioStream = ioStream;
|
||||
_serializationToolkit = serializationToolkit;
|
||||
_context = context;
|
||||
_lenBuffer = new byte[2];
|
||||
}
|
||||
|
||||
public Action<NetworkMessageHeader> MessageReceived = _ => { };
|
||||
|
||||
private async Task<ushort> ReadMessageLength()
|
||||
{
|
||||
await _ioStream.ReadAsync(_lenBuffer);
|
||||
|
||||
var len = BitConverter.ToUInt16(_lenBuffer);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
public Action<NetworkMessage> MessageReceived = _ => { };
|
||||
|
||||
public async Task SingleReceive(CancellationToken token = default)
|
||||
{
|
||||
var len = await ReadMessageLength();
|
||||
var localSpan = _buffer[..len];
|
||||
var firstRead = await _ioStream.ReadAsync(_buffer, token);
|
||||
|
||||
var meta = MemoryMarshal.Read<NetworkMessage.NetworkMessageMeta>(_buffer.Span);
|
||||
|
||||
var len = meta.BodyLength;
|
||||
var readLen = firstRead - 19;
|
||||
|
||||
if (readLen != len)
|
||||
{
|
||||
var lastPart = _buffer[firstRead..(len + 19)];
|
||||
await _ioStream.ReadExactlyAsync(lastPart, cancellationToken: token);
|
||||
}
|
||||
|
||||
await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: token);
|
||||
var message = _serializationToolkit.Deserialize<NetworkMessageHeader>(localSpan, _context);
|
||||
var message = meta.ToMessage(_buffer.Span);
|
||||
MessageReceived(message);
|
||||
}
|
||||
|
||||
@@ -196,17 +181,17 @@ namespace mROA.Implementation
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Send(NetworkMessageHeader message, CancellationToken token = default)
|
||||
private async Task Send(NetworkMessage message, CancellationToken token = default)
|
||||
{
|
||||
var bodySpan = _buffer[2..];
|
||||
var len = _serializationToolkit.Serialize(message, bodySpan.Span, _context);
|
||||
var header = BitConverter.GetBytes((ushort)len);
|
||||
header.CopyTo(_buffer);
|
||||
var sendingSpan = _buffer[..(len + 2)];
|
||||
var meta = message.ToMeta();
|
||||
MemoryMarshal.Write(_buffer.Span, ref meta);
|
||||
message.Data.CopyTo(_buffer.Span[19..]);
|
||||
var sendingSpan = _buffer[..(19 + meta.BodyLength)];
|
||||
await _ioStream.WriteAsync(sendingSpan, token);
|
||||
// _logger.LogTrace("SEND {0}", message.ToString());
|
||||
}
|
||||
|
||||
public async Task SendFromChannel(ChannelReader<NetworkMessageHeader> channel,
|
||||
public async Task SendFromChannel(ChannelReader<NetworkMessage> channel,
|
||||
CancellationToken token = default)
|
||||
{
|
||||
while (token.IsCancellationRequested == false && IsConnected)
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace mROA.Implementation
|
||||
{
|
||||
public class CollectableMethodRepository : IMethodRepository
|
||||
{
|
||||
private List<IMethodInvoker> _methods = new();
|
||||
private readonly List<IMethodInvoker> _methods = new();
|
||||
|
||||
public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers)
|
||||
{
|
||||
@@ -14,10 +14,7 @@ namespace mROA.Implementation
|
||||
|
||||
public IMethodInvoker GetMethod(int id)
|
||||
{
|
||||
if (id == -1)
|
||||
return MethodInvoker.Dispose;
|
||||
|
||||
return _methods[id];
|
||||
return id == -1 ? MethodInvoker.Dispose : _methods[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation.CommandExecution
|
||||
{
|
||||
public class AsyncCommandExecution : ICommandExecution
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public EMessageType MessageType => EMessageType.Unknown;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace mROA.Implementation.CommandExecution
|
||||
{
|
||||
public class ExceptionCommandExecution : ICommandExecution
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public RequestId Id { get; set; }
|
||||
public EMessageType MessageType => EMessageType.ExceptionCommandExecution;
|
||||
public string Exception { get; set; }
|
||||
|
||||
|
||||
@@ -1,19 +1,17 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
|
||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||
|
||||
namespace mROA.Implementation.CommandExecution
|
||||
{
|
||||
public struct FinalCommandExecution : ICommandExecution
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public RequestId Id { get; set; }
|
||||
public EMessageType MessageType => EMessageType.FinishedCommandExecution;
|
||||
}
|
||||
|
||||
public struct FinalCommandExecution<T> : ICommandExecution
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public RequestId Id { get; set; }
|
||||
public EMessageType MessageType => EMessageType.FinishedCommandExecution;
|
||||
public T? Result { get; set; }
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ using System;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
#pragma warning disable CS8618, CS9264
|
||||
public struct ComplexObjectIdentifier : IEquatable<ComplexObjectIdentifier>
|
||||
{
|
||||
public int ContextId;
|
||||
@@ -14,14 +13,9 @@ namespace mROA.Implementation
|
||||
OwnerId = ownerId;
|
||||
}
|
||||
|
||||
public static ComplexObjectIdentifier Singleton(int ownerId) => new() { ContextId = -1, OwnerId = ownerId };
|
||||
|
||||
public static ComplexObjectIdentifier Null = new ComplexObjectIdentifier { ContextId = -2, OwnerId = 0 };
|
||||
public static ComplexObjectIdentifier Null = new() { ContextId = -2, OwnerId = 0 };
|
||||
public static ComplexObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat };
|
||||
|
||||
public int ClientId => Math.Abs(OwnerId);
|
||||
public bool IsSererStored => OwnerId > 0;
|
||||
public bool IsClientStored => OwnerId < 0;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
||||
@@ -1,29 +1,23 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
|
||||
{
|
||||
private IServiceProvider _creationModules;
|
||||
private IConnectionHub _hub;
|
||||
private IContextualSerializationToolKit _serialization;
|
||||
public CreativeRepresentationModuleProducer(IServiceProvider creationModules, IConnectionHub hub, IContextualSerializationToolKit serialization)
|
||||
private readonly IConnectionHub _hub;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
|
||||
public CreativeRepresentationModuleProducer(IConnectionHub hub, IContextualSerializationToolKit serialization)
|
||||
{
|
||||
_creationModules = creationModules;
|
||||
_hub = hub;
|
||||
_serialization = serialization;
|
||||
}
|
||||
|
||||
|
||||
public IRepresentationModule Produce(int id)
|
||||
{
|
||||
if (_hub == null)
|
||||
throw new NullReferenceException("Interaction module is null");
|
||||
|
||||
var interaction = _hub.GetInteraction(id);
|
||||
|
||||
var produced = new RepresentationModule(interaction, _serialization);
|
||||
|
||||
var produced = new RepresentationModule(interaction, _serialization.Clone());
|
||||
|
||||
return produced;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public class DistributionOptions
|
||||
{
|
||||
public EDistributionType DistributionType { get; set; }
|
||||
}
|
||||
|
||||
public enum EDistributionType
|
||||
{
|
||||
Channeled,
|
||||
ExtractorFirst
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public enum EMessageType
|
||||
public enum EMessageType : byte
|
||||
{
|
||||
Unknown,
|
||||
FinishedCommandExecution,
|
||||
@@ -12,6 +12,6 @@ namespace mROA.Implementation
|
||||
ClientRecovery,
|
||||
ClientConnect,
|
||||
ClientDisconnect,
|
||||
UntrustedConnect,
|
||||
UntrustedConnect
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ namespace mROA.Implementation
|
||||
{
|
||||
public EndPointContext()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EndPointContext(IRealStoreInstanceRepository realRepository, IInstanceRepository remoteRepository)
|
||||
{
|
||||
RealRepository = realRepository;
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace mROA.Implementation
|
||||
public void Free(int index)
|
||||
{
|
||||
_freePlaces.AddFirst(index);
|
||||
_array[index] = default;
|
||||
_array[index] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
@@ -14,39 +14,36 @@ namespace mROA.Implementation.Frontend
|
||||
{
|
||||
private readonly IPEndPoint _serverEndPoint;
|
||||
private TcpClient _tcpClient = new();
|
||||
private IChannelInteractionModule _interactionModule;
|
||||
private IContextualSerializationToolKit _serialization;
|
||||
private ChannelInteractionModule.StreamExtractor? _currentExtractor;
|
||||
private readonly IChannelInteractionModule _interactionModule;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
private ChannelInteractionModule.StreamExtractor _currentExtractor;
|
||||
private CancellationTokenSource _rawExtractorCancellation;
|
||||
private IEndPointContext _context;
|
||||
private readonly IEndPointContext _context;
|
||||
|
||||
public NetworkFrontendBridge(IOptions<GatewayOptions> options, IEndPointContext context, IContextualSerializationToolKit serialization, IChannelInteractionModule interactionModule)
|
||||
public NetworkFrontendBridge(IOptions<GatewayOptions> options, IEndPointContext context,
|
||||
IContextualSerializationToolKit serialization, IChannelInteractionModule interactionModule)
|
||||
{
|
||||
_serverEndPoint = options.Value.Endpoint;
|
||||
_context = context;
|
||||
_serialization = serialization;
|
||||
_interactionModule = interactionModule;
|
||||
_rawExtractorCancellation = new CancellationTokenSource();
|
||||
_currentExtractor = new ChannelInteractionModule.StreamExtractor(Stream.Null);
|
||||
}
|
||||
|
||||
public async Task Connect()
|
||||
{
|
||||
if (_interactionModule is null)
|
||||
throw new Exception("Interaction module was not injected");
|
||||
if (_serialization == null)
|
||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
||||
|
||||
_tcpClient.Connect(_serverEndPoint);
|
||||
_tcpClient.NoDelay = true;
|
||||
PrepareExtractor();
|
||||
_interactionModule.IsConnected = () => _currentExtractor.IsConnected;
|
||||
_interactionModule.OnDisconnected += _ => { Reconnect(); };
|
||||
_interactionModule.OnDisconnected += _ => { Reconnect().ConfigureAwait(false); };
|
||||
|
||||
_interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect(), _context))
|
||||
_interactionModule.PostMessageAsync(new NetworkMessage(_serialization, new ClientConnect(), _context))
|
||||
.Wait();
|
||||
|
||||
_currentExtractor.SingleReceive();
|
||||
var idMessage = await _interactionModule.GetNextMessageReceiving(false);
|
||||
_ = _currentExtractor.SingleReceive().ConfigureAwait(false);
|
||||
var idMessage = await _interactionModule.GetNextMessageReceiving();
|
||||
|
||||
if (idMessage.MessageType != EMessageType.IdAssigning)
|
||||
{
|
||||
@@ -55,7 +52,7 @@ namespace mROA.Implementation.Frontend
|
||||
}
|
||||
|
||||
|
||||
Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||
_ = Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||
|
||||
var assignment = _serialization.Deserialize<IdAssignment>(idMessage.Data, _context);
|
||||
_interactionModule.ConnectionId = -assignment.Id;
|
||||
@@ -66,9 +63,9 @@ namespace mROA.Implementation.Frontend
|
||||
private void PrepareExtractor()
|
||||
{
|
||||
_currentExtractor =
|
||||
new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization, _context);
|
||||
new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream());
|
||||
|
||||
_ = _currentExtractor.SendFromChannel(_interactionModule!.TrustedPostChanel,
|
||||
_ = _currentExtractor.SendFromChannel(_interactionModule.TrustedPostChanel,
|
||||
_rawExtractorCancellation.Token);
|
||||
_currentExtractor.MessageReceived = message =>
|
||||
{
|
||||
@@ -86,7 +83,7 @@ namespace mROA.Implementation.Frontend
|
||||
|
||||
PrepareExtractor();
|
||||
|
||||
Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||
_ = Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||
|
||||
await _interactionModule.Restart(true);
|
||||
}
|
||||
@@ -98,7 +95,7 @@ namespace mROA.Implementation.Frontend
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
_ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientDisconnect(),
|
||||
_ = _interactionModule.PostMessageAsync(new NetworkMessage(_serialization, new ClientDisconnect(),
|
||||
_context));
|
||||
_interactionModule.Dispose();
|
||||
_tcpClient.Dispose();
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace mROA.Implementation.Frontend
|
||||
{
|
||||
public class RemoteException : Exception
|
||||
{
|
||||
public Guid CallRequestId;
|
||||
public RequestId CallRequestId;
|
||||
private readonly string _error;
|
||||
|
||||
public RemoteException(string error)
|
||||
|
||||
@@ -3,98 +3,90 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using mROA.Abstract;
|
||||
|
||||
// ReSharper disable MethodHasAsyncOverload
|
||||
|
||||
namespace mROA.Implementation.Frontend
|
||||
{
|
||||
public class RequestExtractor : IRequestExtractor
|
||||
{
|
||||
private IExecuteModule _executeModule;
|
||||
private readonly IExecuteModule _executeModule;
|
||||
|
||||
private IMethodRepository _methodRepository;
|
||||
private readonly IRepresentationModule _representationModule;
|
||||
private readonly IEndPointContext _context;
|
||||
|
||||
private IRepresentationModule _representationModule;
|
||||
private IContextualSerializationToolKit _serializationToolkit;
|
||||
private IEndPointContext _context;
|
||||
|
||||
public RequestExtractor(IExecuteModule executeModule, IMethodRepository methodRepository, IRepresentationModule representationModule, IContextualSerializationToolKit serializationToolkit, IEndPointContext context)
|
||||
public RequestExtractor(IExecuteModule executeModule, IRepresentationModule representationModule,
|
||||
IEndPointContext context)
|
||||
{
|
||||
_executeModule = executeModule;
|
||||
_methodRepository = methodRepository;
|
||||
_representationModule = representationModule;
|
||||
_serializationToolkit = serializationToolkit;
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task StartExtraction()
|
||||
{
|
||||
ThrowIfNotInjected();
|
||||
|
||||
var streamTokenSource = new CancellationTokenSource();
|
||||
|
||||
var query = _representationModule.GetStream(m =>
|
||||
m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest
|
||||
or EMessageType.EventRequest or EMessageType.ClientDisconnect, _context,
|
||||
var query = _representationModule.GetStream(Rule, _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,
|
||||
m => m.MessageType == EMessageType.ClientDisconnect ? typeof(ClientDisconnect) : null);
|
||||
Converters);
|
||||
|
||||
|
||||
await foreach (var command in query)
|
||||
{
|
||||
switch (command.originalType)
|
||||
{
|
||||
case EMessageType.CallRequest:
|
||||
HandleCallRequest((DefaultCallRequest)command.parced);
|
||||
break;
|
||||
case EMessageType.ClientDisconnect:
|
||||
return;
|
||||
case EMessageType.EventRequest:
|
||||
HandleEventRequest((DefaultCallRequest)command.parced);
|
||||
break;
|
||||
case EMessageType.CancelRequest:
|
||||
HandleCancelRequest((command.parced as CancelRequest)!);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
PushMessage(command.parced, command.originalType);
|
||||
}
|
||||
}
|
||||
|
||||
private void ThrowIfNotInjected()
|
||||
public void PushMessage(object parced, EMessageType originalType)
|
||||
{
|
||||
if (_serializationToolkit == null)
|
||||
throw new NullReferenceException("Serializing toolkit is null.");
|
||||
if (_executeModule == null)
|
||||
throw new NullReferenceException("Execute module is null.");
|
||||
if (_representationModule == null)
|
||||
throw new NullReferenceException("Representation module is null.");
|
||||
if (_methodRepository == null)
|
||||
throw new NullReferenceException("Method repository is null.");
|
||||
switch (originalType)
|
||||
{
|
||||
case EMessageType.CallRequest:
|
||||
HandleCallRequest((CallRequest)parced);
|
||||
break;
|
||||
case EMessageType.ClientDisconnect:
|
||||
return;
|
||||
case EMessageType.EventRequest:
|
||||
HandleEventRequest((CallRequest)parced);
|
||||
break;
|
||||
case EMessageType.CancelRequest:
|
||||
HandleCancelRequest((CancelRequest)parced);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
public Predicate<NetworkMessage> Rule { get; } = m =>
|
||||
m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest
|
||||
or EMessageType.EventRequest or EMessageType.ClientDisconnect;
|
||||
|
||||
public Func<NetworkMessage, Type?>[] Converters { get; } =
|
||||
{
|
||||
m => m.MessageType == EMessageType.CallRequest ? typeof(CallRequest) : null,
|
||||
m => m.MessageType == EMessageType.CancelRequest ? typeof(CancelRequest) : null,
|
||||
m => m.MessageType == EMessageType.EventRequest ? typeof(CallRequest) : null,
|
||||
m => m.MessageType == EMessageType.ClientDisconnect ? typeof(ClientDisconnect) : null
|
||||
};
|
||||
|
||||
private void HandleCancelRequest(CancelRequest req)
|
||||
{
|
||||
_executeModule.Execute(req, _context.RealRepository, _representationModule, _context);
|
||||
_executeModule.Cancel(req);
|
||||
}
|
||||
|
||||
private void HandleCallRequest(DefaultCallRequest request)
|
||||
private void HandleCallRequest(CallRequest request)
|
||||
{
|
||||
var result = _executeModule.Execute(request, _context.RealRepository, _representationModule, _context);
|
||||
|
||||
var resultType = result.MessageType;
|
||||
|
||||
if (resultType == EMessageType.Unknown)
|
||||
|
||||
if (result is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_representationModule.PostCallMessage(request.Id, resultType, result, _context);
|
||||
var resultType = result.MessageType;
|
||||
_representationModule.PostCallMessageAsync(request.Id, resultType, result, _context).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private void HandleEventRequest(DefaultCallRequest request)
|
||||
private void HandleEventRequest(CallRequest request)
|
||||
{
|
||||
_executeModule.Execute(request, _context.RemoteRepository, _representationModule, _context);
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation.Frontend
|
||||
{
|
||||
public class StaticOwnershipRepository : IOwnershipRepository
|
||||
{
|
||||
private readonly int _id;
|
||||
|
||||
public StaticOwnershipRepository(int id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public int GetOwnershipId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
public int GetHostOwnershipId()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ namespace mROA.Implementation.Frontend
|
||||
private readonly CancellationTokenSource _tokenSource = new();
|
||||
private readonly IEndPointContext _context;
|
||||
|
||||
public UdpUntrustedInteraction(IContextualSerializationToolKit serializationToolkit, IChannelInteractionModule channelInteractionModule, IEndPointContext context)
|
||||
public UdpUntrustedInteraction(IContextualSerializationToolKit serializationToolkit,
|
||||
IChannelInteractionModule channelInteractionModule, IEndPointContext context)
|
||||
{
|
||||
_serializationToolkit = serializationToolkit;
|
||||
_channelInteractionModule = channelInteractionModule;
|
||||
@@ -43,7 +44,7 @@ namespace mROA.Implementation.Frontend
|
||||
while (token.IsCancellationRequested == false)
|
||||
{
|
||||
var message = new Memory<byte>((await udpClient.ReceiveAsync()).Buffer);
|
||||
var parsed = _serializationToolkit.Deserialize<NetworkMessageHeader>(message, _context);
|
||||
var parsed = _serializationToolkit.Deserialize<NetworkMessage>(message, _context);
|
||||
|
||||
await writer.WriteAsync(parsed, token);
|
||||
}
|
||||
@@ -51,9 +52,9 @@ namespace mROA.Implementation.Frontend
|
||||
|
||||
private async Task Posting(UdpClient udpClient, CancellationToken token)
|
||||
{
|
||||
var initMessage = new NetworkMessageHeader
|
||||
var initMessage = new NetworkMessage
|
||||
{
|
||||
MessageType = EMessageType.UntrustedConnect, Id = Guid.NewGuid(),
|
||||
MessageType = EMessageType.UntrustedConnect, Id = RequestId.Generate(),
|
||||
Data = BitConverter.GetBytes(_channelInteractionModule.ConnectionId)
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace mROA.Implementation
|
||||
|
||||
public class ClientRecovery : INetworkMessage
|
||||
{
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
public ClientRecovery()
|
||||
{
|
||||
Id = 0;
|
||||
@@ -26,5 +27,6 @@ namespace mROA.Implementation
|
||||
public class ClientConnect : INetworkMessage
|
||||
{
|
||||
public EMessageType MessageType => EMessageType.ClientConnect;
|
||||
public string[]? Config { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public class NetworkMessage
|
||||
{
|
||||
private bool Equals(NetworkMessage 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;
|
||||
return obj.GetType() == GetType() && Equals((NetworkMessage)obj);
|
||||
}
|
||||
|
||||
public NetworkMessage()
|
||||
{
|
||||
Data = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public NetworkMessage(IContextualSerializationToolKit serializationToolkit,
|
||||
INetworkMessage networkMessage, IEndPointContext? context)
|
||||
{
|
||||
MessageType = networkMessage.MessageType;
|
||||
Data = serializationToolkit.Serialize(networkMessage, context);
|
||||
Id = RequestId.Generate();
|
||||
}
|
||||
|
||||
public RequestId Id { get; set; }
|
||||
|
||||
public EMessageType MessageType { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
public object Serialized { get; set; }
|
||||
public IEndPointContext Context { get; set; }
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {Id}:{MessageType} [{Data.Length}]";
|
||||
}
|
||||
|
||||
public NetworkMessageMeta ToMeta()
|
||||
{
|
||||
return new NetworkMessageMeta
|
||||
{
|
||||
BodyLength = (ushort)(Data == null ? 0 : Data.Length),
|
||||
Type = (byte)MessageType,
|
||||
Id = Id
|
||||
};
|
||||
}
|
||||
|
||||
public struct NetworkMessageMeta
|
||||
{
|
||||
public RequestId Id;
|
||||
public ushort BodyLength;
|
||||
public byte Type;
|
||||
|
||||
public NetworkMessage ToMessage(Span<byte> memory)
|
||||
{
|
||||
var data = memory[19..][..BodyLength];
|
||||
return new NetworkMessage
|
||||
{
|
||||
Data = data.ToArray(),
|
||||
Id = Id,
|
||||
MessageType = (EMessageType)Type
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public class NetworkMessageHeader
|
||||
{
|
||||
private 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 static readonly NetworkMessageHeader Null = new();
|
||||
|
||||
public NetworkMessageHeader()
|
||||
{
|
||||
Data = Array.Empty<byte>();
|
||||
}
|
||||
|
||||
public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit,
|
||||
INetworkMessage networkMessage, IEndPointContext? context)
|
||||
{
|
||||
MessageType = networkMessage.MessageType;
|
||||
Data = serializationToolkit.Serialize(networkMessage, context);
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public EMessageType MessageType { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $" {Id}:{MessageType} [{Data.Length}]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,13 @@ namespace mROA.Implementation
|
||||
{
|
||||
public class RemoteInstanceRepository : IInstanceRepository
|
||||
{
|
||||
private List<RemoteObjectBase> _producedProxys = new();
|
||||
private ICallIndexProvider _callIndexProvider;
|
||||
private readonly List<RemoteObjectBase> _producedProxies = new();
|
||||
private readonly ICallIndexProvider _callIndexProvider;
|
||||
|
||||
private IRepresentationModuleProducer _representationProducer;
|
||||
private readonly IRepresentationModuleProducer _representationProducer;
|
||||
|
||||
public RemoteInstanceRepository(ICallIndexProvider callIndexProvider, IRepresentationModuleProducer representationProducer)
|
||||
public RemoteInstanceRepository(ICallIndexProvider callIndexProvider,
|
||||
IRepresentationModuleProducer representationProducer)
|
||||
{
|
||||
_callIndexProvider = callIndexProvider;
|
||||
_representationProducer = representationProducer;
|
||||
@@ -31,11 +32,9 @@ namespace mROA.Implementation
|
||||
|
||||
public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context) where T : class
|
||||
{
|
||||
var index = _producedProxys.Find(i => i.Identifier.Equals(id));
|
||||
var index = _producedProxies.Find(i => i.Identifier.Equals(id));
|
||||
if (index is not null)
|
||||
return (T)(index as object);
|
||||
if (_representationProducer == null)
|
||||
throw new NullReferenceException("representation producer is not initialized");
|
||||
|
||||
if (!_callIndexProvider.Activators.TryGetValue(typeof(T), out var remoteType))
|
||||
throw new NotSupportedException();
|
||||
@@ -44,7 +43,7 @@ namespace mROA.Implementation
|
||||
var remote = remoteType(id.ContextId,
|
||||
representationModule, context, _callIndexProvider.GetIndices(typeof(T)));
|
||||
|
||||
_producedProxys.Add(remote!);
|
||||
_producedProxies.Add(remote!);
|
||||
|
||||
return (remote as T)!;
|
||||
}
|
||||
@@ -56,20 +55,15 @@ namespace mROA.Implementation
|
||||
|
||||
public object GetSingletonObject(Type type, IEndPointContext context)
|
||||
{
|
||||
if (_representationProducer == null)
|
||||
throw new NullReferenceException("representation producer is not initialized");
|
||||
|
||||
var representationModule =
|
||||
_representationProducer.Produce(context.OwnerId);
|
||||
|
||||
var instance = _callIndexProvider.Activators[type](-1, representationModule, context,
|
||||
_callIndexProvider.GetIndices(type))!;
|
||||
|
||||
var remoteObjectBase = instance;
|
||||
_producedProxies.Add(instance);
|
||||
|
||||
_producedProxys.Add(remoteObjectBase);
|
||||
|
||||
return _producedProxys.Last();
|
||||
return _producedProxies.Last();
|
||||
}
|
||||
|
||||
public int GetObjectIndex<T>(object o, IEndPointContext context)
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Threading.Tasks;
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation.CommandExecution;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
@@ -21,8 +20,7 @@ namespace mROA.Implementation
|
||||
{
|
||||
if (obj is null) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != GetType()) return false;
|
||||
return Equals((RemoteObjectBase)obj);
|
||||
return obj.GetType() == GetType() && Equals((RemoteObjectBase)obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
@@ -57,9 +55,9 @@ namespace mROA.Implementation
|
||||
protected async Task<T> GetResultAsync<T>(int methodId, object?[]? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new DefaultCallRequest
|
||||
var request = new CallRequest
|
||||
{
|
||||
Id = Guid.NewGuid(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
Id = RequestId.Generate(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
};
|
||||
|
||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context);
|
||||
@@ -102,9 +100,9 @@ namespace mROA.Implementation
|
||||
protected async Task CallAsync(int methodId, object?[]? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new DefaultCallRequest
|
||||
var request = new CallRequest
|
||||
{
|
||||
Id = Guid.NewGuid(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
Id = RequestId.Generate(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
};
|
||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context);
|
||||
|
||||
@@ -142,14 +140,16 @@ namespace mROA.Implementation
|
||||
return;
|
||||
case EMessageType.ExceptionCommandExecution:
|
||||
throw (responseRequest.Deserialized as ExceptionCommandExecution)!.GetException();
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task CallUntrustedAsync(int methodId, object?[]? parameters = null)
|
||||
{
|
||||
var request = new DefaultCallRequest
|
||||
var request = new CallRequest
|
||||
{
|
||||
Id = Guid.NewGuid(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
Id = RequestId.Generate(), CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||
};
|
||||
await _representationModule.PostCallMessageUntrustedAsync(request.Id, EMessageType.CallRequest, request,
|
||||
_context);
|
||||
|
||||
@@ -6,16 +6,16 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using mROA.Abstract;
|
||||
|
||||
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public class RepresentationModule : IRepresentationModule
|
||||
{
|
||||
private IChannelInteractionModule _interaction;
|
||||
private IContextualSerializationToolKit _serialization;
|
||||
private readonly IChannelInteractionModule _interaction;
|
||||
private readonly IContextualSerializationToolKit _serialization;
|
||||
|
||||
public RepresentationModule(IChannelInteractionModule interaction, IContextualSerializationToolKit serialization)
|
||||
public RepresentationModule(IChannelInteractionModule interaction,
|
||||
IContextualSerializationToolKit serialization)
|
||||
{
|
||||
_interaction = interaction;
|
||||
_serialization = serialization;
|
||||
@@ -28,8 +28,8 @@ namespace mROA.Implementation
|
||||
public IEndPointContext Context => _interaction.Context;
|
||||
|
||||
public async Task<(object? Deserialized, EMessageType MessageType)> GetSingle(
|
||||
Predicate<NetworkMessageHeader> rule, IEndPointContext? context,
|
||||
CancellationToken token = default, params Func<NetworkMessageHeader, Type?>[] converter)
|
||||
Predicate<NetworkMessage> rule, IEndPointContext? context,
|
||||
CancellationToken token = default, params Func<NetworkMessage, Type?>[] converter)
|
||||
{
|
||||
var writer = _interaction.ReceiveChanel.Writer;
|
||||
var reader = _interaction.ReceiveChanel.Reader;
|
||||
@@ -52,11 +52,11 @@ namespace mROA.Implementation
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(
|
||||
Predicate<NetworkMessageHeader> rule, IEndPointContext? context,
|
||||
Predicate<NetworkMessage> rule, IEndPointContext? context,
|
||||
[EnumeratorCancellation] CancellationToken token = default,
|
||||
params Func<NetworkMessageHeader, Type?>[] converter)
|
||||
params Func<NetworkMessage, Type?>[] converter)
|
||||
{
|
||||
var writer = _interaction?.ReceiveChanel.Writer;
|
||||
var writer = _interaction.ReceiveChanel.Writer;
|
||||
await foreach (var message in _interaction.ReceiveChanel.Reader.ReadAllAsync(token))
|
||||
{
|
||||
if (!rule(message))
|
||||
@@ -66,7 +66,7 @@ namespace mROA.Implementation
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < converter.Length; i++)
|
||||
for (var i = 0; i < converter.Length; i++)
|
||||
{
|
||||
var func = converter[i];
|
||||
if (func(message) is { } t)
|
||||
@@ -79,30 +79,25 @@ namespace mROA.Implementation
|
||||
}
|
||||
}
|
||||
|
||||
public async Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload,
|
||||
public async Task PostCallMessageAsync<T>(RequestId id, EMessageType eMessageType, T payload,
|
||||
IEndPointContext? context) where T : notnull
|
||||
{
|
||||
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, context);
|
||||
await _interaction.PostMessageAsync(new NetworkMessageHeader
|
||||
await _interaction.PostMessageAsync(new NetworkMessage
|
||||
{ Id = id, MessageType = eMessageType, Data = serialized });
|
||||
}
|
||||
|
||||
public void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
public void PostCallMessage<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||
where T : notnull
|
||||
{
|
||||
PostCallMessageAsync(id, eMessageType, payload, context).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
public async Task PostCallMessageUntrustedAsync<T>(Guid id, EMessageType eMessageType, T payload,
|
||||
public async Task PostCallMessageUntrustedAsync<T>(RequestId id, EMessageType eMessageType, T payload,
|
||||
IEndPointContext? context) where T : notnull
|
||||
{
|
||||
var serialized = _serialization.Serialize(payload, context);
|
||||
await _interaction.PostMessageUntrustedAsync(new NetworkMessageHeader
|
||||
await _interaction.PostMessageUntrustedAsync(new NetworkMessage
|
||||
{ Id = id, MessageType = eMessageType, Data = serialized });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ using System;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public sealed class RequestContext
|
||||
public struct RequestContext
|
||||
{
|
||||
public int OwnerId { get; }
|
||||
public Guid RequestId { get; }
|
||||
public RequestId RequestId { get; }
|
||||
|
||||
public RequestContext(Guid requestId, int ownerId)
|
||||
public RequestContext(RequestId requestId, int ownerId)
|
||||
{
|
||||
RequestId = requestId;
|
||||
OwnerId = ownerId;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public struct RequestId : IEquatable<RequestId>
|
||||
{
|
||||
private static Random _random = new();
|
||||
|
||||
public ulong P0;
|
||||
public ulong P1;
|
||||
|
||||
public static RequestId Generate()
|
||||
{
|
||||
var high = (ulong)(ushort)_random.Next() << 32 | (ulong)_random.Next();
|
||||
var low = (ulong)(ushort)_random.Next() << 32 | (ulong)_random.Next();
|
||||
return new RequestId { P0 = high, P1 = low };
|
||||
}
|
||||
|
||||
public RequestId(byte[] bytes)
|
||||
{
|
||||
P0 = BitConverter.ToUInt64(bytes);
|
||||
P1 = BitConverter.ToUInt64(bytes, 8);
|
||||
}
|
||||
|
||||
public bool Equals(RequestId other)
|
||||
{
|
||||
return P0 == other.P0 && P1 == other.P1;
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is RequestId other && Equals(other);
|
||||
}
|
||||
|
||||
public static bool operator ==(RequestId r1, RequestId r2)
|
||||
{
|
||||
return r1.Equals(r2);
|
||||
}
|
||||
|
||||
public static bool operator !=(RequestId r1, RequestId r2)
|
||||
{
|
||||
return !(r1 == r2);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{P0:X}{P1:X}";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(P0, P1);
|
||||
}
|
||||
|
||||
public byte[] ToByteArray()
|
||||
{
|
||||
var array = new byte[16];
|
||||
MemoryMarshal.Write(array, ref this);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,10 @@ using System.Text.Json.Serialization;
|
||||
using mROA.Abstract;
|
||||
using mROA.Implementation.Attributes;
|
||||
|
||||
// ReSharper disable UnusedMember.Global
|
||||
// #pragma warning disable CS8618, CS9264
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
public interface ISharedObjectShell
|
||||
{
|
||||
// ReSharper disable once UnusedMemberInSuper.Global
|
||||
IEndPointContext EndPointContext { get; set; }
|
||||
ComplexObjectIdentifier Identifier { get; set; }
|
||||
object UniversalValue { get; set; }
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using mROA.Abstract;
|
||||
using mROA.Abstract;
|
||||
|
||||
namespace mROA.Implementation
|
||||
{
|
||||
|
||||
@@ -9,11 +9,11 @@ namespace mROA
|
||||
{
|
||||
public static async ValueTask<int> ReadExactlyAsync(this Stream stream, byte[] buffer, int offset, int count)
|
||||
{
|
||||
return await stream.ReadAtLeastAsyncCore(buffer.AsMemory(offset, count), count, true, default);
|
||||
return await stream.ReadAtLeastAsyncCore(buffer.AsMemory(offset, count), count, true, CancellationToken.None);
|
||||
}
|
||||
|
||||
public static ValueTask<int> ReadExactlyAsync(this Stream stream, Memory<byte> buffer,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
return stream.ReadAtLeastAsyncCore(buffer, buffer.Length, true, cancellationToken);
|
||||
}
|
||||
@@ -28,13 +28,11 @@ namespace mROA
|
||||
int num;
|
||||
for (totalRead = 0; totalRead < minimumBytes; totalRead += num)
|
||||
{
|
||||
num = await stream.ReadAsync(buffer.Slice(totalRead), cancellationToken).ConfigureAwait(false);
|
||||
if (num == 0)
|
||||
{
|
||||
if (throwOnEndOfStream)
|
||||
throw new EndOfStreamException();
|
||||
return totalRead;
|
||||
}
|
||||
num = await stream.ReadAsync(buffer[totalRead..], cancellationToken).ConfigureAwait(false);
|
||||
if (num != 0) continue;
|
||||
if (throwOnEndOfStream)
|
||||
throw new EndOfStreamException();
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
return totalRead;
|
||||
|
||||
+8
-2
@@ -26,8 +26,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.7"/>
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="9.0.7"/>
|
||||
<PackageReference Include="System.Text.Json" Version="9.0.5"/>
|
||||
<PackageReference Include="System.Threading.Channels" Version="9.0.5"/>
|
||||
</ItemGroup>
|
||||
@@ -39,4 +39,10 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
|
||||
<HintPath>..\..\..\..\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.7\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user