@@ -8,7 +8,7 @@ namespace Example.Backend
|
|||||||
{
|
{
|
||||||
public class PagesList : RemoteObjectBase, IPagesList
|
public class PagesList : RemoteObjectBase, IPagesList
|
||||||
{
|
{
|
||||||
public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule)
|
public PagesList(int id, IRepresentationModule representationModule,IEndPointContext context) : base(id, representationModule, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,17 @@ namespace Example.Backend
|
|||||||
{
|
{
|
||||||
public string Name;
|
public string Name;
|
||||||
|
|
||||||
|
public async Task SomeoneIsApproaching(string humanName)
|
||||||
|
{
|
||||||
|
Console.WriteLine(humanName + " is approaching");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SetFingerPrint(int[] fingerPrint)
|
||||||
|
{
|
||||||
|
Console.WriteLine(fingerPrint.Length);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void OnPrintExternal(IPage p0, RequestContext ro)
|
public void OnPrintExternal(IPage p0, RequestContext ro)
|
||||||
{
|
{
|
||||||
OnPrint?.Invoke(p0, ro);
|
OnPrint?.Invoke(p0, ro);
|
||||||
|
|||||||
+13
-13
@@ -1,4 +1,5 @@
|
|||||||
using System.Linq;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Example.Backend;
|
using Example.Backend;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
@@ -7,7 +8,6 @@ using mROA.Codegen;
|
|||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.Backend;
|
using mROA.Implementation.Backend;
|
||||||
using mROA.Implementation.Bootstrap;
|
using mROA.Implementation.Bootstrap;
|
||||||
using mROA.Implementation.Frontend;
|
|
||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
@@ -19,21 +19,22 @@ class Program
|
|||||||
builder.Modules.Add(new BackendIdentityGenerator());
|
builder.Modules.Add(new BackendIdentityGenerator());
|
||||||
// builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
// builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
||||||
// builder.GetModule<IIdentityGenerator>()!);
|
// builder.GetModule<IIdentityGenerator>()!);
|
||||||
builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
var listening = new IPEndPoint(IPAddress.Loopback, 4567);
|
||||||
|
builder.UseNetworkGateway(listening, typeof(ChannelInteractionModule),
|
||||||
builder.GetModule<IIdentityGenerator>()!);
|
builder.GetModule<IIdentityGenerator>()!);
|
||||||
|
builder.Modules.Add(new UdpGateway(listening));
|
||||||
builder.Modules.Add(new ConnectionHub());
|
builder.Modules.Add(new ConnectionHub());
|
||||||
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
|
builder.Modules.Add(new HubRequestExtractor());
|
||||||
|
|
||||||
builder.UseBasicExecution();
|
builder.UseBasicExecution();
|
||||||
builder.Modules.Add(new CreativeRepresentationModuleProducer(
|
builder.Modules.Add(new CreativeRepresentationModuleProducer(
|
||||||
new IInjectableModule[] { builder.GetModule<ISerializationToolkit>()! },
|
new IInjectableModule[] { builder.GetModule<IContextualSerializationToolKit>()! },
|
||||||
typeof(RepresentationModule)));
|
typeof(RepresentationModule)));
|
||||||
builder.Modules.Add(new RemoteContextRepository());
|
builder.Modules.Add(new RemoteInstanceRepository());
|
||||||
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
|
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
|
||||||
builder.Modules.Add(new MultiClientContextRepository(i =>
|
builder.Modules.Add(new MultiClientInstanceRepository(i =>
|
||||||
{
|
{
|
||||||
var repo = new ContextRepository();
|
var repo = new InstanceRepository();
|
||||||
repo.FillSingletons(typeof(PrinterFactory).Assembly);
|
repo.FillSingletons(typeof(PrinterFactory).Assembly);
|
||||||
repo.Inject(builder.Modules.OfType<CreativeRepresentationModuleProducer>().First());
|
repo.Inject(builder.Modules.OfType<CreativeRepresentationModuleProducer>().First());
|
||||||
return repo;
|
return repo;
|
||||||
@@ -45,12 +46,11 @@ class Program
|
|||||||
builder.Build();
|
builder.Build();
|
||||||
new RemoteTypeBinder();
|
new RemoteTypeBinder();
|
||||||
|
|
||||||
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
|
|
||||||
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
|
||||||
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
|
|
||||||
|
|
||||||
|
_ = builder.GetModule<UdpGateway>()!.Start();
|
||||||
var gateway = builder.GetModule<IGatewayModule>();
|
var gateway = builder.GetModule<IGatewayModule>();
|
||||||
|
|
||||||
gateway.Run();
|
gateway.Run();
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,16 @@ namespace Example.Frontend
|
|||||||
{
|
{
|
||||||
public class ClientBasedPrinter : IPrinter
|
public class ClientBasedPrinter : IPrinter
|
||||||
{
|
{
|
||||||
|
public Task SomeoneIsApproaching(string humanName)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task SetFingerPrint(int[] fingerPrint)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void OnPrintExternal(IPage p0, RequestContext ro)
|
public void OnPrintExternal(IPage p0, RequestContext ro)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
+46
-32
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -15,17 +16,19 @@ using mROA.Implementation.Frontend;
|
|||||||
|
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static async Task Main(string[] args)
|
||||||
{
|
{
|
||||||
var builder = new FullMixBuilder();
|
var builder = new FullMixBuilder();
|
||||||
new RemoteTypeBinder();
|
new RemoteTypeBinder();
|
||||||
// builder.Modules.Add(new JsonSerializationToolkit());
|
|
||||||
builder.Modules.Add(new CborSerializationToolkit());
|
|
||||||
|
|
||||||
builder.Modules.Add(new RemoteContextRepository());
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
builder.Modules.Add(new NextGenerationInteractionModule());
|
builder.Modules.Add(new EndPointContext());
|
||||||
|
builder.Modules.Add(new RemoteInstanceRepository());
|
||||||
|
builder.Modules.Add(new ChannelInteractionModule());
|
||||||
|
builder.Modules.Add(new UdpUntrustedInteraction());
|
||||||
builder.Modules.Add(new RepresentationModule());
|
builder.Modules.Add(new RepresentationModule());
|
||||||
builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567)));
|
var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 4567);
|
||||||
|
builder.Modules.Add(new NetworkFrontendBridge(serverEndPoint));
|
||||||
builder.Modules.Add(new StaticRepresentationModuleProducer());
|
builder.Modules.Add(new StaticRepresentationModuleProducer());
|
||||||
builder.Modules.Add(new RequestExtractor());
|
builder.Modules.Add(new RequestExtractor());
|
||||||
builder.Modules.Add(new BasicExecutionModule());
|
builder.Modules.Add(new BasicExecutionModule());
|
||||||
@@ -35,24 +38,28 @@ class Program
|
|||||||
|
|
||||||
builder.Build();
|
builder.Build();
|
||||||
|
|
||||||
|
|
||||||
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
|
||||||
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
|
||||||
|
|
||||||
var frontendBridge = builder.GetModule<IFrontendBridge>()!;
|
var frontendBridge = builder.GetModule<IFrontendBridge>()!;
|
||||||
frontendBridge.Connect();
|
await frontendBridge.Connect();
|
||||||
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
||||||
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
_ = builder.GetModule<UdpUntrustedInteraction>().Start(serverEndPoint);
|
||||||
var context = builder.GetModule<RemoteContextRepository>();
|
Console.WriteLine(builder.GetModule<IEndPointContext>().HostId);
|
||||||
|
var context = builder.GetModule<RemoteInstanceRepository>();
|
||||||
|
|
||||||
var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory;
|
var factory =
|
||||||
|
context.GetSingletonObject<IPrinterFactory>(
|
||||||
|
builder.GetModule<IEndPointContext>());
|
||||||
|
|
||||||
using (var disposingPrinter = factory.Create("Test"))
|
using (var disposingPrinter = factory.Create("Test"))
|
||||||
{
|
{
|
||||||
|
disposingPrinter.SetFingerPrint(new[] { 1, 2, 3 }).ContinueWith(r =>
|
||||||
|
{
|
||||||
|
Console.WriteLine(r.Status);
|
||||||
|
});
|
||||||
|
|
||||||
DemoCheck.CreatingPrinter = true;
|
DemoCheck.CreatingPrinter = true;
|
||||||
disposingPrinter.OnPrint += (_, _) =>
|
disposingPrinter.OnPrint += (_, _) =>
|
||||||
{
|
{
|
||||||
Console.WriteLine("New page creater. Called from event!!!");
|
Console.WriteLine("New page created. Called from event!!!");
|
||||||
DemoCheck.EventCallback = true;
|
DemoCheck.EventCallback = true;
|
||||||
};
|
};
|
||||||
Console.WriteLine("Printer created");
|
Console.WriteLine("Printer created");
|
||||||
@@ -65,7 +72,11 @@ class Program
|
|||||||
|
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
|
|
||||||
|
disposingPrinter.SomeoneIsApproaching("Mikhail");
|
||||||
|
Console.WriteLine("Approaching detected");
|
||||||
|
|
||||||
factory.Register(new ClientBasedPrinter());
|
factory.Register(new ClientBasedPrinter());
|
||||||
|
factory.Register(disposingPrinter);
|
||||||
DemoCheck.ClientBasedImplementation = true;
|
DemoCheck.ClientBasedImplementation = true;
|
||||||
Console.WriteLine("Registered printer");
|
Console.WriteLine("Registered printer");
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
@@ -80,10 +91,9 @@ class Program
|
|||||||
var names = factory.CollectAllNames();
|
var names = factory.CollectAllNames();
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
|
|
||||||
Console.WriteLine(string.Join(", ", names));
|
Console.WriteLine("Names: " + string.Join(", ", names));
|
||||||
|
|
||||||
var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter()
|
var page = await disposingPrinter.Print("Test Page", false, default, CancellationToken.None);
|
||||||
.GetResult();
|
|
||||||
Console.WriteLine("Page printed");
|
Console.WriteLine("Page printed");
|
||||||
DemoCheck.TaskExecution = true;
|
DemoCheck.TaskExecution = true;
|
||||||
Console.WriteLine(page.ToString());
|
Console.WriteLine(page.ToString());
|
||||||
@@ -101,10 +111,11 @@ class Program
|
|||||||
|
|
||||||
Console.WriteLine("Dispose printer");
|
Console.WriteLine("Dispose printer");
|
||||||
}
|
}
|
||||||
|
|
||||||
DemoCheck.Dispose = true;
|
DemoCheck.Dispose = true;
|
||||||
|
|
||||||
|
|
||||||
var loadSingleton = context.GetSingleObject(typeof(ILoadTest), 0) as ILoadTest;
|
var loadSingleton = context.GetSingletonObject<ILoadTest>(builder.GetModule<IEndPointContext>());
|
||||||
|
|
||||||
|
|
||||||
var cts = new CancellationTokenSource();
|
var cts = new CancellationTokenSource();
|
||||||
@@ -116,22 +127,25 @@ class Program
|
|||||||
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
|
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
|
||||||
DemoCheck.TaskCancelation = true;
|
DemoCheck.TaskCancelation = true;
|
||||||
|
|
||||||
|
const int iterations = 10000;
|
||||||
|
var timer = Stopwatch.StartNew();
|
||||||
|
var x = 0;
|
||||||
|
for (int i = 0; i < iterations; i++)
|
||||||
|
{
|
||||||
|
x = loadSingleton.Next(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.Stop();
|
||||||
|
Console.WriteLine("X is {0}", x);
|
||||||
|
Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
||||||
|
Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
||||||
|
|
||||||
frontendBridge.Disconnect();
|
frontendBridge.Disconnect();
|
||||||
|
|
||||||
DemoCheck.Show();
|
DemoCheck.Show();
|
||||||
Console.ReadKey();
|
Console.ReadKey();
|
||||||
//
|
|
||||||
// const int iterations = 10000;
|
|
||||||
// var timer = Stopwatch.StartNew();
|
|
||||||
// var x = 0;
|
|
||||||
// for (int i = 0; i < iterations; i++)
|
|
||||||
// {
|
|
||||||
// x = loadSingleton.Next(x);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// timer.Stop();
|
|
||||||
// Console.WriteLine("X is {0}", x);
|
|
||||||
// Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
|
||||||
// Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,5 +13,8 @@ namespace Example.Shared
|
|||||||
string GetName();
|
string GetName();
|
||||||
Task<IPage> Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken);
|
Task<IPage> Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken);
|
||||||
event Action<IPage, RequestContext> OnPrint;
|
event Action<IPage, RequestContext> OnPrint;
|
||||||
|
[Untrusted]
|
||||||
|
Task SomeoneIsApproaching(string humanName);
|
||||||
|
Task SetFingerPrint(int[] fingerPrint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,13 +213,10 @@ namespace mROA.Cbor
|
|||||||
|
|
||||||
if (obj is IShared)
|
if (obj is IShared)
|
||||||
{
|
{
|
||||||
var generic = obj.GetType().GetInterfaces().FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i));
|
var sharedShell = typeof(SharedObjectShellShell<object>);
|
||||||
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(generic);
|
|
||||||
var so =
|
var so =
|
||||||
Activator.CreateInstance(sharedShell, obj) as
|
Activator.CreateInstance(sharedShell, obj, context) as
|
||||||
ISharedObjectShell;
|
ISharedObjectShell;
|
||||||
if (context != null)
|
|
||||||
so.EndPointContext = context;
|
|
||||||
|
|
||||||
writer.WriteStartArray(1);
|
writer.WriteStartArray(1);
|
||||||
writer.WriteUInt64(so.Identifier.Flat);
|
writer.WriteUInt64(so.Identifier.Flat);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
@@ -34,6 +36,19 @@ namespace mROA.Cbor
|
|||||||
return so.UniversalValue;
|
return so.UniversalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type is { IsArray: true })
|
||||||
|
{
|
||||||
|
var elementType = type.GetElementType();
|
||||||
|
var array = Array.CreateInstance(elementType, _properties.Count);
|
||||||
|
Array.Copy(_properties.Select(i => Convert.ChangeType(i,elementType)).ToArray(), array, _properties.Count);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (typeof(IList).IsAssignableFrom(type))
|
||||||
|
return Convert.ChangeType(_properties.Select(i => Convert.ChangeType(i, type.GetElementType())).ToList(), type);
|
||||||
|
|
||||||
var instance = Activator.CreateInstance(type);
|
var instance = Activator.CreateInstance(type);
|
||||||
if (instance == null)
|
if (instance == null)
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
|
<Version>2.0.2</Version>
|
||||||
|
<LangVersion>9</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace mROA.Codegen
|
|||||||
new mROA.Implementation.AsyncMethodInvoker
|
new mROA.Implementation.AsyncMethodInvoker
|
||||||
{
|
{
|
||||||
IsVoid = <!L isVoid>,
|
IsVoid = <!L isVoid>,
|
||||||
|
IsTrusted = <!L isTrusted>,
|
||||||
ReturnType = typeof(<!L returnType>),
|
ReturnType = typeof(<!L returnType>),
|
||||||
ParameterTypes = new Type[] { <!L parametersType> },
|
ParameterTypes = new Type[] { <!L parametersType> },
|
||||||
SuitableType = typeof(<!L suitableType>),
|
SuitableType = typeof(<!L suitableType>),
|
||||||
@@ -26,6 +27,7 @@ namespace mROA.Codegen
|
|||||||
new mROA.Implementation.MethodInvoker
|
new mROA.Implementation.MethodInvoker
|
||||||
{
|
{
|
||||||
IsVoid = <!L isVoid>,
|
IsVoid = <!L isVoid>,
|
||||||
|
IsTrusted = <!L isTrusted>,
|
||||||
ReturnType = typeof(<!L returnType>),
|
ReturnType = typeof(<!L returnType>),
|
||||||
ParameterTypes = new Type[] { <!L parametersType> },
|
ParameterTypes = new Type[] { <!L parametersType> },
|
||||||
SuitableType = typeof(<!L suitableType>),
|
SuitableType = typeof(<!L suitableType>),
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ namespace <!L namespaceName>
|
|||||||
partial class <!L className>
|
partial class <!L className>
|
||||||
: RemoteObjectBase, <!L originalName>
|
: RemoteObjectBase, <!L originalName>
|
||||||
{
|
{
|
||||||
public <!L className>(int id, IRepresentationModule representationModule)
|
public <!L className>(int id, IRepresentationModule representationModule, IEndPointContext context)
|
||||||
: base(id, representationModule)
|
: base(id, representationModule, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ namespace mROA.Codegen
|
|||||||
public sealed class RemoteTypeBinder
|
public sealed class RemoteTypeBinder
|
||||||
{
|
{
|
||||||
static RemoteTypeBinder(){
|
static RemoteTypeBinder(){
|
||||||
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {
|
RemoteInstanceRepository.RemoteTypes = new Dictionary<Type, Type> {
|
||||||
<!I remoteTypePair r sep typesSep><!D typesSep>,
|
<!I remoteTypePair r sep typesSep><!D typesSep>,
|
||||||
<!D>
|
<!D>
|
||||||
};
|
};
|
||||||
ContextRepository.EventBinders = new object[] {
|
InstanceRepository.EventBinders = new object[] {
|
||||||
<!I eventBinder r sep typesSep>
|
<!I eventBinder r sep typesSep>
|
||||||
<!T objectBinderTemplate>
|
<!T objectBinderTemplate>
|
||||||
new EventBinder<<!L type>>
|
new EventBinder<<!L type>>
|
||||||
@@ -39,7 +39,7 @@ namespace mROA.Codegen
|
|||||||
Parameters = new object[] { <!L transferParameters> }
|
Parameters = new object[] { <!L transferParameters> }
|
||||||
};
|
};
|
||||||
|
|
||||||
module.PostCallMessageAsync(request.Id, EMessageType.EventRequest, request);
|
module.PostCallMessageAsync(request.Id, EMessageType.EventRequest, request, context);
|
||||||
};
|
};
|
||||||
<!T>
|
<!T>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
|
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||||
<Version>2.0.1</Version>
|
<Version>2.0.3</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -291,23 +291,38 @@ namespace mROA.Codegen
|
|||||||
$"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
|
$"{method.ReturnType.ToUnityString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
|
||||||
|
|
||||||
|
|
||||||
|
var isUntrusted = method.GetAttributes().Any(i => i.AttributeClass.Name == "UntrustedAttribute");
|
||||||
|
|
||||||
var prefix = isAsync ? "await " : "";
|
var prefix = isAsync ? "await " : "";
|
||||||
var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : "";
|
var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : "";
|
||||||
var parameterLink = isParametrized
|
var parameterLink = isParametrized
|
||||||
? ", new System.Object[] { " + string.Join(", ", parameters.Select(i => i.Name)) + " }"
|
? ", new System.Object[] { " + string.Join(", ", parameters.Select(i => i.Name)) + " }"
|
||||||
: string.Empty;
|
: string.Empty;
|
||||||
var tokenInsert = isAsync && method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is
|
|
||||||
{ } tokenSymbol
|
|
||||||
? ", cancellationToken : " + tokenSymbol.Name
|
|
||||||
: string.Empty;
|
|
||||||
var caller = isVoid
|
|
||||||
? $"CallAsync({index}{parameterLink}{tokenInsert})"
|
|
||||||
: isAsync
|
|
||||||
? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink}{tokenInsert})"
|
|
||||||
: $"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink}{tokenInsert})";
|
|
||||||
|
|
||||||
if (!isVoid)
|
string caller;
|
||||||
prefix = "return " + prefix;
|
|
||||||
|
if (isUntrusted)
|
||||||
|
{
|
||||||
|
caller = $"CallUntrustedAsync({index}{parameterLink})";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var tokenInsert = isAsync &&
|
||||||
|
method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is
|
||||||
|
{ } tokenSymbol
|
||||||
|
? ", cancellationToken : " + tokenSymbol.Name
|
||||||
|
: string.Empty;
|
||||||
|
|
||||||
|
caller = isVoid
|
||||||
|
? $"CallAsync({index}{parameterLink}{tokenInsert})"
|
||||||
|
: isAsync
|
||||||
|
? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink}{tokenInsert})"
|
||||||
|
: $"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink}{tokenInsert})";
|
||||||
|
|
||||||
|
if (!isVoid)
|
||||||
|
prefix = "return " + prefix;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";");
|
sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";");
|
||||||
|
|
||||||
@@ -365,6 +380,7 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
||||||
|
invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower());
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -375,6 +391,7 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
||||||
|
invokerTemplate.AddDefine("isTrusted", (!isUntrusted).ToString().ToLower());
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,9 +411,11 @@ namespace mROA.Codegen
|
|||||||
var parametersDeclaration = string.Join(", ",
|
var parametersDeclaration = string.Join(", ",
|
||||||
JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i)));
|
JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i)));
|
||||||
|
|
||||||
|
|
||||||
|
int pi = 0;
|
||||||
var transferParameters =
|
var transferParameters =
|
||||||
JoinWithComa(parameters.Where(i => !ParameterFilterForType(i))
|
JoinWithComa(parameters.Select(i => (i, pi++)).Where(i => !ParameterFilterForType(i.i))
|
||||||
.Select(i => "p" + parameters.IndexOf(i)));
|
.Select(i => "p" + i.Item2));
|
||||||
|
|
||||||
var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext");
|
var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext");
|
||||||
if (requestIndex != -1)
|
if (requestIndex != -1)
|
||||||
@@ -423,15 +442,16 @@ namespace mROA.Codegen
|
|||||||
{
|
{
|
||||||
var level = "\t\t\t";
|
var level = "\t\t\t";
|
||||||
|
|
||||||
var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments;
|
int pi = 0;
|
||||||
var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList();
|
var parameters = ((INamedTypeSymbol)eventSymbol.Type).TypeArguments.Select(i => (i, pi++)).ToImmutableArray();
|
||||||
|
var parsingParameters = parameters.RemoveAll(i => ParameterFilterForType(i.i)).ToList();
|
||||||
var parameterTypes = string.Join(", ",
|
var parameterTypes = string.Join(", ",
|
||||||
$"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToUnityString()})"))}");
|
$"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.i.ToUnityString()})"))}");
|
||||||
|
|
||||||
var parametersInsertList = new List<string>();
|
var parametersInsertList = new List<string>();
|
||||||
|
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
switch (parameter.Name)
|
switch (parameter.i.Name)
|
||||||
{
|
{
|
||||||
case "CancellationToken":
|
case "CancellationToken":
|
||||||
parametersInsertList.Add("(CancellationToken)special[1]");
|
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||||
@@ -440,8 +460,8 @@ namespace mROA.Codegen
|
|||||||
parametersInsertList.Add("special[0] as RequestContext");
|
parametersInsertList.Add("special[0] as RequestContext");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
parametersInsertList.Add(Caster(parameter,
|
parametersInsertList.Add(Caster(parameter.i,
|
||||||
$"parameters[{parameters.IndexOf(parameter)}]"));
|
$"parameters[{parameter.Item2}]"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +479,7 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
invokerTemplate.AddDefine("parametersType", parameterTypes);
|
||||||
invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterface.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
invokerTemplate.AddDefine("funcInvoking", funcInvoking);
|
||||||
|
invokerTemplate.AddDefine("isTrusted", "true");
|
||||||
var backend = invokerTemplate.Compile();
|
var backend = invokerTemplate.Compile();
|
||||||
_methodRepoTemplate.Insert("invoker", backend);
|
_methodRepoTemplate.Insert("invoker", backend);
|
||||||
|
|
||||||
@@ -482,8 +503,8 @@ namespace mROA.Codegen
|
|||||||
var parameterTypes = string.Join(", ",
|
var parameterTypes = string.Join(", ",
|
||||||
$"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}");
|
$"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToUnityString() + ")"))}");
|
||||||
var parameterInserts = string.Join(", ",
|
var parameterInserts = string.Join(", ",
|
||||||
method.Parameters.Select(
|
method.Parameters.Select(p =>
|
||||||
p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
|
Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
|
||||||
|
|
||||||
var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
|
var invokerTemplate = (TemplateDocument)_methodInvokerOriginal.Clone();
|
||||||
invokerTemplate.AddDefine("isVoid", "false");
|
invokerTemplate.AddDefine("isVoid", "false");
|
||||||
@@ -492,6 +513,8 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking",
|
invokerTemplate.AddDefine("funcInvoking",
|
||||||
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]");
|
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]");
|
||||||
|
invokerTemplate.AddDefine("isTrusted", "true");
|
||||||
|
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -502,6 +525,8 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking",
|
invokerTemplate.AddDefine("funcInvoking",
|
||||||
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}");
|
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}");
|
||||||
|
invokerTemplate.AddDefine("isTrusted", "true");
|
||||||
|
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -532,6 +557,8 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking",
|
invokerTemplate.AddDefine("funcInvoking",
|
||||||
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}");
|
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}");
|
||||||
|
invokerTemplate.AddDefine("isTrusted", "true");
|
||||||
|
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -545,6 +572,8 @@ namespace mROA.Codegen
|
|||||||
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
invokerTemplate.AddDefine("suitableType", baseInterace.ToUnityString());
|
||||||
invokerTemplate.AddDefine("funcInvoking",
|
invokerTemplate.AddDefine("funcInvoking",
|
||||||
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}");
|
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}");
|
||||||
|
invokerTemplate.AddDefine("isTrusted", "true");
|
||||||
|
|
||||||
backend = invokerTemplate.Compile();
|
backend = invokerTemplate.Compile();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,7 +641,6 @@ namespace mROA.Codegen
|
|||||||
return parts.ToUnityString();
|
return parts.ToUnityString();
|
||||||
|
|
||||||
return type.ToDisplayString();
|
return type.ToDisplayString();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ToUnityString(this IParameterSymbol parameter)
|
public static string ToUnityString(this IParameterSymbol parameter)
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using mROA.Cbor;
|
|
||||||
|
|
||||||
namespace mROA.Test;
|
|
||||||
|
|
||||||
public class CborTest
|
|
||||||
{
|
|
||||||
private ComplexTestObject _complexTestObject;
|
|
||||||
private IContextualSerializationToolKit _serializationToolKit;
|
|
||||||
private BasicCollectionElement _basicCollectionElement;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_basicCollectionElement = new() { A = 567565, B = "test text", C = 2.781f };
|
|
||||||
|
|
||||||
_complexTestObject = new ComplexTestObject
|
|
||||||
{
|
|
||||||
IntValue = 123,
|
|
||||||
DoubleValue = 3.14159,
|
|
||||||
StringValue = "abc",
|
|
||||||
EnumValue = TestEnum.X,
|
|
||||||
CollectionElements =
|
|
||||||
[
|
|
||||||
_basicCollectionElement,
|
|
||||||
new BasicCollectionElement { A = 8_000_000, B = "Fi number", C = 1.618f }
|
|
||||||
],
|
|
||||||
IntArray = [1, 4, 8, 16, 87]
|
|
||||||
};
|
|
||||||
_serializationToolKit = new CborSerializationToolkit();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void BasicOnly()
|
|
||||||
{
|
|
||||||
var value = 123;
|
|
||||||
var data = _serializationToolKit.Serialize(value, null);
|
|
||||||
|
|
||||||
var deserialize = _serializationToolKit.Deserialize<int>(data, null);
|
|
||||||
Assert.That(value, Is.EqualTo(deserialize));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ComplexFlat()
|
|
||||||
{
|
|
||||||
var value = _basicCollectionElement;
|
|
||||||
var data = _serializationToolKit.Serialize(value, null);
|
|
||||||
var deserialize = _serializationToolKit.Deserialize<BasicCollectionElement>(data, null);
|
|
||||||
Assert.That(value, Is.EqualTo(deserialize));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ComplexFull()
|
|
||||||
{
|
|
||||||
var value = _complexTestObject;
|
|
||||||
var data = _serializationToolKit.Serialize(value, null);
|
|
||||||
var deserialize = _serializationToolKit.Deserialize<ComplexTestObject>(data, null);
|
|
||||||
Assert.That(value, Is.EqualTo(deserialize));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SharedObject()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class ComplexTestObject
|
|
||||||
{
|
|
||||||
public int IntValue { get; set; }
|
|
||||||
public double DoubleValue { get; set; }
|
|
||||||
public string StringValue { get; set; }
|
|
||||||
public TestEnum EnumValue { get; set; }
|
|
||||||
public int[] IntArray { get; set; }
|
|
||||||
public List<BasicCollectionElement> CollectionElements { get; set; }
|
|
||||||
|
|
||||||
protected bool Equals(ComplexTestObject other)
|
|
||||||
{
|
|
||||||
return IntValue == other.IntValue && DoubleValue.Equals(other.DoubleValue) && StringValue == other.StringValue && IntArray.SequenceEqual(other.IntArray) && CollectionElements.SequenceEqual(other.CollectionElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (obj is null) return false;
|
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj.GetType() != GetType()) return false;
|
|
||||||
return Equals((ComplexTestObject)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(IntValue, DoubleValue, StringValue, IntArray, CollectionElements);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BasicCollectionElement
|
|
||||||
{
|
|
||||||
public int A { get; set; }
|
|
||||||
public string B { get; set; }
|
|
||||||
public float C { get; set; }
|
|
||||||
|
|
||||||
protected bool Equals(BasicCollectionElement other)
|
|
||||||
{
|
|
||||||
return A == other.A && B == other.B && C.Equals(other.C);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (obj is null) return false;
|
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj.GetType() != GetType()) return false;
|
|
||||||
return Equals((BasicCollectionElement)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return HashCode.Combine(A, B, C);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum TestEnum
|
|
||||||
{
|
|
||||||
X = -5, Y, Z
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
// using System.Net;
|
|
||||||
// using System.Net.Sockets;
|
|
||||||
// using System.Reflection;
|
|
||||||
// using mROA.Abstract;
|
|
||||||
// using mROA.Codegen;
|
|
||||||
// using Example.Shared;
|
|
||||||
// using mROA.Implementation;
|
|
||||||
//
|
|
||||||
// namespace mROA.Test;
|
|
||||||
//
|
|
||||||
// public class FrontendFinalTest
|
|
||||||
// {
|
|
||||||
// private StreamBasedInteractionModule _interactionModule;
|
|
||||||
// private StreamBasedFrontendInteractionModule _frontendInteractionModule;
|
|
||||||
// private JsonFrontendSerialisationModule _frontendSerialisationModule;
|
|
||||||
// private ISerialisationModule _serialisationModule;
|
|
||||||
// private IExecuteModule _executeModule;
|
|
||||||
// private IMethodRepository _methodRepository;
|
|
||||||
// private IContextRepository _contextRepository;
|
|
||||||
// bool isTestNotFinished = true;
|
|
||||||
// private IContextRepository _frontendContextRepository;
|
|
||||||
//
|
|
||||||
// [SetUp]
|
|
||||||
// public void Setup()
|
|
||||||
// {
|
|
||||||
// _methodRepository = new CoCodegenMethodRepository();
|
|
||||||
// var repo2 = new ContextRepository();
|
|
||||||
// repo2.FillSingletons(typeof(ITestController).Assembly);
|
|
||||||
// _contextRepository = repo2;
|
|
||||||
//
|
|
||||||
// _interactionModule = new StreamBasedInteractionModule();
|
|
||||||
//
|
|
||||||
// _serialisationModule = new JsonSerialisationModule();
|
|
||||||
//
|
|
||||||
// _executeModule = new BasicExecutionModule();
|
|
||||||
//
|
|
||||||
// IInjectableModule[] backendModules =
|
|
||||||
// [_methodRepository, _contextRepository, _interactionModule, _serialisationModule, _executeModule];
|
|
||||||
//
|
|
||||||
// foreach (var backendModule in backendModules)
|
|
||||||
// foreach (var injection in backendModules)
|
|
||||||
// backendModule.Inject(injection);
|
|
||||||
//
|
|
||||||
// _frontendInteractionModule = new StreamBasedFrontendInteractionModule();
|
|
||||||
// _frontendSerialisationModule = new JsonFrontendSerialisationModule();
|
|
||||||
// _frontendContextRepository = new FrontendContextRepository();
|
|
||||||
//
|
|
||||||
// IInjectableModule[] frontendModules =
|
|
||||||
// [_frontendInteractionModule, _frontendSerialisationModule, _frontendContextRepository];
|
|
||||||
//
|
|
||||||
// foreach (var backendModule in frontendModules)
|
|
||||||
// foreach (var injection in frontendModules)
|
|
||||||
// backendModule.Inject(injection);
|
|
||||||
//
|
|
||||||
// Task.Run(() =>
|
|
||||||
// {
|
|
||||||
// TcpListener listener = new TcpListener(IPAddress.Loopback, 4567);
|
|
||||||
// listener.Start();
|
|
||||||
//
|
|
||||||
// var stream = listener.AcceptTcpClient().GetStream();
|
|
||||||
//
|
|
||||||
// Console.WriteLine("Client connected");
|
|
||||||
//
|
|
||||||
// _interactionModule.RegisterSourse(stream);
|
|
||||||
//
|
|
||||||
// while (isTestNotFinished) ;
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// var tcpClient = new TcpClient();
|
|
||||||
// tcpClient.Connect(IPAddress.Loopback, 4567);
|
|
||||||
// _frontendInteractionModule.ServerStream = tcpClient.GetStream();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void CallTest()
|
|
||||||
// {
|
|
||||||
// var singleton = _frontendContextRepository.GetSingleObject(typeof(ITestController)) as ITestController;
|
|
||||||
//
|
|
||||||
// var x = singleton.B();
|
|
||||||
// Console.WriteLine(x);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void TransmittionTest()
|
|
||||||
// {
|
|
||||||
// var singleton = _frontendContextRepository.GetSingleObject(typeof(ITestController)) as ITestController;
|
|
||||||
//
|
|
||||||
// var next = singleton.SharedObjectTransmitionTest().Value;
|
|
||||||
// var parameter = singleton.GetTestParameter().Value;
|
|
||||||
// var x = next.Parametrized(new TestParameter { A = 100, LinkedObject = new(parameter!) });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Test;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
public class Identifier
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestParse()
|
||||||
|
{
|
||||||
|
var id = new ComplexObjectIdentifier(-1, -1);
|
||||||
|
var flat = id.Flat;
|
||||||
|
var next = new ComplexObjectIdentifier { Flat = flat };
|
||||||
|
if (id.Equals(next))
|
||||||
|
{
|
||||||
|
Assert.Pass();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Sockets;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using mROA.Implementation;
|
|
||||||
|
|
||||||
namespace mROA.Test
|
|
||||||
{
|
|
||||||
public class NextGenTest
|
|
||||||
{
|
|
||||||
private TcpListener _listener;
|
|
||||||
private NextGenerationInteractionModule _interactionModuleA;
|
|
||||||
private NextGenerationInteractionModule _interactionModuleB;
|
|
||||||
private Guid[] guids = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_listener = new TcpListener(IPAddress.Loopback, 4567);
|
|
||||||
_interactionModuleA = new NextGenerationInteractionModule();
|
|
||||||
_interactionModuleA.Inject(new JsonSerializationToolkit());
|
|
||||||
_interactionModuleB = new NextGenerationInteractionModule();
|
|
||||||
_interactionModuleB.Inject(new JsonSerializationToolkit());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void MultithreadedTest()
|
|
||||||
{
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
_listener.Start();
|
|
||||||
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
|
|
||||||
|
|
||||||
foreach (var guid in guids)
|
|
||||||
{
|
|
||||||
_interactionModuleB.PostMessageAsync(new NetworkMessageHeader { Id = guid, Data = "Hello user"u8.ToArray() });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var client = new TcpClient();
|
|
||||||
client.Connect(IPAddress.Loopback, 4567);
|
|
||||||
_interactionModuleA.BaseStream = client.GetStream();
|
|
||||||
|
|
||||||
var tasks = guids.Select(ReadStream);
|
|
||||||
|
|
||||||
Task.WaitAll(tasks.ToArray());
|
|
||||||
Assert.Pass();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ReadStream(Guid current)
|
|
||||||
{
|
|
||||||
var msg = await _interactionModuleA.GetNextMessageReceiving();
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
|
|
||||||
while (msg.Id != current)
|
|
||||||
{
|
|
||||||
msg = await _interactionModuleA.GetNextMessageReceiving();
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine($"{Environment.CurrentManagedThreadId} Good message received");
|
|
||||||
}
|
|
||||||
|
|
||||||
[TearDown]
|
|
||||||
public void TearDown()
|
|
||||||
{
|
|
||||||
_listener.Stop();
|
|
||||||
_listener.Dispose();
|
|
||||||
_interactionModuleA.Dispose();
|
|
||||||
_interactionModuleB.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
// using System.Net;
|
|
||||||
// using System.Net.Sockets;
|
|
||||||
// using System.Text.Json;
|
|
||||||
// using mROA.Implementation;
|
|
||||||
//
|
|
||||||
// namespace mROA.Test;
|
|
||||||
//
|
|
||||||
// public class StreamTest
|
|
||||||
// {
|
|
||||||
// private StreamBasedInteractionModule _interactionModule;
|
|
||||||
// private StreamBasedFrontendInteractionModule _frontendInteractionModule;
|
|
||||||
// private JsonFrontendSerialisationModule _frontendSerialisationModule;
|
|
||||||
// private ISerialisationModule _serialisationModule;
|
|
||||||
// private IExecuteModule _executeModule;
|
|
||||||
// bool isTestNotFinished = true;
|
|
||||||
//
|
|
||||||
// [SetUp]
|
|
||||||
// public void Setup()
|
|
||||||
// {
|
|
||||||
// _interactionModule = new StreamBasedInteractionModule();
|
|
||||||
//
|
|
||||||
// _serialisationModule = new JsonSerialisationModule(_interactionModule, new MockMethodRepository());
|
|
||||||
//
|
|
||||||
// _executeModule = new MockExecModule();
|
|
||||||
// _serialisationModule.SetExecuteModule(_executeModule);
|
|
||||||
//
|
|
||||||
// _frontendInteractionModule = new StreamBasedFrontendInteractionModule();
|
|
||||||
// _frontendSerialisationModule = new JsonFrontendSerialisationModule(_frontendInteractionModule);
|
|
||||||
//
|
|
||||||
// Task.Run(() =>
|
|
||||||
// {
|
|
||||||
// TcpListener listener = new TcpListener(IPAddress.Loopback, 4567);
|
|
||||||
// listener.Start();
|
|
||||||
//
|
|
||||||
// var stream = listener.AcceptTcpClient().GetStream();
|
|
||||||
//
|
|
||||||
// Console.WriteLine("Client connected");
|
|
||||||
//
|
|
||||||
// _interactionModule.RegisterSourse(stream);
|
|
||||||
//
|
|
||||||
// while (isTestNotFinished) ;
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void StreamingTest()
|
|
||||||
// {
|
|
||||||
// var tcpClient = new TcpClient();
|
|
||||||
// tcpClient.Connect(IPAddress.Loopback, 4567);
|
|
||||||
// _frontendInteractionModule.ServerStream = tcpClient.GetStream();
|
|
||||||
//
|
|
||||||
// var req = new DefaultCallRequest { CommandId = 1, ObjectId = -1 };
|
|
||||||
// _frontendSerialisationModule.PostCallRequest(req);
|
|
||||||
// var res = ((JsonElement)_frontendSerialisationModule
|
|
||||||
// .GetNextCommandExecution<FinalCommandExecution>(req.CallRequestId).GetAwaiter().GetResult().Result!)
|
|
||||||
// .Deserialize<MockResult>();
|
|
||||||
// isTestNotFinished = false;
|
|
||||||
// Assert.That(res.A == "wqer" && res.B == 5);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void RemoteObjectTest()
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
using mROA.Implementation;
|
|
||||||
|
|
||||||
namespace mROA.Test;
|
|
||||||
|
|
||||||
public class UnSOization
|
|
||||||
{
|
|
||||||
private ComplexObjectIdentifier _uoi;
|
|
||||||
|
|
||||||
[SetUp]
|
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
_uoi = new ComplexObjectIdentifier
|
|
||||||
{
|
|
||||||
ContextId = -123, OwnerId = 123
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void FlatTest()
|
|
||||||
{
|
|
||||||
var flat = _uoi.Flat;
|
|
||||||
var next = new ComplexObjectIdentifier { Flat = flat };
|
|
||||||
|
|
||||||
Assert.That(_uoi, Is.EqualTo(next));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
// using System.Diagnostics;
|
|
||||||
// using System.Reflection;
|
|
||||||
// using System.Text;
|
|
||||||
// using System.Text.Json;
|
|
||||||
// using Example.Shared;
|
|
||||||
// using mROA.Implementation;
|
|
||||||
// using Newtonsoft.Json;
|
|
||||||
// using JsonSerializer = System.Text.Json.JsonSerializer;
|
|
||||||
//
|
|
||||||
// namespace mROA.Test;
|
|
||||||
//
|
|
||||||
// public class Tests
|
|
||||||
// {
|
|
||||||
// private ProgramlyInteractionChanel _interactionModule;
|
|
||||||
// private ISerialisationModule _serialisationModule;
|
|
||||||
// private IExecuteModule _executeModule;
|
|
||||||
// private IMethodRepository _methodRepository;
|
|
||||||
// private IContextRepository _contextRepository;
|
|
||||||
//
|
|
||||||
// private ITestController _testController;
|
|
||||||
//
|
|
||||||
// [SetUp]
|
|
||||||
// public void Setup()
|
|
||||||
// {
|
|
||||||
// _interactionModule = new ProgramlyInteractionChanel();
|
|
||||||
// var repo = new MethodRepository();
|
|
||||||
// repo.CollectForAssembly(Assembly.GetExecutingAssembly());
|
|
||||||
// _methodRepository = repo;
|
|
||||||
// var repo2 = new ContextRepository();
|
|
||||||
// repo2.FillSingletons(Assembly.GetExecutingAssembly());
|
|
||||||
// _contextRepository = repo2;
|
|
||||||
// _serialisationModule = new JsonSerialisationModule(_interactionModule, _methodRepository);
|
|
||||||
//
|
|
||||||
// _executeModule = new LaunchReadyExecutionModule(_methodRepository, _serialisationModule, _contextRepository);
|
|
||||||
// TransmissionConfig.DefaultContextRepository = _contextRepository;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void CommandPipelineTest()
|
|
||||||
// {
|
|
||||||
// var sw = Stopwatch.StartNew();
|
|
||||||
//
|
|
||||||
// _interactionModule.PassCommand(132, """
|
|
||||||
// {
|
|
||||||
// "RequestTypeId": 0,
|
|
||||||
// "CommandId": 2
|
|
||||||
// }
|
|
||||||
// """u8.ToArray());
|
|
||||||
// Assert.Pass(_interactionModule.OutputBuffer.Last());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void CommandPipelineTestAsync()
|
|
||||||
// {
|
|
||||||
// var sw = Stopwatch.StartNew();
|
|
||||||
// _interactionModule.PassCommand(132, """
|
|
||||||
// {
|
|
||||||
// "RequestTypeId": 0,
|
|
||||||
// "CommandId": 3
|
|
||||||
// }
|
|
||||||
// """u8.ToArray());
|
|
||||||
// while (_interactionModule.OutputBuffer.Count != 2) ;
|
|
||||||
//
|
|
||||||
// Assert.Pass(_interactionModule.OutputBuffer.Last());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void MethodRegistrationTest()
|
|
||||||
// {
|
|
||||||
// var repo = new MethodRepository();
|
|
||||||
// repo.CollectForAssembly(Assembly.GetExecutingAssembly());
|
|
||||||
// Assert.That(repo.GetMethods().ToList().Count == 8);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void ContextSupplyTest()
|
|
||||||
// {
|
|
||||||
// var repo = new ContextRepository();
|
|
||||||
// repo.FillSingletons(Assembly.GetExecutingAssembly());
|
|
||||||
// var singleObject = repo.GetSingleObject(typeof(ITestController)) as ITestController;
|
|
||||||
// singleObject.B();
|
|
||||||
// Assert.That(singleObject.B() == 6);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void TransmissionTest()
|
|
||||||
// {
|
|
||||||
// _interactionModule.PassCommand(132, """
|
|
||||||
// {
|
|
||||||
// "CommandId": 4
|
|
||||||
// }
|
|
||||||
// """u8.ToArray());
|
|
||||||
// var response =
|
|
||||||
// JsonSerializer.Deserialize<TransmittedSharedObject<IContextRepository>>(
|
|
||||||
// JsonSerializer.Deserialize<FinalCommandExecution>(_interactionModule.OutputBuffer.Last())
|
|
||||||
// ?.Result.ToString()
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes(
|
|
||||||
// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId })));
|
|
||||||
//
|
|
||||||
// var firstFull = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result")
|
|
||||||
// .GetInt32();
|
|
||||||
//
|
|
||||||
// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes(
|
|
||||||
// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 4, ObjectId = response.ContextId })));
|
|
||||||
//
|
|
||||||
// response =
|
|
||||||
// JsonSerializer.Deserialize<TransmittedSharedObject<IContextRepository>>(
|
|
||||||
// JsonSerializer.Deserialize<FinalCommandExecution>(_interactionModule.OutputBuffer.Last())
|
|
||||||
// ?.Result.ToString()
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes(
|
|
||||||
// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId })));
|
|
||||||
// _interactionModule.PassCommand(132, Encoding.UTF8.GetBytes(
|
|
||||||
// JsonSerializer.Serialize(new DefaultCallRequest { CommandId = 2, ObjectId = response.ContextId })));
|
|
||||||
//
|
|
||||||
// var secondFull = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result")
|
|
||||||
// .GetInt32();
|
|
||||||
//
|
|
||||||
// Assert.That(firstFull == 456789 && secondFull == 6);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// [Test]
|
|
||||||
// public void LinkedObjectsAndParametersTest()
|
|
||||||
// {
|
|
||||||
// _interactionModule.PassCommand(132, """
|
|
||||||
// {
|
|
||||||
// "CommandId": 6
|
|
||||||
// }
|
|
||||||
// """u8.ToArray());
|
|
||||||
// var response =
|
|
||||||
// JsonSerializer.Deserialize<TransmittedSharedObject<ITestParameter>>(
|
|
||||||
// JsonSerializer.Deserialize<FinalCommandExecution>(_interactionModule.OutputBuffer.Last())
|
|
||||||
// ?.Result.ToString()
|
|
||||||
// );
|
|
||||||
// var x = response.ContextId;
|
|
||||||
// _interactionModule.PassCommand(132,Encoding.UTF8.GetBytes(
|
|
||||||
// JsonSerializer.Serialize(new DefaultCallRequest
|
|
||||||
// {
|
|
||||||
// CommandId = 5,
|
|
||||||
// Parameter = new TestParameter
|
|
||||||
// {
|
|
||||||
// A = 10,
|
|
||||||
// LinkedObject = new TransmittedSharedObject<ITestParameter> { ContextId = x }
|
|
||||||
// }
|
|
||||||
// })));
|
|
||||||
//
|
|
||||||
// var finalResponse = JsonDocument.Parse(_interactionModule.OutputBuffer.Last()).RootElement.GetProperty("Result").GetInt32();
|
|
||||||
//
|
|
||||||
// Assert.That(finalResponse, Is.EqualTo(20));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -23,8 +23,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Codegen", "Codegen", "{3DB22457-E65B-426F-B3DD-08C615132B3E}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -72,6 +70,5 @@ Global
|
|||||||
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
{3DB22457-E65B-426F-B3DD-08C615132B3E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IChannelInteractionModule : IInjectableModule, IDisposable
|
||||||
|
{
|
||||||
|
int ConnectionId { get; set; }
|
||||||
|
Channel<NetworkMessageHeader> ReceiveChanel { get; }
|
||||||
|
ChannelReader<NetworkMessageHeader> TrustedPostChanel { get; }
|
||||||
|
ChannelReader<NetworkMessageHeader> UntrustedPostChanel { get; }
|
||||||
|
Func<bool> IsConnected { get; set; }
|
||||||
|
ValueTask<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true);
|
||||||
|
Task PostMessageAsync(NetworkMessageHeader messageHeader);
|
||||||
|
Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader);
|
||||||
|
event Action<int> OnDisconnected;
|
||||||
|
Task Restart(bool sendRecovery);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
|
|
||||||
public interface IConnectionHub : IInjectableModule
|
public interface IConnectionHub : IInjectableModule
|
||||||
{
|
{
|
||||||
void RegisterInteraction(INextGenerationInteractionModule interaction);
|
void RegisterInteraction(IChannelInteractionModule interaction);
|
||||||
INextGenerationInteractionModule GetInteraction(int id);
|
IChannelInteractionModule GetInteraction(int id);
|
||||||
event ConnectionHandler? OnConnected;
|
event ConnectionHandler? OnConnected;
|
||||||
event DisconnectionHandler? OnDisconnected;
|
event DisconnectionHandler? OnDisconnected;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
using mROA.Implementation;
|
|
||||||
|
|
||||||
namespace mROA.Abstract
|
|
||||||
{
|
|
||||||
public interface IContextRepository : IInjectableModule
|
|
||||||
{
|
|
||||||
int HostId { get; set; }
|
|
||||||
int ResisterObject<T>(object o, IEndPointContext context);
|
|
||||||
void ClearObject(ComplexObjectIdentifier id);
|
|
||||||
T GetObject<T>(ComplexObjectIdentifier id);
|
|
||||||
object GetSingleObject(Type type, int ownerId);
|
|
||||||
int GetObjectIndex<T>(object o, IEndPointContext context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ namespace mROA.Abstract
|
|||||||
{
|
{
|
||||||
public interface IContextRepositoryHub
|
public interface IContextRepositoryHub
|
||||||
{
|
{
|
||||||
IContextRepository GetRepository(int clientId);
|
IInstanceRepository GetRepository(int clientId);
|
||||||
void FreeRepository(int clientId);
|
void FreeRepository(int clientId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+2
-3
@@ -1,9 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Cbor
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
public interface IContextualSerializationToolKit : ISerializationToolkit
|
public interface IContextualSerializationToolKit : IInjectableModule
|
||||||
{
|
{
|
||||||
byte[] Serialize(object objectToSerialize, IEndPointContext? context);
|
byte[] Serialize(object objectToSerialize, IEndPointContext? context);
|
||||||
void Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext? context);
|
void Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext? context);
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
namespace mROA.Abstract
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
public interface IEndPointContext
|
public interface IEndPointContext : IInjectableModule
|
||||||
{
|
{
|
||||||
IContextRepository RealRepository { get; }
|
IInstanceRepository RealRepository { get; }
|
||||||
IContextRepository RemoteRepository { get; }
|
IInstanceRepository RemoteRepository { get; }
|
||||||
int HostId { get; }
|
int HostId { get; set; }
|
||||||
int OwnerId { get; }
|
int OwnerId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,20 @@
|
|||||||
namespace mROA.Abstract
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
public interface IEventBinder<T>
|
public interface IEventBinder<T> : IEventBinder
|
||||||
{
|
{
|
||||||
public void BindEvents(T source, IEndPointContext context,
|
public void BindEvents(T source, IEndPointContext context,
|
||||||
IRepresentationModuleProducer representationModuleProducer, int index);
|
IRepresentationModuleProducer representationModuleProducer, int index);
|
||||||
|
|
||||||
|
void IEventBinder.BindEvents(object source, IEndPointContext context, IRepresentationModuleProducer representationModuleProducer,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
BindEvents((T)source, context, representationModuleProducer, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IEventBinder
|
||||||
|
{
|
||||||
|
public void BindEvents(object source, IEndPointContext context,
|
||||||
|
IRepresentationModuleProducer representationModuleProducer, int index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ namespace mROA.Abstract
|
|||||||
{
|
{
|
||||||
public interface IExecuteModule : IInjectableModule
|
public interface IExecuteModule : IInjectableModule
|
||||||
{
|
{
|
||||||
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository,
|
||||||
IRepresentationModule representationModule);
|
IRepresentationModule representationModule, IEndPointContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace mROA.Abstract
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
public interface IFrontendBridge : IInjectableModule, IDisposable
|
public interface IFrontendBridge : IInjectableModule, IDisposable
|
||||||
{
|
{
|
||||||
void Connect();
|
Task Connect();
|
||||||
void Obstacle();
|
void Obstacle();
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IInstanceRepository : IInjectableModule
|
||||||
|
{
|
||||||
|
int ResisterObject<T>(object o, IEndPointContext context);
|
||||||
|
void ClearObject(ComplexObjectIdentifier id, IEndPointContext context);
|
||||||
|
T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context);
|
||||||
|
T GetSingletonObject<T>(IEndPointContext context) where T : class, IShared;
|
||||||
|
object GetSingletonObject(Type type, IEndPointContext context);
|
||||||
|
int GetObjectIndex<T>(object o, IEndPointContext context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using mROA.Implementation;
|
|
||||||
|
|
||||||
namespace mROA.Abstract
|
|
||||||
{
|
|
||||||
public interface INextGenerationInteractionModule : IInjectableModule, IDisposable
|
|
||||||
{
|
|
||||||
int ConnectionId { get; set; }
|
|
||||||
public Stream? BaseStream { get; set; }
|
|
||||||
Task<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true);
|
|
||||||
Task PostMessageAsync(NetworkMessageHeader messageHeader);
|
|
||||||
void HandleMessage(NetworkMessageHeader messageHeader);
|
|
||||||
NetworkMessageHeader[] UnhandledMessages { get; }
|
|
||||||
NetworkMessageHeader? FirstByFilter(Predicate<NetworkMessageHeader> predicate);
|
|
||||||
event Action<int> OnDisconected;
|
|
||||||
Task Restart(bool sendRecovery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,6 +5,7 @@ namespace mROA.Abstract
|
|||||||
public interface IMethodInvoker
|
public interface IMethodInvoker
|
||||||
{
|
{
|
||||||
bool IsVoid { get; }
|
bool IsVoid { get; }
|
||||||
|
bool IsTrusted { get; }
|
||||||
Type[] ParameterTypes { get; }
|
Type[] ParameterTypes { get; }
|
||||||
Type? ReturnType { get; }
|
Type? ReturnType { get; }
|
||||||
Type SuitableType { get; }
|
Type SuitableType { get; }
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ namespace mROA.Abstract
|
|||||||
{
|
{
|
||||||
public interface IRemoteObjectFactory : IInjectableModule
|
public interface IRemoteObjectFactory : IInjectableModule
|
||||||
{
|
{
|
||||||
T Produce<T>(ComplexObjectIdentifier id);
|
T Produce<T>(ComplexObjectIdentifier id, IEndPointContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IRepresentationModule : IInjectableModule
|
||||||
|
{
|
||||||
|
int Id { get; }
|
||||||
|
|
||||||
|
Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate<NetworkMessageHeader> rule,
|
||||||
|
IEndPointContext? context, CancellationToken token = default,
|
||||||
|
params Func<NetworkMessageHeader, Type?>[] converter);
|
||||||
|
|
||||||
|
IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate<NetworkMessageHeader> rule,
|
||||||
|
IEndPointContext? context, CancellationToken token = default,
|
||||||
|
params Func<NetworkMessageHeader, Type?>[] converter);
|
||||||
|
|
||||||
|
Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||||
|
where T : notnull;
|
||||||
|
|
||||||
|
void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||||
|
where T : notnull;
|
||||||
|
|
||||||
|
Task PostCallMessageUntrustedAsync<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||||
|
where T : notnull;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using mROA.Implementation;
|
|
||||||
|
|
||||||
namespace mROA.Abstract
|
|
||||||
{
|
|
||||||
public interface IRepresentationModule : IInjectableModule
|
|
||||||
{
|
|
||||||
int Id { get; }
|
|
||||||
|
|
||||||
Task<T> GetMessageAsync<T>(Guid? requestId = null, EMessageType? messageType = null,
|
|
||||||
CancellationToken token = default);
|
|
||||||
|
|
||||||
T GetMessage<T>(Guid? requestId = null, EMessageType? messageType = null);
|
|
||||||
|
|
||||||
Task<byte[]> GetRawMessage(Guid? requestId = null, EMessageType? messageType = null,
|
|
||||||
CancellationToken token = default);
|
|
||||||
|
|
||||||
Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
|
|
||||||
Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType);
|
|
||||||
void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
|
|
||||||
void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
using System;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
namespace mROA.Abstract
|
|
||||||
{
|
{
|
||||||
public interface ISerializationToolkit : IInjectableModule
|
// public interface IContextualSerializationToolKit : IInjectableModule
|
||||||
{
|
// {
|
||||||
byte[] Serialize<T>(T objectToSerialize);
|
// byte[] Serialize<T>(T objectToSerialize);
|
||||||
byte[] Serialize(object objectToSerialize, Type type);
|
// byte[] Serialize(object objectToSerialize, Type type);
|
||||||
T? Deserialize<T>(byte[] rawData);
|
// T? Deserialize<T>(byte[] rawData);
|
||||||
object? Deserialize(byte[] rawData, Type type);
|
// object? Deserialize(byte[] rawData, Type type);
|
||||||
T? Deserialize<T>(Span<byte> rawData);
|
// T? Deserialize<T>(Span<byte> rawData);
|
||||||
object? Deserialize(Span<byte> rawData, Type type);
|
// object? Deserialize(Span<byte> rawData, Type type);
|
||||||
T? Cast<T>(object? nonCasted);
|
// T? Cast<T>(object? nonCasted);
|
||||||
object? Cast(object? nonCasted, Type type);
|
// object? Cast(object? nonCasted, Type type);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IUntrustedGateway : IInjectableModule, IDisposable
|
||||||
|
{
|
||||||
|
Task Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IUntrustedInteractionModule : IInjectableModule, IDisposable
|
||||||
|
{
|
||||||
|
Task Start(IPEndPoint endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.Attributes
|
||||||
|
{
|
||||||
|
public class UntrustedAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ namespace mROA.Implementation.Backend
|
|||||||
|
|
||||||
public int GetNextIdentity()
|
public int GetNextIdentity()
|
||||||
{
|
{
|
||||||
return ++_currentId;
|
return -++_currentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
|
|||||||
@@ -21,9 +21,8 @@ namespace mROA.Implementation.Backend
|
|||||||
|
|
||||||
public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies)
|
public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies)
|
||||||
{
|
{
|
||||||
var repo = new ContextRepository();
|
var repo = new InstanceRepository();
|
||||||
repo.FillSingletons(assemblies);
|
repo.FillSingletons(assemblies);
|
||||||
TransmissionConfig.RealContextRepository = repo;
|
|
||||||
builder.Modules.Add(repo);
|
builder.Modules.Add(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
private ICancellationRepository? _cancellationRepo;
|
private ICancellationRepository? _cancellationRepo;
|
||||||
private IMethodRepository? _methodRepo;
|
private IMethodRepository? _methodRepo;
|
||||||
private ISerializationToolkit? _serialization;
|
private IContextualSerializationToolKit? _serialization;
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
@@ -21,27 +21,21 @@ namespace mROA.Implementation.Backend
|
|||||||
case ICancellationRepository cancellationRepo:
|
case ICancellationRepository cancellationRepo:
|
||||||
_cancellationRepo = cancellationRepo;
|
_cancellationRepo = cancellationRepo;
|
||||||
break;
|
break;
|
||||||
case ISerializationToolkit serializationToolkit:
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
_serialization = serializationToolkit;
|
_serialization = serializationToolkit;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
public ICommandExecution Execute(ICallRequest command, IInstanceRepository instanceRepository,
|
||||||
IRepresentationModule representationModule)
|
IRepresentationModule representationModule, IEndPointContext endPointContext)
|
||||||
{
|
{
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine(command.GetType().Name);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ThrowIfNotInjected(contextRepository);
|
ThrowIfNotInjected(instanceRepository);
|
||||||
if (command is CancelRequest)
|
if (command is CancelRequest)
|
||||||
{
|
{
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine("Final cancelling request");
|
|
||||||
#endif
|
|
||||||
return CancelExecution(command);
|
return CancelExecution(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +43,7 @@ namespace mROA.Implementation.Backend
|
|||||||
if (invoker == null)
|
if (invoker == null)
|
||||||
throw new Exception($"Command {command.CommandId} not found");
|
throw new Exception($"Command {command.CommandId} not found");
|
||||||
|
|
||||||
var context = GetContext(command, contextRepository, invoker);
|
var context = GetContext(command, instanceRepository, invoker, endPointContext);
|
||||||
|
|
||||||
if (context == null)
|
if (context == null)
|
||||||
throw new NullReferenceException("Instance can't be null");
|
throw new NullReferenceException("Instance can't be null");
|
||||||
@@ -58,7 +52,7 @@ namespace mROA.Implementation.Backend
|
|||||||
object?[]? castedParams = null;
|
object?[]? castedParams = null;
|
||||||
|
|
||||||
if (invoker.ParameterTypes.Length != 0)
|
if (invoker.ParameterTypes.Length != 0)
|
||||||
castedParams = CastedParams(command, invoker);
|
castedParams = CastedParams(command, invoker, endPointContext);
|
||||||
|
|
||||||
|
|
||||||
var execContext = new RequestContext(command.Id, representationModule.Id);
|
var execContext = new RequestContext(command.Id, representationModule.Id);
|
||||||
@@ -68,18 +62,15 @@ namespace mROA.Implementation.Backend
|
|||||||
case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker:
|
case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker:
|
||||||
return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command,
|
return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command,
|
||||||
_cancellationRepo!,
|
_cancellationRepo!,
|
||||||
representationModule, execContext);
|
representationModule, execContext, endPointContext);
|
||||||
case AsyncMethodInvoker asyncMethodInvoker:
|
case AsyncMethodInvoker asyncMethodInvoker:
|
||||||
return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo!,
|
return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo!,
|
||||||
representationModule, execContext);
|
representationModule, execContext, endPointContext);
|
||||||
default:
|
default:
|
||||||
var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext);
|
var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext);
|
||||||
if (command.CommandId == -1)
|
if (command.CommandId == -1)
|
||||||
{
|
{
|
||||||
#if TRACE
|
instanceRepository.ClearObject(command.ObjectId, endPointContext);
|
||||||
Console.WriteLine("Disposing object");
|
|
||||||
#endif
|
|
||||||
contextRepository.ClearObject(command.ObjectId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -95,26 +86,27 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object GetContext(ICallRequest command, IContextRepository contextRepository, IMethodInvoker invoker)
|
private static object GetContext(ICallRequest command, IInstanceRepository instanceRepository,
|
||||||
|
IMethodInvoker invoker, IEndPointContext endPointContext)
|
||||||
{
|
{
|
||||||
var context = command.ObjectId.ContextId != -1
|
var context = command.ObjectId.ContextId != -1
|
||||||
? contextRepository.GetObject<object>(command.ObjectId)
|
? instanceRepository.GetObject<object>(command.ObjectId, endPointContext)
|
||||||
: contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId);
|
: instanceRepository.GetSingletonObject(invoker.SuitableType, endPointContext);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker)
|
private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker, IEndPointContext context)
|
||||||
{
|
{
|
||||||
object?[] castedParams = new object[invoker.ParameterTypes.Length];
|
object?[] castedParams = new object[invoker.ParameterTypes.Length];
|
||||||
for (var i = 0; i < castedParams.Length; i++)
|
for (var i = 0; i < castedParams.Length; i++)
|
||||||
{
|
{
|
||||||
castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i]);
|
castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i], context);
|
||||||
}
|
}
|
||||||
|
|
||||||
return castedParams;
|
return castedParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThrowIfNotInjected(IContextRepository contextRepository)
|
private void ThrowIfNotInjected(IInstanceRepository instanceRepository)
|
||||||
{
|
{
|
||||||
if (_cancellationRepo is null)
|
if (_cancellationRepo is null)
|
||||||
throw new NullReferenceException("Method repository was not defined");
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
@@ -122,7 +114,7 @@ namespace mROA.Implementation.Backend
|
|||||||
if (_methodRepo is null)
|
if (_methodRepo is null)
|
||||||
throw new NullReferenceException("Method repository was not defined");
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
|
|
||||||
if (contextRepository is null)
|
if (instanceRepository is null)
|
||||||
throw new NullReferenceException("Context repository was not defined");
|
throw new NullReferenceException("Context repository was not defined");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,6 +139,11 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||||
|
|
||||||
|
if (!invoker.IsTrusted)
|
||||||
|
{
|
||||||
|
return new AsyncCommandExecution();
|
||||||
|
}
|
||||||
|
|
||||||
if (invoker.IsVoid)
|
if (invoker.IsVoid)
|
||||||
{
|
{
|
||||||
return new FinalCommandExecution
|
return new FinalCommandExecution
|
||||||
@@ -163,24 +160,27 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return new ExceptionCommandExecution
|
if (invoker.IsTrusted)
|
||||||
|
return new ExceptionCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
return new AsyncCommandExecution
|
||||||
{
|
{
|
||||||
Id = command.Id,
|
Id = command.Id
|
||||||
Exception = e.ToString()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
IRepresentationModule representationModule, RequestContext executionContext)
|
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
#if TRACE
|
|
||||||
token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}"));
|
|
||||||
#endif
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
|
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
|
||||||
@@ -194,12 +194,10 @@ namespace mROA.Implementation.Backend
|
|||||||
};
|
};
|
||||||
_cancellationRepo?.FreeCancelation(command.Id);
|
_cancellationRepo?.FreeCancelation(command.Id);
|
||||||
|
|
||||||
var multiClientOwnershipRepository =
|
|
||||||
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
|
||||||
|
|
||||||
multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id);
|
if (invoker.IsTrusted)
|
||||||
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution, payload);
|
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution,
|
||||||
multiClientOwnershipRepository?.FreeOwnership();
|
payload, context);
|
||||||
});
|
});
|
||||||
|
|
||||||
return new AsyncCommandExecution
|
return new AsyncCommandExecution
|
||||||
@@ -209,17 +207,22 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return new ExceptionCommandExecution
|
if (invoker.IsTrusted)
|
||||||
|
return new ExceptionCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
return new AsyncCommandExecution
|
||||||
{
|
{
|
||||||
Id = command.Id,
|
Id = command.Id
|
||||||
Exception = e.ToString()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
IRepresentationModule representationModule, RequestContext executionContext)
|
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
@@ -237,12 +240,8 @@ namespace mROA.Implementation.Backend
|
|||||||
};
|
};
|
||||||
_cancellationRepo!.FreeCancelation(command.Id);
|
_cancellationRepo!.FreeCancelation(command.Id);
|
||||||
|
|
||||||
var multiClientOwnershipRepository =
|
|
||||||
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
|
||||||
multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id);
|
|
||||||
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution,
|
representationModule.PostCallMessage(command.Id, EMessageType.FinishedCommandExecution,
|
||||||
payload);
|
payload, context);
|
||||||
multiClientOwnershipRepository?.FreeOwnership();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return new AsyncCommandExecution
|
return new AsyncCommandExecution
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
public class ConnectionHub : IConnectionHub
|
public class ConnectionHub : IConnectionHub
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
|
private readonly Dictionary<int, IChannelInteractionModule> _connections = new();
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
private IContextualSerializationToolKit? _serializationToolkit;
|
||||||
|
|
||||||
public void RegisterInteraction(INextGenerationInteractionModule interaction)
|
public void RegisterInteraction(IChannelInteractionModule interaction)
|
||||||
{
|
{
|
||||||
if (_serializationToolkit is null)
|
if (_serializationToolkit is null)
|
||||||
throw new NullReferenceException("Serialization toolkit is null");
|
throw new NullReferenceException("Serialization toolkit is null");
|
||||||
@@ -21,9 +21,9 @@ namespace mROA.Implementation.Backend
|
|||||||
OnConnected?.Invoke(module);
|
OnConnected?.Invoke(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
public INextGenerationInteractionModule GetInteraction(int id)
|
public IChannelInteractionModule GetInteraction(int id)
|
||||||
{
|
{
|
||||||
return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
|
return _connections!.GetValueOrDefault(id, null) ?? _connections!.GetValueOrDefault(-id, null) ?? throw new Exception("No connection found");
|
||||||
}
|
}
|
||||||
|
|
||||||
public event ConnectionHandler? OnConnected;
|
public event ConnectionHandler? OnConnected;
|
||||||
@@ -31,7 +31,7 @@ namespace mROA.Implementation.Backend
|
|||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
if (dependency is ISerializationToolkit serializationToolkit)
|
if (dependency is IContextualSerializationToolKit serializationToolkit)
|
||||||
_serializationToolkit = serializationToolkit;
|
_serializationToolkit = serializationToolkit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using System;
|
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend
|
namespace mROA.Implementation.Backend
|
||||||
{
|
{
|
||||||
@@ -7,17 +7,11 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
private IConnectionHub? _hub;
|
private IConnectionHub? _hub;
|
||||||
|
|
||||||
private IContextRepository? _contextRepository;
|
private IInstanceRepository? _contextRepository;
|
||||||
private IContextRepository? _remoteContextRepository;
|
private IInstanceRepository? _remoteContextRepository;
|
||||||
private IMethodRepository? _methodRepository;
|
private IMethodRepository? _methodRepository;
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
private IContextualSerializationToolKit? _serializationToolkit;
|
||||||
private IExecuteModule? _executeModule;
|
private IExecuteModule? _executeModule;
|
||||||
private readonly Type _extractorType;
|
|
||||||
|
|
||||||
public HubRequestExtractor(Type extractorType)
|
|
||||||
{
|
|
||||||
_extractorType = extractorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
@@ -27,17 +21,17 @@ namespace mROA.Implementation.Backend
|
|||||||
_hub = connectionHub;
|
_hub = connectionHub;
|
||||||
_hub.OnConnected += HubOnOnConnected;
|
_hub.OnConnected += HubOnOnConnected;
|
||||||
break;
|
break;
|
||||||
case MultiClientContextRepository:
|
case MultiClientInstanceRepository:
|
||||||
case ContextRepository:
|
case InstanceRepository:
|
||||||
_contextRepository = dependency as IContextRepository;
|
_contextRepository = dependency as IInstanceRepository;
|
||||||
break;
|
break;
|
||||||
case RemoteContextRepository remoteContextRepository:
|
case RemoteInstanceRepository remoteContextRepository:
|
||||||
_remoteContextRepository = remoteContextRepository;
|
_remoteContextRepository = remoteContextRepository;
|
||||||
break;
|
break;
|
||||||
case IMethodRepository methodRepository:
|
case IMethodRepository methodRepository:
|
||||||
_methodRepository = methodRepository;
|
_methodRepository = methodRepository;
|
||||||
break;
|
break;
|
||||||
case ISerializationToolkit serializationToolkit:
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
_serializationToolkit = serializationToolkit;
|
_serializationToolkit = serializationToolkit;
|
||||||
break;
|
break;
|
||||||
case IExecuteModule executeModule:
|
case IExecuteModule executeModule:
|
||||||
@@ -49,7 +43,7 @@ namespace mROA.Implementation.Backend
|
|||||||
private void HubOnOnConnected(IRepresentationModule interaction)
|
private void HubOnOnConnected(IRepresentationModule interaction)
|
||||||
{
|
{
|
||||||
var extractor = CreateExtractor(interaction);
|
var extractor = CreateExtractor(interaction);
|
||||||
extractor.StartExtraction().ContinueWith(t => OnDisconnected(interaction));
|
extractor.StartExtraction().ContinueWith(_ => OnDisconnected(interaction));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDisconnected(IRepresentationModule representationModule)
|
private void OnDisconnected(IRepresentationModule representationModule)
|
||||||
@@ -60,16 +54,23 @@ namespace mROA.Implementation.Backend
|
|||||||
|
|
||||||
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
||||||
{
|
{
|
||||||
var extractor = (IRequestExtractor)Activator.CreateInstance(_extractorType)!;
|
var extractor = new RequestExtractor();
|
||||||
|
var context = new EndPointContext
|
||||||
|
{
|
||||||
|
HostId = 0, OwnerId = -interaction.Id
|
||||||
|
};
|
||||||
extractor.Inject(interaction);
|
extractor.Inject(interaction);
|
||||||
if (_contextRepository is IContextRepositoryHub contextHub)
|
if (_contextRepository is IContextRepositoryHub contextHub)
|
||||||
extractor.Inject(contextHub.GetRepository(interaction.Id));
|
context.RealRepository = contextHub.GetRepository(interaction.Id);
|
||||||
else
|
else
|
||||||
extractor.Inject(interaction);
|
context.RealRepository = _contextRepository!;
|
||||||
|
|
||||||
|
context.RemoteRepository = _remoteContextRepository!;
|
||||||
|
|
||||||
|
extractor.Inject(context);
|
||||||
extractor.Inject(_methodRepository);
|
extractor.Inject(_methodRepository);
|
||||||
extractor.Inject(_serializationToolkit);
|
extractor.Inject(_serializationToolkit);
|
||||||
extractor.Inject(_executeModule);
|
extractor.Inject(_executeModule);
|
||||||
extractor.Inject(_remoteContextRepository);
|
|
||||||
return extractor;
|
return extractor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-8
@@ -2,13 +2,12 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend
|
namespace mROA.Implementation.Backend
|
||||||
{
|
{
|
||||||
public class ContextRepository : IContextRepository
|
public class InstanceRepository : IInstanceRepository
|
||||||
{
|
{
|
||||||
public static object[] EventBinders = { };
|
public static object[] EventBinders = { };
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ namespace mROA.Implementation.Backend
|
|||||||
private IStorage<object> _storage;
|
private IStorage<object> _storage;
|
||||||
|
|
||||||
|
|
||||||
public ContextRepository()
|
public InstanceRepository()
|
||||||
{
|
{
|
||||||
_storage = new ExtensibleStorage<object>();
|
_storage = new ExtensibleStorage<object>();
|
||||||
}
|
}
|
||||||
@@ -33,18 +32,24 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
var last = _storage.Place(o);
|
var last = _storage.Place(o);
|
||||||
|
|
||||||
EventBinders.OfType<IEventBinder<T>>().FirstOrDefault()
|
var sharedType = typeof(IShared);
|
||||||
?.BindEvents((T)o, context, _representationModuleProducer!, last);
|
var interfaces = o.GetType().GetInterfaces();
|
||||||
|
var generic = interfaces.Where(i => sharedType.IsAssignableFrom(i) && i != sharedType)
|
||||||
|
.Select(i => typeof(IEventBinder<>).MakeGenericType(i));
|
||||||
|
|
||||||
|
var binders = EventBinders.Where(i => generic.Any(g => g.IsAssignableFrom(i.GetType())));
|
||||||
|
foreach (var binder in binders)
|
||||||
|
((IEventBinder)binder).BindEvents(o, context, _representationModuleProducer!, last);
|
||||||
|
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearObject(ComplexObjectIdentifier id)
|
public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
{
|
{
|
||||||
_storage.Free(id.ContextId);
|
_storage.Free(id.ContextId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetObject<T>(ComplexObjectIdentifier id)
|
public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
{
|
{
|
||||||
var value = _storage.GetValue(id.ContextId);
|
var value = _storage.GetValue(id.ContextId);
|
||||||
|
|
||||||
@@ -56,7 +61,13 @@ namespace mROA.Implementation.Backend
|
|||||||
return (T)value;
|
return (T)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object GetSingleObject(Type type, int ownerId)
|
public T GetSingletonObject<T>(IEndPointContext context) where T : class, IShared
|
||||||
|
{
|
||||||
|
return GetSingletonObject(typeof(T), context) as T ??
|
||||||
|
throw new ArgumentException("Unregistered singleton type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetSingletonObject(Type type, IEndPointContext context)
|
||||||
{
|
{
|
||||||
return _singletons.GetValueOrDefault(type.GetHashCode()) ??
|
return _singletons.GetValueOrDefault(type.GetHashCode()) ??
|
||||||
throw new ArgumentException("Unregistered singleton type");
|
throw new ArgumentException("Unregistered singleton type");
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend
|
|
||||||
{
|
|
||||||
public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub
|
|
||||||
{
|
|
||||||
private readonly Func<int, IContextRepository> _produceRepository;
|
|
||||||
private readonly Dictionary<int, IContextRepository> _repositories = new();
|
|
||||||
|
|
||||||
public MultiClientContextRepository(Func<int, IContextRepository> produceRepository)
|
|
||||||
{
|
|
||||||
_produceRepository = produceRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public int HostId { get; set; }
|
|
||||||
|
|
||||||
public int ResisterObject<T>(object o, IEndPointContext context)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
|
||||||
return repository.ResisterObject<T>(o, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearObject(ComplexObjectIdentifier id)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
|
||||||
repository.ClearObject(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetObject<T>(ComplexObjectIdentifier id)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
|
||||||
return repository.GetObject<T>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetSingleObject(Type type, int ownerId)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
|
||||||
return repository.GetSingleObject(type, ownerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetObjectIndex<T>(object o, IEndPointContext context)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
|
||||||
return repository.GetObjectIndex<T>(o, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IContextRepository GetRepository(int clientId)
|
|
||||||
{
|
|
||||||
var repository = GetRepositoryByClientId(clientId);
|
|
||||||
return repository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FreeRepository(int clientId)
|
|
||||||
{
|
|
||||||
_repositories.Remove(clientId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IContextRepository GetRepositoryByClientId(int clientId)
|
|
||||||
{
|
|
||||||
if (_repositories.TryGetValue(clientId, out var repository))
|
|
||||||
return repository;
|
|
||||||
|
|
||||||
var created = _produceRepository(clientId);
|
|
||||||
_repositories.Add(clientId, created);
|
|
||||||
return created;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.Backend
|
||||||
|
{
|
||||||
|
public class MultiClientInstanceRepository : IInstanceRepository, IContextRepositoryHub
|
||||||
|
{
|
||||||
|
private readonly Func<int, IInstanceRepository> _produceRepository;
|
||||||
|
private readonly Dictionary<int, IInstanceRepository> _repositories = new();
|
||||||
|
|
||||||
|
public MultiClientInstanceRepository(Func<int, IInstanceRepository> produceRepository)
|
||||||
|
{
|
||||||
|
_produceRepository = produceRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public int HostId { get; set; }
|
||||||
|
|
||||||
|
public int ResisterObject<T>(object o, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
return repository.ResisterObject<T>(o, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
repository.ClearObject(id, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
return repository.GetObject<T>(id, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetSingletonObject<T>(IEndPointContext context) where T : class, IShared
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
return repository.GetSingletonObject<T>(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetSingletonObject(Type type, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
return repository.GetSingletonObject(type, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetObjectIndex<T>(object o, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(context.OwnerId);
|
||||||
|
return repository.GetObjectIndex<T>(o, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IInstanceRepository GetRepository(int clientId)
|
||||||
|
{
|
||||||
|
var repository = GetRepositoryByClientId(clientId);
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FreeRepository(int clientId)
|
||||||
|
{
|
||||||
|
_repositories.Remove(clientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IInstanceRepository GetRepositoryByClientId(int clientId)
|
||||||
|
{
|
||||||
|
if (_repositories.TryGetValue(clientId, out var repository))
|
||||||
|
return repository;
|
||||||
|
|
||||||
|
var created = _produceRepository(clientId);
|
||||||
|
_repositories.Add(clientId, created);
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,10 +13,8 @@ namespace mROA.Implementation.Backend
|
|||||||
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
|
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetHostOwnershipId()
|
public int GetHostOwnershipId() => 0;
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterOwnership(int ownershipId)
|
public void RegisterOwnership(int ownershipId)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
@@ -12,7 +14,8 @@ namespace mROA.Implementation.Backend
|
|||||||
private readonly Type? _interactionModuleType;
|
private readonly Type? _interactionModuleType;
|
||||||
private readonly TcpListener _tcpListener;
|
private readonly TcpListener _tcpListener;
|
||||||
private IConnectionHub? _hub;
|
private IConnectionHub? _hub;
|
||||||
private ISerializationToolkit? _serialization;
|
private IContextualSerializationToolKit? _serialization;
|
||||||
|
private Dictionary<int, CancellationTokenSource> _extractorsCTS = new();
|
||||||
|
|
||||||
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType,
|
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType,
|
||||||
IInjectableModule[] injectableModules)
|
IInjectableModule[] injectableModules)
|
||||||
@@ -29,15 +32,6 @@ namespace mROA.Implementation.Backend
|
|||||||
Console.WriteLine("Enter Backspace to stop");
|
Console.WriteLine("Enter Backspace to stop");
|
||||||
|
|
||||||
Task.Run(HandleIncomingConnections);
|
Task.Run(HandleIncomingConnections);
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var key = Console.ReadKey();
|
|
||||||
if (key.Key == ConsoleKey.Backspace)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Stopping");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@@ -52,49 +46,73 @@ namespace mROA.Implementation.Backend
|
|||||||
case IConnectionHub interactionModule:
|
case IConnectionHub interactionModule:
|
||||||
_hub = interactionModule;
|
_hub = interactionModule;
|
||||||
break;
|
break;
|
||||||
case ISerializationToolkit serializationToolkit:
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
_serialization = serializationToolkit;
|
_serialization = serializationToolkit;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleIncomingConnections()
|
private async Task HandleIncomingConnections()
|
||||||
{
|
{
|
||||||
ThrowIfNotInjected();
|
ThrowIfNotInjected();
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var client = _tcpListener.AcceptTcpClient();
|
var client = await _tcpListener.AcceptTcpClientAsync();
|
||||||
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
||||||
var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule;
|
var interaction = Activator.CreateInstance(_interactionModuleType!) as IChannelInteractionModule;
|
||||||
|
|
||||||
foreach (var injectableModule in _injectableModules!)
|
foreach (var injectableModule in _injectableModules!)
|
||||||
interaction!.Inject(injectableModule);
|
interaction!.Inject(injectableModule);
|
||||||
|
|
||||||
interaction!.Inject(_serialization);
|
interaction!.Inject(_serialization);
|
||||||
interaction.BaseStream = client.GetStream();
|
|
||||||
|
|
||||||
var connectionRequest = interaction.GetNextMessageReceiving(false)
|
|
||||||
.GetAwaiter().GetResult()!;
|
//TODO сделать контекст
|
||||||
|
var context = new EndPointContext();
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
switch (connectionRequest.MessageType)
|
switch (connectionRequest.MessageType)
|
||||||
{
|
{
|
||||||
case EMessageType.ClientConnect:
|
case EMessageType.ClientConnect:
|
||||||
|
context.HostId = 0;
|
||||||
|
context.OwnerId = -interaction.ConnectionId;
|
||||||
|
Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token));
|
||||||
|
_ = streamExtractor.SendFromChannel(interaction.TrustedPostChanel, cts.Token);
|
||||||
interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!,
|
interaction.PostMessageAsync(new NetworkMessageHeader(_serialization!,
|
||||||
new IdAssignment { Id = -interaction.ConnectionId }));
|
new IdAssignment { Id = interaction.ConnectionId }, null));
|
||||||
|
_extractorsCTS[interaction.ConnectionId] = cts;
|
||||||
_hub!.RegisterInteraction(interaction);
|
_hub!.RegisterInteraction(interaction);
|
||||||
Console.WriteLine("Client registered");
|
Console.WriteLine("Client registered");
|
||||||
break;
|
break;
|
||||||
case EMessageType.ClientRecovery:
|
case EMessageType.ClientRecovery:
|
||||||
{
|
{
|
||||||
|
var recoveryRequest = _serialization!.Deserialize<ClientRecovery>(connectionRequest.Data, null);
|
||||||
interaction.BaseStream = null;
|
|
||||||
var recoveryRequest = _serialization!.Deserialize<ClientRecovery>(connectionRequest.Data)!;
|
|
||||||
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
var recoveryInteraction = _hub.GetInteraction(recoveryRequest.Id);
|
||||||
recoveryInteraction.BaseStream = client.GetStream();
|
|
||||||
|
_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);
|
recoveryInteraction.Restart(false);
|
||||||
Console.WriteLine("Connection recovery for client {0} finished", recoveryRequest.Id);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using static mROA.Implementation.EMessageType;
|
||||||
|
|
||||||
|
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 IEndPointContext _context;
|
||||||
|
public UdpGateway(IPEndPoint listeningEndpoint)
|
||||||
|
{
|
||||||
|
_client = new UdpClient(listeningEndpoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
switch (dependency)
|
||||||
|
{
|
||||||
|
case IConnectionHub hub:
|
||||||
|
_hub = hub;
|
||||||
|
break;
|
||||||
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
|
break;
|
||||||
|
case IEndPointContext context:
|
||||||
|
_context = context;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_tokenSource.Cancel();
|
||||||
|
_client.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Start()
|
||||||
|
{
|
||||||
|
var token = _tokenSource.Token;
|
||||||
|
return Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while (token.IsCancellationRequested == false)
|
||||||
|
{
|
||||||
|
var incoming = await _client.ReceiveAsync();
|
||||||
|
var parsed = _serializationToolkit.Deserialize<NetworkMessageHeader>(incoming.Buffer, _context);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int channelId;
|
||||||
|
switch (parsed.MessageType)
|
||||||
|
{
|
||||||
|
case UntrustedConnect:
|
||||||
|
channelId = BitConverter.ToInt32(parsed.Data);
|
||||||
|
_reservedPorts[incoming.RemoteEndPoint] = channelId;
|
||||||
|
_ = UntrustedSend(_hub.GetInteraction(channelId), incoming.RemoteEndPoint);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
channelId = _reservedPorts[incoming.RemoteEndPoint];
|
||||||
|
var interaction = _hub.GetInteraction(channelId);
|
||||||
|
await interaction.ReceiveChanel.Writer.WriteAsync(parsed, token);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UntrustedSend(IChannelInteractionModule interaction, IPEndPoint endpoint)
|
||||||
|
{
|
||||||
|
return Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await foreach (var post in interaction.UntrustedPostChanel.ReadAllAsync())
|
||||||
|
{
|
||||||
|
if (post.MessageType is not (CallRequest or EMessageType.CancelRequest
|
||||||
|
or EventRequest))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var parsed = _serializationToolkit.Serialize(post, _context);
|
||||||
|
await _client.SendAsync(parsed, parsed.Length, endpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
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 IContextualSerializationToolKit? _serialization;
|
||||||
|
private bool _isConnected = true;
|
||||||
|
private bool _isActive = true;
|
||||||
|
private TaskCompletionSource<Stream> _reconnection;
|
||||||
|
private IEndPointContext? _context;
|
||||||
|
|
||||||
|
public ChannelInteractionModule()
|
||||||
|
{
|
||||||
|
ReceiveChanel = Channel.CreateUnbounded<NetworkMessageHeader>(new UnboundedChannelOptions
|
||||||
|
{
|
||||||
|
SingleReader = false,
|
||||||
|
SingleWriter = false,
|
||||||
|
});
|
||||||
|
_receiveReader = ReceiveChanel.Reader;
|
||||||
|
_outputTrustedChannel = Channel.CreateBounded<NetworkMessageHeader>(new BoundedChannelOptions(1)
|
||||||
|
{
|
||||||
|
SingleReader = true,
|
||||||
|
SingleWriter = true,
|
||||||
|
});
|
||||||
|
_trustedWriter = _outputTrustedChannel.Writer;
|
||||||
|
_outputUntrustedChannel = Channel.CreateUnbounded<NetworkMessageHeader>(new UnboundedChannelOptions
|
||||||
|
{
|
||||||
|
SingleReader = true,
|
||||||
|
SingleWriter = true,
|
||||||
|
});
|
||||||
|
_untrustedWriter = _outputUntrustedChannel.Writer;
|
||||||
|
_reconnection = new TaskCompletionSource<Stream>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ConnectionId { get; set; }
|
||||||
|
|
||||||
|
public Channel<NetworkMessageHeader> ReceiveChanel { get; }
|
||||||
|
|
||||||
|
public ChannelReader<NetworkMessageHeader> TrustedPostChanel => _outputTrustedChannel.Reader;
|
||||||
|
public ChannelReader<NetworkMessageHeader> UntrustedPostChanel => _outputUntrustedChannel.Reader;
|
||||||
|
public Func<bool> IsConnected { get; set; } = () => false;
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
switch (dependency)
|
||||||
|
{
|
||||||
|
case IContextualSerializationToolKit toolkit:
|
||||||
|
_serialization = toolkit;
|
||||||
|
break;
|
||||||
|
case IIdentityGenerator identityGenerator:
|
||||||
|
ConnectionId = identityGenerator.GetNextIdentity();
|
||||||
|
break;
|
||||||
|
case IEndPointContext endpointContext:
|
||||||
|
_context = endpointContext;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if (!IsConnected())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _trustedWriter.WriteAsync(messageHeader);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
||||||
|
|
||||||
|
|
||||||
|
public async Task PostMessageAsync(NetworkMessageHeader messageHeader)
|
||||||
|
{
|
||||||
|
if (_serialization == null)
|
||||||
|
throw new NullReferenceException("Serialization toolkit is not initialized");
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (await PostMessageInternal(messageHeader))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!_isActive)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isConnected = false;
|
||||||
|
await MakeRecovery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PostMessageUntrustedAsync(NetworkMessageHeader messageHeader)
|
||||||
|
{
|
||||||
|
await _untrustedWriter.WriteAsync(messageHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<int>? OnDisconnected;
|
||||||
|
|
||||||
|
public async Task Restart(bool sendRecovery)
|
||||||
|
{
|
||||||
|
if (sendRecovery)
|
||||||
|
{
|
||||||
|
await PostMessageAsync(
|
||||||
|
new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId)), _context));
|
||||||
|
await ReceiveChanel.Reader.ReadAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _trustedWriter.WriteAsync(new NetworkMessageHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
_reconnection.TrySetResult(Stream.Null);
|
||||||
|
_isConnected = true;
|
||||||
|
_reconnection = new TaskCompletionSource<Stream>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MakeRecovery()
|
||||||
|
{
|
||||||
|
lock (_reconnection)
|
||||||
|
{
|
||||||
|
OnDisconnected?.Invoke(ConnectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_reconnection.Task.IsCompleted && !_isConnected)
|
||||||
|
{
|
||||||
|
await _reconnection.Task;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_isActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StreamExtractor
|
||||||
|
{
|
||||||
|
private readonly Stream _ioStream;
|
||||||
|
private readonly IContextualSerializationToolKit _serializationToolkit;
|
||||||
|
private const int BufferSize = ushort.MaxValue;
|
||||||
|
private readonly Memory<byte> _buffer = new byte[BufferSize];
|
||||||
|
private bool _manualConnectionState = true;
|
||||||
|
private readonly IEndPointContext _context;
|
||||||
|
|
||||||
|
public StreamExtractor(Stream ioStream, IContextualSerializationToolKit serializationToolkit,
|
||||||
|
IEndPointContext context)
|
||||||
|
{
|
||||||
|
_ioStream = ioStream;
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action<NetworkMessageHeader> MessageReceived = _ => { };
|
||||||
|
|
||||||
|
private ushort ReadMessageLength()
|
||||||
|
{
|
||||||
|
var firstBit = _ioStream.ReadByte();
|
||||||
|
if (firstBit == -1)
|
||||||
|
{
|
||||||
|
_manualConnectionState = false;
|
||||||
|
throw new EndOfStreamException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_manualConnectionState = true;
|
||||||
|
var secondBit = (byte)_ioStream.ReadByte();
|
||||||
|
|
||||||
|
var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit });
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SingleReceive(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var len = ReadMessageLength();
|
||||||
|
var localSpan = _buffer[..len];
|
||||||
|
|
||||||
|
await _ioStream.ReadExactlyAsync(localSpan, cancellationToken: token);
|
||||||
|
|
||||||
|
var message = _serializationToolkit.Deserialize<NetworkMessageHeader>(localSpan, _context);
|
||||||
|
MessageReceived(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoopedReceive(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
while (token.IsCancellationRequested == false && IsConnected)
|
||||||
|
{
|
||||||
|
await SingleReceive(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Send(NetworkMessageHeader message, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
var rawMessage = _serializationToolkit.Serialize(message, _context);
|
||||||
|
var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort));
|
||||||
|
|
||||||
|
await _ioStream.WriteAsync(header, token);
|
||||||
|
await _ioStream.WriteAsync(rawMessage, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendFromChannel(ChannelReader<NetworkMessageHeader> channel,
|
||||||
|
CancellationToken token = default)
|
||||||
|
{
|
||||||
|
while (token.IsCancellationRequested == false && IsConnected)
|
||||||
|
{
|
||||||
|
var message = await channel.ReadAsync(token);
|
||||||
|
await Send(message, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsConnected => _ioStream is { CanRead: true, CanWrite: true } && _manualConnectionState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Implementation
|
|
||||||
{
|
|
||||||
public class ComplexContextRepository : IContextRepository
|
|
||||||
{
|
|
||||||
private List<KeyValuePair<int, ExtensibleStorage<object>>> _storages = new();
|
|
||||||
public static object[] EventBinders = { };
|
|
||||||
|
|
||||||
private IRemoteObjectFactory? _remoteObjectFactory;
|
|
||||||
private IRepresentationModuleProducer? _representationModuleProducer;
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
|
||||||
if (dependency is IRemoteObjectFactory remoteObjectFactory)
|
|
||||||
{
|
|
||||||
_remoteObjectFactory = remoteObjectFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dependency is IRepresentationModuleProducer moduleProducer)
|
|
||||||
{
|
|
||||||
_representationModuleProducer = moduleProducer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int HostId { get; set; }
|
|
||||||
|
|
||||||
public int ResisterObject<T>(object o, IEndPointContext context)
|
|
||||||
{
|
|
||||||
var storageIndex = _storages.FindIndex(i => i.Key == context.OwnerId);
|
|
||||||
if (storageIndex == -1)
|
|
||||||
{
|
|
||||||
_storages.Add(
|
|
||||||
new KeyValuePair<int, ExtensibleStorage<object>>(context.OwnerId, new ExtensibleStorage<object>()));
|
|
||||||
storageIndex = _storages.Count - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var storage = _storages[storageIndex].Value;
|
|
||||||
|
|
||||||
var placedIndex = storage.Place(o);
|
|
||||||
EventBinders.OfType<IEventBinder<T>>().FirstOrDefault()
|
|
||||||
?.BindEvents((T)o, context, _representationModuleProducer!, placedIndex);
|
|
||||||
|
|
||||||
return placedIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearObject(ComplexObjectIdentifier id)
|
|
||||||
{
|
|
||||||
_storages.Find(i => i.Key == id.OwnerId).Value.Free(id.ContextId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetObject<T>(ComplexObjectIdentifier id)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetSingleObject(Type type, int ownerId)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetObjectIndex<T>(object o, IEndPointContext context)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,7 +32,7 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
public ulong Flat
|
public ulong Flat
|
||||||
{
|
{
|
||||||
get => (ulong)OwnerId << 32 | (uint)ContextId;
|
get => (ulong)((long)OwnerId << 32 | (uint)ContextId);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
OwnerId = (int)(value >> 32);
|
OwnerId = (int)(value >> 32);
|
||||||
|
|||||||
@@ -12,5 +12,6 @@ namespace mROA.Implementation
|
|||||||
ClientRecovery,
|
ClientRecovery,
|
||||||
ClientConnect,
|
ClientConnect,
|
||||||
ClientDisconnect,
|
ClientDisconnect,
|
||||||
|
UntrustedConnect,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,27 @@
|
|||||||
using System;
|
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation.Backend;
|
||||||
|
|
||||||
namespace mROA.Implementation
|
namespace mROA.Implementation
|
||||||
{
|
{
|
||||||
public class EndPointContext : IEndPointContext
|
public class EndPointContext : IEndPointContext
|
||||||
{
|
{
|
||||||
public Func<int> OwnerFunc;
|
public IInstanceRepository RealRepository { get; set; }
|
||||||
public IContextRepository RealRepository { get; set; }
|
public IInstanceRepository RemoteRepository { get; set; }
|
||||||
public IContextRepository RemoteRepository { get; set; }
|
|
||||||
public int HostId { get; set; }
|
public int HostId { get; set; }
|
||||||
|
|
||||||
public int OwnerId
|
public int OwnerId { get; set; }
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
get => OwnerFunc();
|
switch (dependency)
|
||||||
// ReSharper disable once UnusedMember.Global
|
{
|
||||||
set { OwnerFunc = () => value; }
|
case RemoteInstanceRepository remoteRepository:
|
||||||
|
RemoteRepository = remoteRepository;
|
||||||
|
break;
|
||||||
|
case InstanceRepository realRepository:
|
||||||
|
RealRepository = realRepository;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Abstract
|
namespace mROA.Implementation
|
||||||
{
|
{
|
||||||
public class EventBinder<T> : IEventBinder<T>
|
public class EventBinder<T> : IEventBinder<T>
|
||||||
{
|
{
|
||||||
public Action<T, IEndPointContext, IRepresentationModuleProducer, int> BindAction { get; set; }
|
public Action<T, IEndPointContext, IRepresentationModuleProducer, int> BindAction { get; set; } = (_, _, _, _) => { };
|
||||||
|
|
||||||
public void BindEvents(T source, IEndPointContext context,
|
public void BindEvents(T source, IEndPointContext context,
|
||||||
IRepresentationModuleProducer representationModuleProducer, int index)
|
IRepresentationModuleProducer representationModuleProducer, int index)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using Exception = System.Exception;
|
using Exception = System.Exception;
|
||||||
@@ -11,28 +12,35 @@ namespace mROA.Implementation.Frontend
|
|||||||
{
|
{
|
||||||
private readonly IPEndPoint _serverEndPoint;
|
private readonly IPEndPoint _serverEndPoint;
|
||||||
private TcpClient _tcpClient = new();
|
private TcpClient _tcpClient = new();
|
||||||
private NextGenerationInteractionModule? _interactionModule;
|
private IChannelInteractionModule? _interactionModule;
|
||||||
private ISerializationToolkit? _serialization;
|
private IContextualSerializationToolKit? _serialization;
|
||||||
|
private ChannelInteractionModule.StreamExtractor _currentExtractor;
|
||||||
|
private CancellationTokenSource _rawExtractorCancellation;
|
||||||
|
private IEndPointContext _context;
|
||||||
|
|
||||||
public NetworkFrontendBridge(IPEndPoint serverEndPoint)
|
public NetworkFrontendBridge(IPEndPoint serverEndPoint)
|
||||||
{
|
{
|
||||||
_serverEndPoint = serverEndPoint;
|
_serverEndPoint = serverEndPoint;
|
||||||
|
_rawExtractorCancellation = new CancellationTokenSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
switch (dependency)
|
switch (dependency)
|
||||||
{
|
{
|
||||||
case NextGenerationInteractionModule interactionModule:
|
case ChannelInteractionModule interactionModule:
|
||||||
_interactionModule = interactionModule;
|
_interactionModule = interactionModule;
|
||||||
break;
|
break;
|
||||||
case ISerializationToolkit toolkit:
|
case IContextualSerializationToolKit toolkit:
|
||||||
_serialization = toolkit;
|
_serialization = toolkit;
|
||||||
break;
|
break;
|
||||||
|
case IEndPointContext endPointContext:
|
||||||
|
_context = endPointContext;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Connect()
|
public async Task Connect()
|
||||||
{
|
{
|
||||||
if (_interactionModule is null)
|
if (_interactionModule is null)
|
||||||
throw new Exception("Interaction module was not injected");
|
throw new Exception("Interaction module was not injected");
|
||||||
@@ -41,15 +49,16 @@ namespace mROA.Implementation.Frontend
|
|||||||
|
|
||||||
_tcpClient.Connect(_serverEndPoint);
|
_tcpClient.Connect(_serverEndPoint);
|
||||||
|
|
||||||
_interactionModule.BaseStream = _tcpClient.GetStream();
|
PrepareExtractor();
|
||||||
|
_interactionModule.IsConnected = () => _currentExtractor.IsConnected;
|
||||||
|
_interactionModule.OnDisconnected += _ => { Reconnect(); };
|
||||||
|
|
||||||
_interactionModule.OnDisconected += id =>
|
_interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect(), _context))
|
||||||
{
|
.Wait();
|
||||||
Reconnect();
|
|
||||||
};
|
_currentExtractor.SingleReceive();
|
||||||
|
var idMessage = await _interactionModule.GetNextMessageReceiving(false);
|
||||||
|
|
||||||
_interactionModule.PostMessageAsync(new NetworkMessageHeader(_serialization, new ClientConnect())).Wait();
|
|
||||||
var idMessage = _interactionModule.GetNextMessageReceiving(false).GetAwaiter().GetResult();
|
|
||||||
if (idMessage.MessageType != EMessageType.IdAssigning)
|
if (idMessage.MessageType != EMessageType.IdAssigning)
|
||||||
{
|
{
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
@@ -57,28 +66,51 @@ namespace mROA.Implementation.Frontend
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var assignment = _serialization.Deserialize<IdAssignment>(idMessage.Data)!;
|
Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||||
|
|
||||||
|
var assignment = _serialization.Deserialize<IdAssignment>(idMessage.Data, _context);
|
||||||
_interactionModule.ConnectionId = -assignment.Id;
|
_interactionModule.ConnectionId = -assignment.Id;
|
||||||
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id);
|
_context.HostId = assignment.Id;
|
||||||
|
_context.OwnerId = assignment.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareExtractor()
|
||||||
|
{
|
||||||
|
_currentExtractor =
|
||||||
|
new ChannelInteractionModule.StreamExtractor(_tcpClient.GetStream(), _serialization!, _context);
|
||||||
|
|
||||||
|
_ = _currentExtractor.SendFromChannel(_interactionModule!.TrustedPostChanel,
|
||||||
|
_rawExtractorCancellation.Token);
|
||||||
|
_currentExtractor.MessageReceived = message =>
|
||||||
|
{
|
||||||
|
_interactionModule.ReceiveChanel.Writer.WriteAsync(message);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Reconnect()
|
private async Task Reconnect()
|
||||||
{
|
{
|
||||||
_tcpClient = new TcpClient();
|
_tcpClient = new TcpClient();
|
||||||
_tcpClient.Connect(_serverEndPoint);
|
_tcpClient.Connect(_serverEndPoint);
|
||||||
_interactionModule.BaseStream = _tcpClient.GetStream();
|
|
||||||
|
_rawExtractorCancellation.Cancel();
|
||||||
|
_rawExtractorCancellation = new CancellationTokenSource();
|
||||||
|
|
||||||
|
PrepareExtractor();
|
||||||
|
|
||||||
|
Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
|
||||||
|
|
||||||
await _interactionModule.Restart(true);
|
await _interactionModule.Restart(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Obstacle()
|
public void Obstacle()
|
||||||
{
|
{
|
||||||
_interactionModule!.BaseStream!.Dispose();
|
|
||||||
_tcpClient.Dispose();
|
_tcpClient.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect()
|
public void Disconnect()
|
||||||
{
|
{
|
||||||
_ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect()));
|
_ = _interactionModule!.PostMessageAsync(new NetworkMessageHeader(_serialization!, new ClientDisconnect(),
|
||||||
|
_context));
|
||||||
_interactionModule.Dispose();
|
_interactionModule.Dispose();
|
||||||
_tcpClient.Dispose();
|
_tcpClient.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.Backend;
|
|
||||||
using mROA.Implementation.CommandExecution;
|
|
||||||
|
|
||||||
// ReSharper disable MethodHasAsyncOverload
|
// ReSharper disable MethodHasAsyncOverload
|
||||||
|
|
||||||
@@ -13,11 +10,12 @@ namespace mROA.Implementation.Frontend
|
|||||||
public class RequestExtractor : IRequestExtractor
|
public class RequestExtractor : IRequestExtractor
|
||||||
{
|
{
|
||||||
private IExecuteModule? _executeModule;
|
private IExecuteModule? _executeModule;
|
||||||
|
|
||||||
private IMethodRepository? _methodRepository;
|
private IMethodRepository? _methodRepository;
|
||||||
private IContextRepository? _realContextRepository;
|
|
||||||
private IContextRepository? _remoteContextRepository;
|
|
||||||
private IRepresentationModule? _representationModule;
|
private IRepresentationModule? _representationModule;
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
private IContextualSerializationToolKit? _serializationToolkit;
|
||||||
|
private IEndPointContext _context;
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
@@ -26,93 +24,64 @@ namespace mROA.Implementation.Frontend
|
|||||||
case IExecuteModule executeModule:
|
case IExecuteModule executeModule:
|
||||||
_executeModule = executeModule;
|
_executeModule = executeModule;
|
||||||
break;
|
break;
|
||||||
case MultiClientContextRepository:
|
|
||||||
case ContextRepository:
|
|
||||||
_realContextRepository = dependency as IContextRepository;
|
|
||||||
break;
|
|
||||||
case RemoteContextRepository remoteContextRepository:
|
|
||||||
_remoteContextRepository = remoteContextRepository;
|
|
||||||
break;
|
|
||||||
case IMethodRepository methodRepository:
|
case IMethodRepository methodRepository:
|
||||||
_methodRepository = methodRepository;
|
_methodRepository = methodRepository;
|
||||||
break;
|
break;
|
||||||
case IRepresentationModule representationModule:
|
case IRepresentationModule representationModule:
|
||||||
_representationModule = representationModule;
|
_representationModule = representationModule;
|
||||||
break;
|
break;
|
||||||
case ISerializationToolkit serializationToolkit:
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
_serializationToolkit = serializationToolkit;
|
_serializationToolkit = serializationToolkit;
|
||||||
break;
|
break;
|
||||||
|
case IEndPointContext remoteContext:
|
||||||
|
_context = remoteContext;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StartExtraction()
|
public async Task StartExtraction()
|
||||||
{
|
{
|
||||||
return Task.Run(() =>
|
ThrowIfNotInjected();
|
||||||
{
|
|
||||||
ThrowIfNotInjected();
|
|
||||||
var multiClientOwnershipRepository =
|
|
||||||
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
|
||||||
multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
|
|
||||||
|
|
||||||
try
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
var streamTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var query = _representationModule!.GetStream(m =>
|
||||||
|
m.MessageType is EMessageType.CallRequest or EMessageType.CancelRequest
|
||||||
|
or EMessageType.EventRequest or EMessageType.ClientDisconnect, _context,
|
||||||
|
streamTokenSource.Token,
|
||||||
|
m => m.MessageType == EMessageType.CallRequest ? typeof(DefaultCallRequest) : null,
|
||||||
|
m => m.MessageType == EMessageType.CancelRequest ? typeof(CancelRequest) : null,
|
||||||
|
m => m.MessageType == EMessageType.EventRequest ? typeof(DefaultCallRequest) : null,
|
||||||
|
m => m.MessageType == EMessageType.ClientDisconnect ? typeof(ClientDisconnect) : null);
|
||||||
|
|
||||||
|
|
||||||
|
await foreach (var command in query)
|
||||||
{
|
{
|
||||||
#if TRACE
|
switch (command.originalType)
|
||||||
var sw = new Stopwatch();
|
|
||||||
#endif
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
#if TRACE
|
case EMessageType.CallRequest:
|
||||||
Console.WriteLine("Waiting for request...");
|
HandleCallRequest((command.parced as DefaultCallRequest)!);
|
||||||
if (sw.IsRunning)
|
|
||||||
{
|
|
||||||
sw.Stop();
|
|
||||||
Console.WriteLine($"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
var tokenSource = new CancellationTokenSource();
|
|
||||||
var token = tokenSource.Token;
|
|
||||||
var defaultRequest =
|
|
||||||
_representationModule!.GetMessageAsync<DefaultCallRequest>(
|
|
||||||
messageType: EMessageType.CallRequest, token: token);
|
|
||||||
var cancelRequest =
|
|
||||||
_representationModule!.GetMessageAsync<CancelRequest>(
|
|
||||||
messageType: EMessageType.CancelRequest, token: token);
|
|
||||||
var eventRequest =
|
|
||||||
_representationModule!.GetMessageAsync<DefaultCallRequest>(
|
|
||||||
messageType: EMessageType.EventRequest, token: token);
|
|
||||||
var disconnectRequest =
|
|
||||||
_representationModule!.GetMessageAsync<ClientDisconnect>(
|
|
||||||
messageType: EMessageType.ClientDisconnect, token:token);
|
|
||||||
Task.WaitAny(defaultRequest, cancelRequest, eventRequest, disconnectRequest);
|
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine("Request received");
|
|
||||||
sw.Restart();
|
|
||||||
#endif
|
|
||||||
if (cancelRequest.IsCompleted)
|
|
||||||
{
|
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine("Cancelling request");
|
|
||||||
#endif
|
|
||||||
HandleCancelRequest(tokenSource, cancelRequest.Result);
|
|
||||||
}
|
|
||||||
else if (defaultRequest.IsCompleted)
|
|
||||||
{
|
|
||||||
HandleCallRequest(tokenSource, defaultRequest.Result);
|
|
||||||
}
|
|
||||||
else if(eventRequest.IsCompleted)
|
|
||||||
{
|
|
||||||
HandleEventRequest(tokenSource, eventRequest.Result);
|
|
||||||
}else if (disconnectRequest.IsCompleted)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
case EMessageType.ClientDisconnect:
|
||||||
|
return;
|
||||||
|
case EMessageType.EventRequest:
|
||||||
|
HandleEventRequest((command.parced as DefaultCallRequest)!);
|
||||||
|
break;
|
||||||
|
case EMessageType.CancelRequest:
|
||||||
|
HandleCancelRequest((command.parced as CancelRequest)!);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
}
|
||||||
{
|
catch
|
||||||
multiClientOwnershipRepository?.FreeOwnership();
|
{
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ThrowIfNotInjected()
|
private void ThrowIfNotInjected()
|
||||||
@@ -121,25 +90,20 @@ namespace mROA.Implementation.Frontend
|
|||||||
throw new NullReferenceException("Serializing toolkit is null.");
|
throw new NullReferenceException("Serializing toolkit is null.");
|
||||||
if (_executeModule == null)
|
if (_executeModule == null)
|
||||||
throw new NullReferenceException("Execute module is null.");
|
throw new NullReferenceException("Execute module is null.");
|
||||||
if (_realContextRepository == null)
|
|
||||||
throw new NullReferenceException("Context repository is null.");
|
|
||||||
if (_representationModule == null)
|
if (_representationModule == null)
|
||||||
throw new NullReferenceException("Representation module is null.");
|
throw new NullReferenceException("Representation module is null.");
|
||||||
if (_methodRepository == null)
|
if (_methodRepository == null)
|
||||||
throw new NullReferenceException("Method repository is null.");
|
throw new NullReferenceException("Method repository is null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCancelRequest(CancellationTokenSource tokenSource, CancelRequest req)
|
private void HandleCancelRequest(CancelRequest req)
|
||||||
{
|
{
|
||||||
tokenSource.Cancel();
|
_executeModule!.Execute(req, _context.RealRepository, _representationModule!, _context);
|
||||||
_executeModule!.Execute(req, _realContextRepository!, _representationModule!);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleCallRequest(CancellationTokenSource tokenSource, DefaultCallRequest request)
|
private void HandleCallRequest(DefaultCallRequest request)
|
||||||
{
|
{
|
||||||
tokenSource.Cancel();
|
var result = _executeModule!.Execute(request, _context.RealRepository, _representationModule!, _context);
|
||||||
|
|
||||||
var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!);
|
|
||||||
|
|
||||||
var resultType = result.MessageType;
|
var resultType = result.MessageType;
|
||||||
|
|
||||||
@@ -148,13 +112,12 @@ namespace mROA.Implementation.Frontend
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType());
|
_representationModule!.PostCallMessage(request.Id, resultType, result, _context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleEventRequest(CancellationTokenSource tokenSource, DefaultCallRequest request)
|
private void HandleEventRequest(DefaultCallRequest request)
|
||||||
{
|
{
|
||||||
tokenSource.Cancel();
|
_executeModule!.Execute(request, _context.RemoteRepository, _representationModule!, _context);
|
||||||
_executeModule!.Execute(request, _remoteContextRepository!, _representationModule!);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.Frontend
|
||||||
|
{
|
||||||
|
public class UdpUntrustedInteraction : IUntrustedInteractionModule
|
||||||
|
{
|
||||||
|
private IContextualSerializationToolKit _serializationToolkit;
|
||||||
|
private IChannelInteractionModule _channelInteractionModule;
|
||||||
|
private CancellationTokenSource _tokenSource = new();
|
||||||
|
private IEndPointContext _context;
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_tokenSource.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task Start(IPEndPoint endpoint)
|
||||||
|
{
|
||||||
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
var client = new UdpClient();
|
||||||
|
client.Connect(endpoint);
|
||||||
|
Listening(client, _tokenSource.Token);
|
||||||
|
Posting(client, _tokenSource.Token);
|
||||||
|
}, _tokenSource.Token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Listening(UdpClient udpClient, CancellationToken token)
|
||||||
|
{
|
||||||
|
var writer = _channelInteractionModule.ReceiveChanel.Writer;
|
||||||
|
while (token.IsCancellationRequested == false)
|
||||||
|
{
|
||||||
|
var message = new Memory<byte>((await udpClient.ReceiveAsync()).Buffer);
|
||||||
|
var parsed = _serializationToolkit.Deserialize<NetworkMessageHeader>(message, _context);
|
||||||
|
|
||||||
|
await writer.WriteAsync(parsed, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Posting(UdpClient udpClient, CancellationToken token)
|
||||||
|
{
|
||||||
|
var initMessage = new NetworkMessageHeader
|
||||||
|
{
|
||||||
|
MessageType = EMessageType.UntrustedConnect, Id = Guid.NewGuid(),
|
||||||
|
Data = BitConverter.GetBytes(_channelInteractionModule.ConnectionId)
|
||||||
|
};
|
||||||
|
|
||||||
|
var initParsed = _serializationToolkit.Serialize(initMessage, _context);
|
||||||
|
|
||||||
|
await udpClient.SendAsync(initParsed, initParsed.Length);
|
||||||
|
|
||||||
|
await foreach (var post in _channelInteractionModule.UntrustedPostChanel.ReadAllAsync(token))
|
||||||
|
{
|
||||||
|
if (post.MessageType is not (EMessageType.CallRequest or EMessageType.CancelRequest
|
||||||
|
or EMessageType.EventRequest))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var serialized = _serializationToolkit.Serialize(post, _context);
|
||||||
|
|
||||||
|
await udpClient.SendAsync(serialized, serialized.Length);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
switch (dependency)
|
||||||
|
{
|
||||||
|
case IChannelInteractionModule channelModule:
|
||||||
|
_channelInteractionModule = channelModule;
|
||||||
|
break;
|
||||||
|
case IContextualSerializationToolKit serializationToolkit:
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
|
break;
|
||||||
|
case IEndPointContext endPointContext:
|
||||||
|
_context = endPointContext;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Text.Json;
|
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Implementation
|
|
||||||
{
|
|
||||||
public class JsonSerializationToolkit : ISerializationToolkit
|
|
||||||
{
|
|
||||||
public byte[] Serialize<T>(T objectToSerialize)
|
|
||||||
{
|
|
||||||
return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Serialize(object objectToSerialize, Type type)
|
|
||||||
{
|
|
||||||
return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T? Deserialize<T>(byte[] rawData)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize<T>(rawData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? Deserialize(byte[] rawData, Type type)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize(rawData, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T? Deserialize<T>(Span<byte> rawData)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize<T>(rawData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? Deserialize(Span<byte> rawData, Type type)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize(rawData, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T Cast<T>(object nonCasted)
|
|
||||||
{
|
|
||||||
return nonCasted switch
|
|
||||||
{
|
|
||||||
JsonElement jsonElement => jsonElement.Deserialize<T>()!,
|
|
||||||
T casted => casted,
|
|
||||||
_ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Cast(object nonCasted, Type type)
|
|
||||||
{
|
|
||||||
if (nonCasted is JsonElement jsonElement)
|
|
||||||
return jsonElement.Deserialize(type)!;
|
|
||||||
|
|
||||||
throw new JsonException("Cannot cast object to type " + type.FullName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,7 @@ namespace mROA.Implementation
|
|||||||
public class MethodInvoker : IMethodInvoker
|
public class MethodInvoker : IMethodInvoker
|
||||||
{
|
{
|
||||||
public bool IsVoid { get; set; }
|
public bool IsVoid { get; set; }
|
||||||
|
public bool IsTrusted { get; set; } = true;
|
||||||
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
|
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
|
||||||
public Type? ReturnType { get; set; }
|
public Type? ReturnType { get; set; }
|
||||||
public Func<object, object?[]?, object[], object?> Invoking { get; set; } = (_, _, _) => null;
|
public Func<object, object?[]?, object[], object?> Invoking { get; set; } = (_, _, _) => null;
|
||||||
@@ -32,9 +33,10 @@ namespace mROA.Implementation
|
|||||||
public class AsyncMethodInvoker : IMethodInvoker
|
public class AsyncMethodInvoker : IMethodInvoker
|
||||||
{
|
{
|
||||||
public bool IsVoid { get; set; }
|
public bool IsVoid { get; set; }
|
||||||
|
public bool IsTrusted { get; set; } = true;
|
||||||
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
|
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
|
||||||
public Type? ReturnType { get; set; }
|
public Type? ReturnType { get; set; }
|
||||||
public Type SuitableType { get; set; }
|
public Type SuitableType { get; set; } = typeof(object);
|
||||||
|
|
||||||
public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } =
|
public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } =
|
||||||
(_, _, _, post) => { post.Invoke(null); };
|
(_, _, _, post) => { post.Invoke(null); };
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
@@ -8,6 +7,19 @@ namespace mROA.Implementation
|
|||||||
{
|
{
|
||||||
public class NetworkMessageHeader
|
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 static readonly NetworkMessageHeader Null = new();
|
||||||
public NetworkMessageHeader()
|
public NetworkMessageHeader()
|
||||||
{
|
{
|
||||||
@@ -15,15 +27,15 @@ namespace mROA.Implementation
|
|||||||
MessageType = EMessageType.Unknown;
|
MessageType = EMessageType.Unknown;
|
||||||
Data = Array.Empty<byte>();
|
Data = Array.Empty<byte>();
|
||||||
}
|
}
|
||||||
public NetworkMessageHeader(ISerializationToolkit serializationToolkit, INetworkMessage networkMessage)
|
public NetworkMessageHeader(IContextualSerializationToolKit serializationToolkit,
|
||||||
|
INetworkMessage networkMessage, IEndPointContext? context)
|
||||||
{
|
{
|
||||||
MessageType = networkMessage.MessageType;
|
MessageType = networkMessage.MessageType;
|
||||||
Data = serializationToolkit.Serialize(networkMessage);
|
Data = serializationToolkit.Serialize(networkMessage, context);
|
||||||
Id = Guid.NewGuid();
|
Id = Guid.NewGuid();
|
||||||
}
|
}
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
|
|
||||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
|
||||||
public EMessageType MessageType { get; set; }
|
public EMessageType MessageType { get; set; }
|
||||||
|
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
|||||||
@@ -1,269 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Implementation
|
|
||||||
{
|
|
||||||
public class NextGenerationInteractionModule : INextGenerationInteractionModule
|
|
||||||
{
|
|
||||||
private int DebugId = new Random().Next();
|
|
||||||
private const int BufferSize = ushort.MaxValue;
|
|
||||||
private readonly Memory<byte> _buffer = new byte[BufferSize];
|
|
||||||
private readonly List<NetworkMessageHeader> _messageBuffer = new(128);
|
|
||||||
private Task<NetworkMessageHeader>? _currentReceiving;
|
|
||||||
private ISerializationToolkit? _serialization;
|
|
||||||
private Stream? _baseStream;
|
|
||||||
private bool _isConnected = true;
|
|
||||||
private bool _isInReconnectionState;
|
|
||||||
private bool _isActive = true;
|
|
||||||
private TaskCompletionSource<Stream> _reconnection;
|
|
||||||
|
|
||||||
public NextGenerationInteractionModule()
|
|
||||||
{
|
|
||||||
_reconnection = new TaskCompletionSource<Stream>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ConnectionId { get; set; }
|
|
||||||
|
|
||||||
public Stream? BaseStream
|
|
||||||
{
|
|
||||||
get => _baseStream; set => _baseStream = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
|
||||||
switch (dependency)
|
|
||||||
{
|
|
||||||
case ISerializationToolkit toolkit:
|
|
||||||
_serialization = toolkit;
|
|
||||||
break;
|
|
||||||
case IIdentityGenerator identityGenerator:
|
|
||||||
ConnectionId = identityGenerator.GetNextIdentity();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<NetworkMessageHeader> GetNextMessageReceiving(bool infinite = true)
|
|
||||||
{
|
|
||||||
if (!infinite) return Receive().AsTask();
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{DateTime.Now.TimeOfDay} Posting message: {messageHeader.Id} - {messageHeader.MessageType} to {ConnectionId}");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
var rawMessage = _serialization.Serialize(messageHeader);
|
|
||||||
var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort));
|
|
||||||
|
|
||||||
if (!_baseStream.CanWrite)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
await BaseStream.WriteAsync(header);
|
|
||||||
await BaseStream.WriteAsync(rawMessage);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#pragma warning restore CS8602 // Dereference of a possibly null reference.
|
|
||||||
|
|
||||||
|
|
||||||
public async Task PostMessageAsync(NetworkMessageHeader messageHeader)
|
|
||||||
{
|
|
||||||
if (BaseStream == null)
|
|
||||||
throw new NullReferenceException("BaseStream is null");
|
|
||||||
|
|
||||||
if (_serialization == null)
|
|
||||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
|
||||||
|
|
||||||
// Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message));
|
|
||||||
|
|
||||||
bool withError = false;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (withError)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Post again");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (await PostMessageInternal(messageHeader))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!_isActive)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_isConnected = false;
|
|
||||||
withError = true;
|
|
||||||
await MakeRecovery("OUT");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandleMessage(NetworkMessageHeader messageHeader)
|
|
||||||
{
|
|
||||||
_messageBuffer.Remove(messageHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NetworkMessageHeader[] UnhandledMessages => _messageBuffer.ToArray();
|
|
||||||
|
|
||||||
public NetworkMessageHeader? FirstByFilter(Predicate<NetworkMessageHeader> predicate)
|
|
||||||
{
|
|
||||||
return _messageBuffer.FirstOrDefault(m => predicate(m));
|
|
||||||
}
|
|
||||||
|
|
||||||
public event Action<int>? OnDisconected;
|
|
||||||
|
|
||||||
private async Task<NetworkMessageHeader> GetNextMessage()
|
|
||||||
{
|
|
||||||
if (BaseStream == null)
|
|
||||||
throw new NullReferenceException("BaseStream is null");
|
|
||||||
|
|
||||||
if (_serialization == null)
|
|
||||||
throw new NullReferenceException("Serialization toolkit is null");
|
|
||||||
|
|
||||||
bool withError = false;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (withError)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Receive again");
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var message = await Receive();
|
|
||||||
_currentReceiving = Task.Run(async () => await GetNextMessage());
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
if (!_isActive)
|
|
||||||
{
|
|
||||||
return NetworkMessageHeader.Null;
|
|
||||||
}
|
|
||||||
withError = true;
|
|
||||||
await MakeRecovery("IN");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ushort ReadMessageLength()
|
|
||||||
{
|
|
||||||
var firstBit = BaseStream.ReadByte();
|
|
||||||
if (firstBit == -1)
|
|
||||||
{
|
|
||||||
_isConnected = false;
|
|
||||||
throw new EndOfStreamException();
|
|
||||||
}
|
|
||||||
|
|
||||||
_isConnected = true;
|
|
||||||
var secondBit = (byte)BaseStream.ReadByte();
|
|
||||||
|
|
||||||
var len = BitConverter.ToUInt16(new[] { (byte)firstBit, secondBit });
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ValueTask<NetworkMessageHeader> Receive()
|
|
||||||
{
|
|
||||||
var len = ReadMessageLength();
|
|
||||||
var localSpan = _buffer[..len];
|
|
||||||
|
|
||||||
await BaseStream.ReadExactlyAsync(localSpan);
|
|
||||||
|
|
||||||
var message = _serialization.Deserialize<NetworkMessageHeader>(localSpan.Span);
|
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.MessageType}");
|
|
||||||
TransmissionConfig.TotalTransmittedBytes += len;
|
|
||||||
Console.WriteLine($"Total received bytes are {TransmissionConfig.TotalTransmittedBytes}");
|
|
||||||
#endif
|
|
||||||
_messageBuffer.Add(message);
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task Restart(bool sendRecovery)
|
|
||||||
{
|
|
||||||
if (sendRecovery)
|
|
||||||
{
|
|
||||||
await PostMessageAsync(
|
|
||||||
new NetworkMessageHeader(_serialization!, new ClientRecovery(Math.Abs(ConnectionId))));
|
|
||||||
var iTest = _baseStream.ReadByte();
|
|
||||||
var bTest = (byte)iTest;
|
|
||||||
_baseStream.WriteByte(bTest);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const byte confirmByte = 128;
|
|
||||||
_baseStream.WriteByte(confirmByte);
|
|
||||||
var iPong = _baseStream.ReadByte();
|
|
||||||
var bPong = (byte)iPong;
|
|
||||||
if (confirmByte != bPong)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Incorrect byte");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Setting result for reconnection");
|
|
||||||
var setting = _reconnection.TrySetResult(BaseStream);
|
|
||||||
_isInReconnectionState = false;
|
|
||||||
_isConnected = true;
|
|
||||||
Console.WriteLine($"Set result for reconnection {setting}");
|
|
||||||
|
|
||||||
_reconnection = new TaskCompletionSource<Stream>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task MakeRecovery(string source)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Staring recovery from {0}", source);
|
|
||||||
|
|
||||||
lock (_reconnection)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Got lock from {0}", source);
|
|
||||||
if (_isConnected || _isInReconnectionState)
|
|
||||||
{
|
|
||||||
Console.WriteLine(
|
|
||||||
$"{source} {_isConnected} {_isInReconnectionState} {!_baseStream.CanRead} {!_baseStream.CanWrite}");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Call OnDisconnected from {0}", source);
|
|
||||||
_isInReconnectionState = true;
|
|
||||||
OnDisconected?.Invoke(ConnectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Waiting for reconnect from {0}", source);
|
|
||||||
if (!_reconnection.Task.IsCompleted && !_isConnected)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Current connection state {0} from {1}", _isConnected, source);
|
|
||||||
await _reconnection.Task;
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Reconnect finished from {0}", source);
|
|
||||||
lock (_reconnection)
|
|
||||||
{
|
|
||||||
_isInReconnectionState = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Console.WriteLine("Interaction module disposed");
|
|
||||||
_isActive = false;
|
|
||||||
if (_currentReceiving is { IsCompleted: true })
|
|
||||||
{
|
|
||||||
_currentReceiving?.Dispose();
|
|
||||||
}
|
|
||||||
_baseStream?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+13
-8
@@ -5,7 +5,7 @@ using mROA.Abstract;
|
|||||||
|
|
||||||
namespace mROA.Implementation
|
namespace mROA.Implementation
|
||||||
{
|
{
|
||||||
public class RemoteContextRepository : IContextRepository
|
public class RemoteInstanceRepository : IInstanceRepository
|
||||||
{
|
{
|
||||||
private List<RemoteObjectBase> _producedRemoteEndpoints = new();
|
private List<RemoteObjectBase> _producedRemoteEndpoints = new();
|
||||||
public static Dictionary<Type, Type> RemoteTypes = new();
|
public static Dictionary<Type, Type> RemoteTypes = new();
|
||||||
@@ -18,12 +18,12 @@ namespace mROA.Implementation
|
|||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearObject(ComplexObjectIdentifier id)
|
public void ClearObject(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetObject<T>(ComplexObjectIdentifier id)
|
public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
{
|
{
|
||||||
var index = _producedRemoteEndpoints.Find(i => i.Identifier.Equals(id));
|
var index = _producedRemoteEndpoints.Find(i => i.Identifier.Equals(id));
|
||||||
if (index is not null)
|
if (index is not null)
|
||||||
@@ -33,25 +33,30 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
|
if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
|
||||||
var representationModule =
|
var representationModule =
|
||||||
_representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
_representationProducer.Produce(context.OwnerId);
|
||||||
var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
|
var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
|
||||||
representationModule)!;
|
representationModule, context)!;
|
||||||
|
|
||||||
_producedRemoteEndpoints.Add((remote as RemoteObjectBase)!);
|
_producedRemoteEndpoints.Add((remote as RemoteObjectBase)!);
|
||||||
|
|
||||||
return remote;
|
return remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object GetSingleObject(Type type, int ownerId)
|
public T GetSingletonObject<T>(IEndPointContext context) where T : class, IShared
|
||||||
|
{
|
||||||
|
return GetSingletonObject(typeof(T), context) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetSingletonObject(Type type, IEndPointContext context)
|
||||||
{
|
{
|
||||||
if (_representationProducer == null)
|
if (_representationProducer == null)
|
||||||
throw new NullReferenceException("representation producer is not initialized");
|
throw new NullReferenceException("representation producer is not initialized");
|
||||||
|
|
||||||
var representationModule =
|
var representationModule =
|
||||||
_representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
_representationProducer.Produce(context.OwnerId);
|
||||||
|
|
||||||
_producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1,
|
_producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1,
|
||||||
representationModule) as RemoteObjectBase)!);
|
representationModule, context) as RemoteObjectBase)!);
|
||||||
|
|
||||||
return _producedRemoteEndpoints.Last();
|
return _producedRemoteEndpoints.Last();
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,9 @@ namespace mROA.Implementation
|
|||||||
{
|
{
|
||||||
public abstract class RemoteObjectBase : IDisposable
|
public abstract class RemoteObjectBase : IDisposable
|
||||||
{
|
{
|
||||||
protected bool Equals(RemoteObjectBase other)
|
private readonly IEndPointContext _context;
|
||||||
|
|
||||||
|
public bool Equals(RemoteObjectBase other)
|
||||||
{
|
{
|
||||||
return _identifier.Equals(other._identifier);
|
return _identifier.Equals(other._identifier);
|
||||||
}
|
}
|
||||||
@@ -31,10 +33,11 @@ namespace mROA.Implementation
|
|||||||
private readonly ComplexObjectIdentifier _identifier;
|
private readonly ComplexObjectIdentifier _identifier;
|
||||||
private readonly IRepresentationModule _representationModule;
|
private readonly IRepresentationModule _representationModule;
|
||||||
|
|
||||||
protected RemoteObjectBase(int id, IRepresentationModule representationModule)
|
protected RemoteObjectBase(int id, IRepresentationModule representationModule, IEndPointContext context)
|
||||||
{
|
{
|
||||||
_identifier = new ComplexObjectIdentifier { ContextId = id, OwnerId = representationModule.Id };
|
_identifier = new ComplexObjectIdentifier { ContextId = id, OwnerId = representationModule.Id };
|
||||||
_representationModule = representationModule;
|
_representationModule = representationModule;
|
||||||
|
_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Id => _identifier.ContextId;
|
public int Id => _identifier.ContextId;
|
||||||
@@ -56,44 +59,40 @@ namespace mROA.Implementation
|
|||||||
CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||||
};
|
};
|
||||||
|
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request);
|
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context);
|
||||||
|
|
||||||
var localTokenSource = new CancellationTokenSource();
|
var localTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
var successResponse =
|
var responseRequestTask = _representationModule.GetSingle(
|
||||||
_representationModule.GetMessageAsync<FinalCommandExecution<T>>(request.Id,
|
m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, _context,
|
||||||
EMessageType.FinishedCommandExecution,
|
localTokenSource.Token,
|
||||||
localTokenSource.Token);
|
m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution<T>) : null,
|
||||||
var errorResponse =
|
m => m.MessageType is EMessageType.ExceptionCommandExecution
|
||||||
_representationModule.GetMessageAsync<ExceptionCommandExecution>(requestId: request.Id,
|
? typeof(ExceptionCommandExecution)
|
||||||
EMessageType.ExceptionCommandExecution, localTokenSource.Token);
|
: null);
|
||||||
|
|
||||||
cancellationToken.Register(async () =>
|
cancellationToken.Register(() =>
|
||||||
{
|
{
|
||||||
#if TRACE
|
#if TRACE
|
||||||
Console.WriteLine("Cancelling task");
|
Console.WriteLine("Cancelling task");
|
||||||
#endif
|
#endif
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest,
|
_representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest,
|
||||||
new CancelRequest
|
new CancelRequest
|
||||||
{
|
{
|
||||||
Id = request.Id
|
Id = request.Id
|
||||||
});
|
}, _context).ContinueWith(_ => localTokenSource.Cancel());
|
||||||
localTokenSource.Cancel();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Task.WaitAny(new Task[]
|
var response = await responseRequestTask;
|
||||||
{
|
|
||||||
successResponse, errorResponse
|
|
||||||
}, cancellationToken);
|
|
||||||
|
|
||||||
if (successResponse.IsCompletedSuccessfully)
|
if (response.Deserialized is FinalCommandExecution<T> successResponse)
|
||||||
{
|
{
|
||||||
localTokenSource.Cancel();
|
localTokenSource.Cancel();
|
||||||
return successResponse.Result.Result!;
|
return successResponse.Result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
localTokenSource.Cancel();
|
localTokenSource.Cancel();
|
||||||
throw errorResponse.Result.GetException();
|
throw (response.Deserialized as ExceptionCommandExecution)!.GetException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task CallAsync(int methodId, object?[]? parameters = null,
|
protected async Task CallAsync(int methodId, object?[]? parameters = null,
|
||||||
@@ -103,44 +102,52 @@ namespace mROA.Implementation
|
|||||||
{
|
{
|
||||||
CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||||
};
|
};
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request);
|
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request, _context);
|
||||||
|
|
||||||
var localTokenSource = new CancellationTokenSource();
|
var localTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
var successResponse =
|
var responseRequestTask = _representationModule.GetSingle(
|
||||||
_representationModule.GetMessageAsync<FinalCommandExecution>(request.Id,
|
m => m.MessageType is EMessageType.FinishedCommandExecution or EMessageType.ExceptionCommandExecution, _context,
|
||||||
EMessageType.FinishedCommandExecution,
|
localTokenSource.Token,
|
||||||
localTokenSource.Token);
|
m => m.MessageType is EMessageType.FinishedCommandExecution ? typeof(FinalCommandExecution) : null,
|
||||||
var errorResponse =
|
m => m.MessageType is EMessageType.ExceptionCommandExecution
|
||||||
_representationModule.GetMessageAsync<ExceptionCommandExecution>(requestId: request.Id,
|
? typeof(ExceptionCommandExecution)
|
||||||
EMessageType.ExceptionCommandExecution, localTokenSource.Token);
|
: null);
|
||||||
|
|
||||||
cancellationToken.Register(async () =>
|
|
||||||
|
cancellationToken.Register(() =>
|
||||||
{
|
{
|
||||||
#if TRACE
|
#if TRACE
|
||||||
Console.WriteLine("Cancelling task");
|
Console.WriteLine("Cancelling task");
|
||||||
#endif
|
#endif
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest,
|
_representationModule.PostCallMessageAsync(request.Id, EMessageType.CancelRequest,
|
||||||
new CancelRequest
|
new CancelRequest
|
||||||
{
|
{
|
||||||
Id = request.Id
|
Id = request.Id
|
||||||
});
|
}, _context).ContinueWith(_ => localTokenSource.Cancel());
|
||||||
localTokenSource.Cancel();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Task.WaitAny(new Task[]
|
var responseRequest = await responseRequestTask;
|
||||||
{
|
|
||||||
errorResponse, successResponse
|
|
||||||
}, cancellationToken);
|
|
||||||
|
|
||||||
#if TRACE
|
#if TRACE
|
||||||
Console.WriteLine($"Handling message");
|
Console.WriteLine($"Handling message");
|
||||||
#endif
|
#endif
|
||||||
if (successResponse.IsCompletedSuccessfully)
|
switch (responseRequest.MessageType)
|
||||||
return;
|
{
|
||||||
|
case EMessageType.FinishedCommandExecution:
|
||||||
|
return;
|
||||||
|
case EMessageType.ExceptionCommandExecution:
|
||||||
|
throw (responseRequest.Deserialized as ExceptionCommandExecution)!.GetException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (errorResponse.IsCompletedSuccessfully)
|
protected async Task CallUntrustedAsync(int methodId, object?[]? parameters = null)
|
||||||
throw errorResponse.Result.GetException();
|
{
|
||||||
|
var request = new DefaultCallRequest
|
||||||
|
{
|
||||||
|
CommandId = methodId, ObjectId = _identifier, Parameters = parameters
|
||||||
|
};
|
||||||
|
await _representationModule.PostCallMessageUntrustedAsync(request.Id, EMessageType.CallRequest, request,
|
||||||
|
_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ namespace mROA.Implementation
|
|||||||
public static Dictionary<Type, Type> RemoteTypes = new();
|
public static Dictionary<Type, Type> RemoteTypes = new();
|
||||||
private IRepresentationModuleProducer? _representationProducer;
|
private IRepresentationModuleProducer? _representationProducer;
|
||||||
|
|
||||||
public T Produce<T>(ComplexObjectIdentifier id)
|
public T Produce<T>(ComplexObjectIdentifier id, IEndPointContext context)
|
||||||
{
|
{
|
||||||
if (_representationProducer == null)
|
if (_representationProducer == null)
|
||||||
throw new NullReferenceException("representation producer is not initialized");
|
throw new NullReferenceException("representation producer is not initialized");
|
||||||
|
|
||||||
if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
|
if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
|
||||||
var representationModule =
|
var representationModule =
|
||||||
_representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
_representationProducer.Produce(context.OwnerId);
|
||||||
var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
|
var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
|
||||||
representationModule)!;
|
representationModule)!;
|
||||||
return remote;
|
return remote;
|
||||||
|
|||||||
@@ -1,111 +1,110 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
#pragma warning disable CS8602 // Dereference of a possibly null reference.
|
||||||
|
|
||||||
namespace mROA.Implementation
|
namespace mROA.Implementation
|
||||||
{
|
{
|
||||||
public class RepresentationModule : IRepresentationModule
|
public class RepresentationModule : IRepresentationModule
|
||||||
{
|
{
|
||||||
private INextGenerationInteractionModule? _interaction;
|
private IChannelInteractionModule? _interaction;
|
||||||
private ISerializationToolkit? _serialization;
|
private IContextualSerializationToolKit? _serialization;
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
switch (dependency)
|
switch (dependency)
|
||||||
{
|
{
|
||||||
case ISerializationToolkit toolkit:
|
case IContextualSerializationToolKit toolkit:
|
||||||
_serialization = toolkit;
|
_serialization = toolkit;
|
||||||
break;
|
break;
|
||||||
case INextGenerationInteractionModule interactionModule:
|
case IChannelInteractionModule interactionModule:
|
||||||
_interaction = interactionModule;
|
_interaction = interactionModule;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized"))
|
public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized"))
|
||||||
.ConnectionId;
|
.ConnectionId;
|
||||||
|
|
||||||
public async Task<T> GetMessageAsync<T>(Guid? requestId, EMessageType? messageType,
|
public async Task<(object? Deserialized, EMessageType MessageType)> GetSingle(
|
||||||
CancellationToken token = default)
|
Predicate<NetworkMessageHeader> rule, IEndPointContext? context,
|
||||||
|
CancellationToken token = default, params Func<NetworkMessageHeader, Type?>[] converter)
|
||||||
{
|
{
|
||||||
if (_serialization == null)
|
var writer = _interaction.ReceiveChanel.Writer;
|
||||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
var reader = _interaction.ReceiveChanel.Reader;
|
||||||
|
|
||||||
var rawMessage = await GetRawMessage(requestId, messageType, token);
|
|
||||||
return _serialization.Deserialize<T>(rawMessage)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetMessage<T>(Guid? requestId = null, EMessageType? messageType = null)
|
await foreach (var message in reader.ReadAllAsync(token))
|
||||||
{
|
|
||||||
if (_serialization == null)
|
|
||||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
|
||||||
|
|
||||||
var rawMessage = GetRawMessage(requestId, messageType).GetAwaiter().GetResult();
|
|
||||||
return _serialization.Deserialize<T>(rawMessage)!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<byte[]> GetRawMessage(Guid? requestId = null, EMessageType? messageType = null,
|
|
||||||
CancellationToken token = default)
|
|
||||||
{
|
|
||||||
if (_interaction == null)
|
|
||||||
throw new NullReferenceException("Interaction toolkit is not initialized");
|
|
||||||
|
|
||||||
var fromBuffer =
|
|
||||||
_interaction.FirstByFilter(message =>
|
|
||||||
(requestId is null || message.Id == requestId) &&
|
|
||||||
(messageType is null || message.MessageType == messageType));
|
|
||||||
|
|
||||||
if (fromBuffer == null)
|
|
||||||
{
|
{
|
||||||
while (token.IsCancellationRequested == false)
|
if (!rule(message))
|
||||||
{
|
{
|
||||||
var message = await _interaction.GetNextMessageReceiving();
|
await writer.WriteAsync(message, token);
|
||||||
if ((requestId is not null && message.Id != requestId) ||
|
continue;
|
||||||
(messageType is not null && message.MessageType != messageType))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
_interaction.HandleMessage(message);
|
|
||||||
return message.Data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var type = converter.Select(i => i(message)).First(i => i != null)!;
|
||||||
|
var deserialized = _serialization.Deserialize(message.Data, type, context);
|
||||||
|
return (deserialized, message.MessageType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fromBuffer == null)
|
return (null, EMessageType.Unknown);
|
||||||
{
|
|
||||||
return Array.Empty<byte>();
|
|
||||||
}
|
|
||||||
|
|
||||||
_interaction.HandleMessage(fromBuffer);
|
|
||||||
return fromBuffer.Data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull
|
public async IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(
|
||||||
|
Predicate<NetworkMessageHeader> rule, IEndPointContext? context,
|
||||||
|
[EnumeratorCancellation] CancellationToken token = default,
|
||||||
|
params Func<NetworkMessageHeader, Type?>[] converter)
|
||||||
{
|
{
|
||||||
await PostCallMessageAsync(id, eMessageType, payload, typeof(T));
|
var writer = _interaction?.ReceiveChanel.Writer;
|
||||||
|
await foreach (var message in _interaction.ReceiveChanel.Reader.ReadAllAsync(token))
|
||||||
|
{
|
||||||
|
if (!rule(message))
|
||||||
|
{
|
||||||
|
await writer.WriteAsync(message, token);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = converter.Select(i => i(message)).First(i => i != null)!;
|
||||||
|
var deserialized = _serialization.Deserialize(message.Data, type, context);
|
||||||
|
yield return (deserialized, message.MessageType)!;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType)
|
// public async Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload,
|
||||||
|
// IEndPointContext? context) where T : notnull
|
||||||
|
// {
|
||||||
|
// await this.PostCallMessageAsync(id, eMessageType, payload, context);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public async Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull
|
||||||
{
|
{
|
||||||
if (_interaction == null)
|
if (_interaction == null)
|
||||||
throw new NullReferenceException("Interaction toolkit is not initialized");
|
throw new NullReferenceException("Interaction toolkit is not initialized");
|
||||||
if (_serialization == null)
|
if (_serialization == null)
|
||||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
throw new NullReferenceException("Serialization toolkit is not initialized");
|
||||||
|
|
||||||
var serialized = _serialization.Serialize(payload, payloadType);
|
var serialized = _serialization.Serialize(payload, context);
|
||||||
await _interaction.PostMessageAsync(new NetworkMessageHeader
|
await _interaction.PostMessageAsync(new NetworkMessageHeader
|
||||||
{ Id = id, MessageType = eMessageType, Data = serialized });
|
{ Id = id, MessageType = eMessageType, Data = serialized });
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull
|
public void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload, IEndPointContext? context)
|
||||||
|
where T : notnull
|
||||||
{
|
{
|
||||||
PostCallMessageAsync(id, eMessageType, payload).GetAwaiter().GetResult();
|
PostCallMessageAsync(id, eMessageType, payload, context).GetAwaiter().GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType)
|
public async Task PostCallMessageUntrustedAsync<T>(Guid id, EMessageType eMessageType, T payload,
|
||||||
|
IEndPointContext? context) where T : notnull
|
||||||
{
|
{
|
||||||
PostCallMessageAsync(id, eMessageType, payload, payloadType).GetAwaiter().GetResult();
|
var serialized = _serialization.Serialize(payload, context);
|
||||||
|
await _interaction.PostMessageUntrustedAsync(new NetworkMessageHeader
|
||||||
|
{ Id = id, MessageType = eMessageType, Data = serialized });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,7 +4,7 @@ using mROA.Abstract;
|
|||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
// ReSharper disable UnusedMember.Global
|
// ReSharper disable UnusedMember.Global
|
||||||
#pragma warning disable CS8618, CS9264
|
// #pragma warning disable CS8618, CS9264
|
||||||
|
|
||||||
namespace mROA.Implementation
|
namespace mROA.Implementation
|
||||||
{
|
{
|
||||||
@@ -20,18 +20,21 @@ namespace mROA.Implementation
|
|||||||
{
|
{
|
||||||
private ComplexObjectIdentifier _identifier = ComplexObjectIdentifier.Null;
|
private ComplexObjectIdentifier _identifier = ComplexObjectIdentifier.Null;
|
||||||
|
|
||||||
private T _value;
|
private T? _value;
|
||||||
|
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
public SharedObjectShellShell()
|
public SharedObjectShellShell()
|
||||||
{
|
{
|
||||||
|
_value = default;
|
||||||
|
EndPointContext = new EndPointContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
public SharedObjectShellShell(T value)
|
public SharedObjectShellShell(T value, IEndPointContext endPointContext)
|
||||||
{
|
{
|
||||||
|
EndPointContext = endPointContext;
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +43,7 @@ namespace mROA.Implementation
|
|||||||
// ReSharper disable once MemberCanBePrivate.Global
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
public T Value
|
public T Value
|
||||||
{
|
{
|
||||||
get => _value;
|
get => _value!;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_value = value;
|
_value = value;
|
||||||
@@ -57,15 +60,7 @@ namespace mROA.Implementation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[SerializationIgnore]
|
[SerializationIgnore] [JsonIgnore] public IEndPointContext EndPointContext { get; set; }
|
||||||
[JsonIgnore]
|
|
||||||
public IEndPointContext EndPointContext { get; set; } = new EndPointContext
|
|
||||||
{
|
|
||||||
RealRepository = TransmissionConfig.RealContextRepository,
|
|
||||||
RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository,
|
|
||||||
HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(),
|
|
||||||
OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId
|
|
||||||
};
|
|
||||||
|
|
||||||
public ComplexObjectIdentifier Identifier
|
public ComplexObjectIdentifier Identifier
|
||||||
{
|
{
|
||||||
@@ -77,18 +72,18 @@ namespace mROA.Implementation
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_identifier = value;
|
_identifier = value;
|
||||||
Value = GetDefaultContextRepository().GetObject<T>(Identifier);
|
Value = GetDefaultContextRepository().GetObject<T>(Identifier, EndPointContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public object UniversalValue
|
public object UniversalValue
|
||||||
{
|
{
|
||||||
get => _value;
|
get => _value!;
|
||||||
set => _value = (T)value;
|
set => _value = (T)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IContextRepository GetDefaultContextRepository() =>
|
private IInstanceRepository GetDefaultContextRepository() =>
|
||||||
(_identifier.OwnerId == EndPointContext.HostId
|
(_identifier.OwnerId == EndPointContext.OwnerId
|
||||||
? EndPointContext.RealRepository
|
? EndPointContext.RealRepository
|
||||||
: EndPointContext.RemoteRepository) ??
|
: EndPointContext.RemoteRepository) ??
|
||||||
throw new NullReferenceException(
|
throw new NullReferenceException(
|
||||||
@@ -96,7 +91,7 @@ namespace mROA.Implementation
|
|||||||
|
|
||||||
public static implicit operator T(SharedObjectShellShell<T> value) => value.Value;
|
public static implicit operator T(SharedObjectShellShell<T> value) => value.Value;
|
||||||
|
|
||||||
public static implicit operator SharedObjectShellShell<T>(T value) =>
|
// public static implicit operator SharedObjectShellShell<T>(T value) =>
|
||||||
new(value);
|
// new(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using System;
|
|
||||||
using mROA.Abstract;
|
|
||||||
|
|
||||||
namespace mROA.Implementation
|
|
||||||
{
|
|
||||||
#pragma warning disable CS8618, CS9264
|
|
||||||
public static class TransmissionConfig
|
|
||||||
{
|
|
||||||
#if TRACE
|
|
||||||
public static int TotalTransmittedBytes { get; set; }
|
|
||||||
#endif
|
|
||||||
private static IContextRepository? _realContextRepository;
|
|
||||||
private static IContextRepository? _remoteEndpointContextRepository;
|
|
||||||
private static IOwnershipRepository? _ownershipRepository;
|
|
||||||
|
|
||||||
public static IContextRepository RealContextRepository
|
|
||||||
{
|
|
||||||
get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null");
|
|
||||||
set => _realContextRepository = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IContextRepository RemoteEndpointContextRepository
|
|
||||||
{
|
|
||||||
get => _remoteEndpointContextRepository ??
|
|
||||||
throw new NullReferenceException("RemoteEndpointContextRepository is null");
|
|
||||||
set => _remoteEndpointContextRepository = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IOwnershipRepository OwnershipRepository
|
|
||||||
{
|
|
||||||
get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null");
|
|
||||||
set => _ownershipRepository = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-1
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<Title>mROA</Title>
|
<Title>mROA</Title>
|
||||||
<Version>2.0.0</Version>
|
<Version>2.0.1</Version>
|
||||||
<Authors>YaslePoy</Authors>
|
<Authors>YaslePoy</Authors>
|
||||||
<Description>Fast and easy RPC with contex</Description>
|
<Description>Fast and easy RPC with contex</Description>
|
||||||
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
|
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Text.Json" Version="9.0.2"/>
|
<PackageReference Include="System.Text.Json" Version="9.0.2"/>
|
||||||
|
<PackageReference Include="System.Threading.Channels" Version="9.0.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user