Merge remote-tracking branch 'origin/Unitization'
# Conflicts: # Example.Backend/Printer.cs # Example.Frontend/Program.cs # mROA.Test/NextGenTest.cs # mROA/Abstract/IContextRepository.cs # mROA/Abstract/IInteractionModule.cs # mROA/Abstract/ISerialisationModule.cs # mROA/Implementation/Backend/BasicExecutionModule.cs # mROA/Implementation/Backend/ContextRepository.cs # mROA/Implementation/Backend/MultiClientContextRepository.cs # mROA/Implementation/Backend/NetworkGatewayModule.cs # mROA/Implementation/Frontend/NetworkFrontendBridge.cs # mROA/Implementation/Frontend/RequestExtractor.cs # mROA/Implementation/NetworkMessage.cs # mROA/Implementation/NextGenerationInteractionModule.cs # mROA/Implementation/RemoteContextRepository.cs # mROA/Implementation/RemoteObjectBase.cs # mROA/Implementation/RepresentationModule.cs
This commit is contained in:
@@ -2,9 +2,20 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<LangVersion>9</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<DefineConstants>TRACE;</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,28 +1,51 @@
|
|||||||
using Example.Shared;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Example.Shared;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Backend;
|
namespace Example.Backend
|
||||||
|
|
||||||
[SharedObjectSingleton]
|
|
||||||
public class LoadTestImp : ILoadTest
|
|
||||||
{
|
{
|
||||||
public int Next(int last)
|
[SharedObjectSingleton]
|
||||||
|
public class LoadTestImp : ILoadTest
|
||||||
{
|
{
|
||||||
return last + 1;
|
public int Next(int last)
|
||||||
}
|
{
|
||||||
|
return last + 1;
|
||||||
|
}
|
||||||
|
|
||||||
public int Last(int next)
|
public int Last(int next)
|
||||||
{
|
{
|
||||||
return next - 1;
|
return next - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void C()
|
public void C()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void A()
|
public void A()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AsyncTest(CancellationToken token)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Async Test");
|
||||||
|
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Waiting canceled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Console.WriteLine("Waiting...");
|
||||||
|
await Task.Delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine("Waited until the end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using Example.Shared;
|
using Example.Shared;
|
||||||
|
|
||||||
namespace Example.Backend;
|
namespace Example.Backend
|
||||||
|
|
||||||
public class Page : IPage
|
|
||||||
{
|
{
|
||||||
public string Text;
|
public class Page : IPage
|
||||||
public byte[] GetData()
|
|
||||||
{
|
{
|
||||||
return Encoding.UTF8.GetBytes(Text);
|
public string Text;
|
||||||
|
public byte[] GetData()
|
||||||
|
{
|
||||||
|
return Encoding.UTF8.GetBytes(Text);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Example.Shared;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace Example.Backend
|
||||||
|
{
|
||||||
|
public class PagesList : RemoteObjectBase, IPagesList
|
||||||
|
{
|
||||||
|
public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<IPage> Collection { get; }
|
||||||
|
|
||||||
|
public IPage this[int index]
|
||||||
|
{
|
||||||
|
get => GetResultAsync<IPage>(3, new object[] { index }).GetAwaiter().GetResult();
|
||||||
|
set => CallAsync(5, new object[] { index, value }).Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPage Get(int index)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(IPage item)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(int index, IPage item)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<IPage>? OnAdd;
|
||||||
|
public event Action<IPage>? OnRemove;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
// TODO release managed resources here
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAddExternal(IPage p0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnRemoveExternal(IPage p0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+36
-13
@@ -1,21 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Example.Shared;
|
using Example.Shared;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
namespace Example.Backend;
|
namespace Example.Backend
|
||||||
|
|
||||||
public class Printer : IPrinter
|
|
||||||
{
|
{
|
||||||
public string Name;
|
public class Printer : IPrinter
|
||||||
|
|
||||||
public string GetName()
|
|
||||||
{
|
{
|
||||||
return Name;
|
public string Name;
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken = default)
|
public void OnPrintExternal(IPage p0, RequestContext ro)
|
||||||
{
|
{
|
||||||
// throw new Exception("The method or operation is not implemented.");
|
OnPrint?.Invoke(p0, ro);
|
||||||
// var sharedObject = new Page { Text = text };
|
}
|
||||||
return new Page { Text = text };
|
|
||||||
|
public double Resource { get; set; } = 100d;
|
||||||
|
|
||||||
|
public string GetName()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IPage> Print(string text, bool some, RequestContext context,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
// throw new Exception("The method or operation is not implemented.");
|
||||||
|
var page = new Page { Text = text };
|
||||||
|
Console.WriteLine($"Request id : :{context.RequestId}");
|
||||||
|
OnPrint?.Invoke(page, context);
|
||||||
|
Resource /= 1.5;
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<IPage, RequestContext>? OnPrint;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Console.WriteLine(
|
||||||
|
"Dispose printer with name {0}, Dispose works, Dispose works, Dispose works, Dispose works,", Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,40 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Example.Shared;
|
using Example.Shared;
|
||||||
using mROA.Implementation;
|
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Backend;
|
namespace Example.Backend
|
||||||
|
|
||||||
[SharedObjectSingleton]
|
|
||||||
public class PrinterFactory : IPrinterFactory
|
|
||||||
{
|
{
|
||||||
private List<IPrinter> _printers = new();
|
[SharedObjectSingleton]
|
||||||
|
public class PrinterFactory : IPrinterFactory
|
||||||
public SharedObject<IPrinter> Create(string printerName)
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Creating printer");
|
private List<IPrinter> _printers = new List<IPrinter>();
|
||||||
return new Printer { Name = printerName };
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Register(SharedObject<IPrinter> printer)
|
public IPrinter Create(string printerName)
|
||||||
{
|
{
|
||||||
_printers.Add(printer.Value);
|
Console.WriteLine("Creating printer");
|
||||||
Console.WriteLine("Registered printer");
|
return new Printer { Name = printerName };
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharedObject<IPrinter> GetPrinterByName(string printerName)
|
public void Register(IPrinter printer)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Getting printer");
|
_printers.Add(printer);
|
||||||
return new SharedObject<IPrinter>(_printers.Find(i => i.GetName() == printerName)!);
|
Console.WriteLine("Registered printer");
|
||||||
}
|
}
|
||||||
|
|
||||||
public SharedObject<IPrinter> GetFirstPrinter()
|
public IPrinter GetPrinterByName(string printerName)
|
||||||
{
|
{
|
||||||
return new SharedObject<IPrinter>(_printers.First());
|
Console.WriteLine("Getting printer");
|
||||||
}
|
return (_printers.Find(i => i.GetName() == printerName)!);
|
||||||
|
}
|
||||||
|
|
||||||
public string[] CollectAllNames()
|
public IPrinter GetFirstPrinter()
|
||||||
{
|
{
|
||||||
Console.WriteLine("Collecting all printers");
|
return _printers.First();
|
||||||
return _printers.Select(i => i.GetName()).ToArray();
|
}
|
||||||
|
|
||||||
|
public string[] CollectAllNames()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Collecting all printers");
|
||||||
|
return _printers.Select(i => i.GetName()).ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+43
-30
@@ -1,43 +1,56 @@
|
|||||||
using System.Net;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using Example.Backend;
|
using Example.Backend;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
using mROA.Cbor;
|
||||||
using mROA.Codegen;
|
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;
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
|
class Program
|
||||||
var builder = new FullMixBuilder();
|
|
||||||
builder.UseJsonSerialisation();
|
|
||||||
builder.Modules.Add(new BackendIdentityGenerator());
|
|
||||||
builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
|
||||||
builder.GetModule<IIdentityGenerator>()!);
|
|
||||||
|
|
||||||
builder.Modules.Add(new ConnectionHub());
|
|
||||||
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
|
|
||||||
|
|
||||||
builder.UseBasicExecution();
|
|
||||||
|
|
||||||
builder.Modules.Add(new RemoteContextRepository());
|
|
||||||
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
|
|
||||||
builder.Modules.Add(new MultiClientContextRepository(i =>
|
|
||||||
{
|
{
|
||||||
var repo = new ContextRepository();
|
public static void Main(string[] args)
|
||||||
repo.FillSingletons(typeof(PrinterFactory).Assembly);
|
{
|
||||||
return repo;
|
var builder = new FullMixBuilder();
|
||||||
}));
|
// builder.UseJsonSerialisation();
|
||||||
builder.SetupMethodsRepository(new CoCodegenMethodRepository());
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
builder.Modules.Add(new CreativeRepresentationModuleProducer([builder.GetModule<JsonSerializationToolkit>()!],
|
builder.Modules.Add(new BackendIdentityGenerator());
|
||||||
typeof(RepresentationModule)));
|
// builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
||||||
|
// builder.GetModule<IIdentityGenerator>()!);
|
||||||
|
builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
|
||||||
|
builder.GetModule<IIdentityGenerator>()!);
|
||||||
|
|
||||||
builder.Build();
|
builder.Modules.Add(new ConnectionHub());
|
||||||
new RemoteTypeBinder();
|
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
|
||||||
|
|
||||||
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
|
builder.UseBasicExecution();
|
||||||
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
builder.Modules.Add(new CreativeRepresentationModuleProducer(
|
||||||
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
|
new IInjectableModule[] { builder.GetModule<ISerializationToolkit>()! },
|
||||||
|
typeof(RepresentationModule)));
|
||||||
|
builder.Modules.Add(new RemoteContextRepository());
|
||||||
|
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
|
||||||
|
builder.Modules.Add(new MultiClientContextRepository(i =>
|
||||||
|
{
|
||||||
|
var repo = new ContextRepository();
|
||||||
|
repo.FillSingletons(typeof(PrinterFactory).Assembly);
|
||||||
|
repo.Inject(builder.Modules.OfType<CreativeRepresentationModuleProducer>().First());
|
||||||
|
return repo;
|
||||||
|
}));
|
||||||
|
builder.SetupMethodsRepository(new CoCodegenMethodRepository());
|
||||||
|
|
||||||
var gateway = builder.GetModule<IGatewayModule>();
|
builder.Modules.Add(new CancellationRepository());
|
||||||
|
|
||||||
gateway.Run();
|
builder.Build();
|
||||||
|
new RemoteTypeBinder();
|
||||||
|
|
||||||
|
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
|
||||||
|
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
||||||
|
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
|
||||||
|
|
||||||
|
var gateway = builder.GetModule<IGatewayModule>();
|
||||||
|
|
||||||
|
gateway.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using Example.Events.Shared;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace Example.Events.Backend;
|
||||||
|
|
||||||
|
public class Chat : IChat
|
||||||
|
{
|
||||||
|
public void PostSymbol(string symbol, RequestContext context)
|
||||||
|
{
|
||||||
|
OnCharPosted?.Invoke(symbol, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<string, RequestContext>? OnCharPosted;
|
||||||
|
|
||||||
|
public void OnCharPostedExternal(string p0, RequestContext p1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
using Example.Events.Shared;
|
||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace Example.Events.Backend;
|
||||||
|
|
||||||
|
[SharedObjectSingleton]
|
||||||
|
public class ChatFactory : IChatFactory
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Guid, IChat> Chats = new();
|
||||||
|
|
||||||
|
public IChat GetChat(Guid id)
|
||||||
|
{
|
||||||
|
if (Chats.TryGetValue(id, out var chat))
|
||||||
|
{
|
||||||
|
return chat;
|
||||||
|
}
|
||||||
|
|
||||||
|
var created = new Chat();
|
||||||
|
Chats.Add(id, created);
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<DefineConstants />
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Example.Events.Shared\Example.Events.Shared.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System.Net;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using mROA.Cbor;
|
||||||
|
using mROA.Codegen;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Backend;
|
||||||
|
using mROA.Implementation.Bootstrap;
|
||||||
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
|
namespace Example.Events.Backend;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var builder = new FullMixBuilder();
|
||||||
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
|
builder.Modules.Add(new BackendIdentityGenerator());
|
||||||
|
builder.UseNetworkGateway(IPEndPoint.Parse("192.168.1.101:6000"), typeof(NextGenerationInteractionModule),
|
||||||
|
builder.GetModule<IIdentityGenerator>()!);
|
||||||
|
|
||||||
|
builder.Modules.Add(new ConnectionHub());
|
||||||
|
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
|
||||||
|
|
||||||
|
builder.UseBasicExecution();
|
||||||
|
builder.Modules.Add(new CreativeRepresentationModuleProducer(
|
||||||
|
new IInjectableModule[] { builder.GetModule<ISerializationToolkit>()! },
|
||||||
|
typeof(RepresentationModule)));
|
||||||
|
builder.Modules.Add(new RemoteContextRepository());
|
||||||
|
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
|
||||||
|
builder.Modules.Add(new MultiClientContextRepository(i =>
|
||||||
|
{
|
||||||
|
var repo = new ContextRepository();
|
||||||
|
repo.FillSingletons(typeof(ChatFactory).Assembly);
|
||||||
|
repo.Inject(builder.Modules.OfType<CreativeRepresentationModuleProducer>().First());
|
||||||
|
return repo;
|
||||||
|
}));
|
||||||
|
builder.SetupMethodsRepository(new CoCodegenMethodRepository());
|
||||||
|
|
||||||
|
builder.Modules.Add(new CancellationRepository());
|
||||||
|
|
||||||
|
builder.Build();
|
||||||
|
new RemoteTypeBinder();
|
||||||
|
|
||||||
|
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
|
||||||
|
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
||||||
|
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
|
||||||
|
|
||||||
|
var gateway = builder.GetModule<IGatewayModule>();
|
||||||
|
|
||||||
|
gateway.Run();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<DefineConstants />
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Example.Events.Shared\Example.Events.Shared.csproj"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Net;
|
||||||
|
using Example.Events.Shared;
|
||||||
|
using mROA.Cbor;
|
||||||
|
using mROA.Codegen;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Backend;
|
||||||
|
using mROA.Implementation.Bootstrap;
|
||||||
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
|
namespace Example.Events.Client;
|
||||||
|
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var builder = new FullMixBuilder();
|
||||||
|
new RemoteTypeBinder();
|
||||||
|
// builder.Modules.Add(new JsonSerializationToolkit());
|
||||||
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
|
|
||||||
|
builder.Modules.Add(new RemoteContextRepository());
|
||||||
|
builder.Modules.Add(new NextGenerationInteractionModule());
|
||||||
|
builder.Modules.Add(new RepresentationModule());
|
||||||
|
builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Parse("95.105.78.72"), 6000)));
|
||||||
|
builder.Modules.Add(new StaticRepresentationModuleProducer());
|
||||||
|
builder.Modules.Add(new RequestExtractor());
|
||||||
|
builder.Modules.Add(new BasicExecutionModule());
|
||||||
|
builder.Modules.Add(new CoCodegenMethodRepository());
|
||||||
|
builder.UseCollectableContextRepository();
|
||||||
|
builder.Modules.Add(new CancellationRepository());
|
||||||
|
|
||||||
|
builder.Build();
|
||||||
|
|
||||||
|
|
||||||
|
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
||||||
|
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
||||||
|
|
||||||
|
builder.GetModule<NetworkFrontendBridge>()!.Connect();
|
||||||
|
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
||||||
|
|
||||||
|
var chatFactory =
|
||||||
|
TransmissionConfig.RemoteEndpointContextRepository.GetSingleObject(typeof(IChatFactory), 0) as IChatFactory;
|
||||||
|
var chat = chatFactory.GetChat(Guid.Empty);
|
||||||
|
chat.OnCharPosted += (s, context) => { Console.Write(s); };
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var input = Console.ReadKey(true);
|
||||||
|
if (input.Key == ConsoleKey.Escape)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var symb = "";
|
||||||
|
|
||||||
|
if (input.Key == ConsoleKey.Backspace)
|
||||||
|
{
|
||||||
|
symb = "\b \b";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
symb = input.KeyChar.ToString();
|
||||||
|
#if TRACE
|
||||||
|
Console.Write(symb);
|
||||||
|
var sw = Stopwatch.StartNew();
|
||||||
|
chat.PostSymbol(symb);
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
|
||||||
|
#else
|
||||||
|
Console.Write(symb);
|
||||||
|
chat.PostSymbol(symb);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>9</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj"/>
|
||||||
|
<ProjectReference Include="..\mROA\mROA.csproj"/>
|
||||||
|
<ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||||
|
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace Example.Events.Shared
|
||||||
|
{
|
||||||
|
[SharedObjectInterface]
|
||||||
|
public partial interface IChat : IShared
|
||||||
|
{
|
||||||
|
void PostSymbol(string symbol, RequestContext context = default);
|
||||||
|
event Action<string, RequestContext> OnCharPosted;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace Example.Events.Shared
|
||||||
|
{
|
||||||
|
[SharedObjectInterface]
|
||||||
|
public interface IChatFactory : IShared
|
||||||
|
{
|
||||||
|
IChat GetChat(Guid id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,28 +1,47 @@
|
|||||||
using Example.Shared;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Example.Shared;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
namespace Example.Frontend;
|
namespace Example.Frontend
|
||||||
|
|
||||||
public class ClientBasedPrinter : IPrinter
|
|
||||||
{
|
{
|
||||||
public string GetName()
|
public class ClientBasedPrinter : IPrinter
|
||||||
{
|
{
|
||||||
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)");
|
public void OnPrintExternal(IPage p0, RequestContext ro)
|
||||||
return "ClientBasedPrinter from mroa";
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Resource { get; set; }
|
||||||
|
|
||||||
|
public string GetName()
|
||||||
|
{
|
||||||
|
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)");
|
||||||
|
DemoCheck.BackwardCall = true;
|
||||||
|
|
||||||
|
return "ClientBasedPrinter from mroa";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IPage> Print(string text, bool some, RequestContext context,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Printed: {text}");
|
||||||
|
await Task.Yield();
|
||||||
|
return new ClientBasedPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
public event Action<IPage, RequestContext>? OnPrint;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken)
|
public class ClientBasedPage : IPage
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Printed: {text}");
|
public byte[] GetData()
|
||||||
await Task.Yield();
|
{
|
||||||
return new ClientBasedPage();
|
return new byte[] { 1, 2, 3 };
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public class ClientBasedPage : IPage
|
|
||||||
{
|
|
||||||
public byte[] GetData()
|
|
||||||
{
|
|
||||||
return [1, 2, 3];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Example.Frontend
|
||||||
|
{
|
||||||
|
public static class DemoCheck
|
||||||
|
{
|
||||||
|
public static bool ClientBasedImplementation;
|
||||||
|
public static bool TaskCancelation;
|
||||||
|
public static bool Dispose;
|
||||||
|
public static bool PropertySet;
|
||||||
|
public static bool PropertyGet;
|
||||||
|
public static bool TaskExecution;
|
||||||
|
public static bool BackwardCall;
|
||||||
|
public static bool BasicNonParamsCall;
|
||||||
|
public static bool EventCallback;
|
||||||
|
public static bool CreatingPrinter;
|
||||||
|
|
||||||
|
public static void Show()
|
||||||
|
{
|
||||||
|
Console.WriteLine("======================== Demo summary ========================");
|
||||||
|
var fields = typeof(DemoCheck).GetFields().OrderBy(i => i.Name).ToList();
|
||||||
|
foreach (var field in fields)
|
||||||
|
{
|
||||||
|
var value = (bool)field.GetValue(null)!;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Console.BackgroundColor = ConsoleColor.Green;
|
||||||
|
}else Console.BackgroundColor = ConsoleColor.Gray;
|
||||||
|
|
||||||
|
Console.Write($"{field.Name}");
|
||||||
|
Console.BackgroundColor = ConsoleColor.Black;
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,18 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<LangVersion>9</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<DefineConstants>TRACE;</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<DefineConstants></DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+106
-54
@@ -1,80 +1,132 @@
|
|||||||
using System.Diagnostics;
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Example.Frontend;
|
using Example.Frontend;
|
||||||
using Example.Shared;
|
using Example.Shared;
|
||||||
|
using mROA.Cbor;
|
||||||
using mROA.Codegen;
|
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;
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
var builder = new FullMixBuilder();
|
class Program
|
||||||
new RemoteTypeBinder();
|
{
|
||||||
builder.Modules.Add(new JsonSerializationToolkit());
|
public static void Main(string[] args)
|
||||||
builder.Modules.Add(new RemoteContextRepository());
|
{
|
||||||
builder.Modules.Add(new NextGenerationInteractionModule());
|
var builder = new FullMixBuilder();
|
||||||
builder.Modules.Add(new RepresentationModule());
|
new RemoteTypeBinder();
|
||||||
builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567)));
|
// builder.Modules.Add(new JsonSerializationToolkit());
|
||||||
builder.Modules.Add(new StaticRepresentationModuleProducer());
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
builder.Modules.Add(new RequestExtractor());
|
|
||||||
builder.Modules.Add(new BasicExecutionModule());
|
builder.Modules.Add(new RemoteContextRepository());
|
||||||
builder.Modules.Add(new CoCodegenMethodRepository());
|
builder.Modules.Add(new NextGenerationInteractionModule());
|
||||||
builder.UseCollectableContextRepository();
|
builder.Modules.Add(new RepresentationModule());
|
||||||
builder.Build();
|
builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567)));
|
||||||
|
builder.Modules.Add(new StaticRepresentationModuleProducer());
|
||||||
|
builder.Modules.Add(new RequestExtractor());
|
||||||
|
builder.Modules.Add(new BasicExecutionModule());
|
||||||
|
builder.Modules.Add(new CoCodegenMethodRepository());
|
||||||
|
builder.UseCollectableContextRepository();
|
||||||
|
builder.Modules.Add(new CancellationRepository());
|
||||||
|
|
||||||
|
builder.Build();
|
||||||
|
|
||||||
|
|
||||||
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
|
||||||
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
|
||||||
|
|
||||||
builder.GetModule<NetworkFrontendBridge>()!.Connect();
|
builder.GetModule<NetworkFrontendBridge>()!.Connect();
|
||||||
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
|
||||||
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
|
||||||
var context = builder.GetModule<RemoteContextRepository>();
|
var context = builder.GetModule<RemoteContextRepository>();
|
||||||
|
|
||||||
var factory = context.GetSingleObject<IPrinterFactory>();
|
var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory;
|
||||||
|
|
||||||
//правильный порядок команд 8-5-10-7
|
//правильный порядок команд 8-5-10-7
|
||||||
var printer = factory.Create("Test");
|
using (var disposingPrinter = factory.Create("Test"))
|
||||||
Console.WriteLine("Printer created");
|
{
|
||||||
Thread.Sleep(100);
|
DemoCheck.CreatingPrinter = true;
|
||||||
|
disposingPrinter.OnPrint += (_, _) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("New page creater. Called from event!!!");
|
||||||
|
DemoCheck.EventCallback = true;
|
||||||
|
};
|
||||||
|
Console.WriteLine("Printer created");
|
||||||
|
Thread.Sleep(100);
|
||||||
|
|
||||||
var name = printer.Value.GetName();
|
var name = disposingPrinter.GetName();
|
||||||
Console.WriteLine("Printer name : {0}", name);
|
DemoCheck.BasicNonParamsCall = true;
|
||||||
Thread.Sleep(100);
|
Console.WriteLine("Printer name : {0}", name);
|
||||||
|
|
||||||
factory.Register(new SharedObject<IPrinter>(new ClientBasedPrinter()));
|
Thread.Sleep(100);
|
||||||
Console.WriteLine("Registered printer");
|
|
||||||
Thread.Sleep(100);
|
factory.Register(new ClientBasedPrinter());
|
||||||
|
DemoCheck.ClientBasedImplementation = true;
|
||||||
|
Console.WriteLine("Registered printer");
|
||||||
|
Thread.Sleep(100);
|
||||||
|
|
||||||
|
|
||||||
var registred = factory.GetFirstPrinter();
|
var registered = factory.GetFirstPrinter();
|
||||||
Console.WriteLine("First printer");
|
Console.WriteLine("First printer");
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
|
|
||||||
Console.WriteLine(registred.Value);
|
Console.WriteLine(registered);
|
||||||
Console.WriteLine("Collecting all printers");
|
Console.WriteLine("Collecting all printers");
|
||||||
var names = factory.CollectAllNames();
|
var names = factory.CollectAllNames();
|
||||||
Thread.Sleep(100);
|
Thread.Sleep(100);
|
||||||
|
|
||||||
Console.WriteLine(string.Join(", ", names));
|
Console.WriteLine(string.Join(", ", names));
|
||||||
|
|
||||||
var page = printer.Value.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult();
|
var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter()
|
||||||
var data = page.Value.GetData();
|
.GetResult();
|
||||||
Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data));
|
Console.WriteLine("Page printed");
|
||||||
|
DemoCheck.TaskExecution = true;
|
||||||
|
Console.WriteLine(page.ToString());
|
||||||
|
|
||||||
var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest;
|
Console.WriteLine($"Printer resource : {disposingPrinter.Resource}");
|
||||||
|
DemoCheck.PropertyGet = true;
|
||||||
|
|
||||||
const int iterations = 10000;
|
Console.WriteLine("Restoring resource");
|
||||||
var timer = Stopwatch.StartNew();
|
disposingPrinter.Resource = 100;
|
||||||
var x = 0;
|
DemoCheck.PropertySet = true;
|
||||||
for (int i = 0; i < iterations; i++)
|
Console.WriteLine($"Printer resource again : {disposingPrinter.Resource}");
|
||||||
{
|
|
||||||
x = loadSingleton.Next(x);
|
|
||||||
// Console.WriteLine(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
timer.Stop();
|
var data = page.GetData();
|
||||||
Console.WriteLine("X is {0}", x);
|
Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data));
|
||||||
Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
|
||||||
Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
Console.WriteLine("Dispose printer");
|
||||||
|
}
|
||||||
|
DemoCheck.Dispose = true;
|
||||||
|
|
||||||
|
|
||||||
|
var loadSingleton = context.GetSingleObject(typeof(ILoadTest), 0) as ILoadTest;
|
||||||
|
|
||||||
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var token = cts.Token;
|
||||||
|
var t = Task.Run(async () => await loadSingleton!.AsyncTest(token));
|
||||||
|
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
cts.Cancel();
|
||||||
|
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
|
||||||
|
DemoCheck.TaskCancelation = true;
|
||||||
|
DemoCheck.Show();
|
||||||
|
Console.ReadKey();
|
||||||
|
//
|
||||||
|
// const int iterations = 10000;
|
||||||
|
// var timer = Stopwatch.StartNew();
|
||||||
|
// var x = 0;
|
||||||
|
// for (int i = 0; i < iterations; i++)
|
||||||
|
// {
|
||||||
|
// x = loadSingleton.Next(x);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// timer.Stop();
|
||||||
|
// Console.WriteLine("X is {0}", x);
|
||||||
|
// Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
||||||
|
// Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,15 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
<LangVersion>9</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj"/>
|
||||||
<ProjectReference Include="..\mROA\mROA.csproj"/>
|
<ProjectReference Include="..\mROA\mROA.csproj"/>
|
||||||
<ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
<ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace Example.Shared
|
||||||
|
{
|
||||||
|
public interface IDataList<T> : IShared, IDisposable
|
||||||
|
{
|
||||||
|
IReadOnlyList<T> Collection { get; }
|
||||||
|
T this[int index] { get; set; }
|
||||||
|
T Get(int index);
|
||||||
|
void Add(T item);
|
||||||
|
void Remove(int index, T item);
|
||||||
|
event Action<T> OnAdd;
|
||||||
|
event Action<T> OnRemove;
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
-10
@@ -1,13 +1,18 @@
|
|||||||
using mROA.Implementation.Attributes;
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Shared;
|
namespace Example.Shared
|
||||||
|
|
||||||
[SharedObjectInterface]
|
|
||||||
public interface ILoadTest
|
|
||||||
{
|
{
|
||||||
int Next(int last);
|
[SharedObjectInterface]
|
||||||
int Last(int next);
|
public interface ILoadTest : IShared
|
||||||
void C();
|
{
|
||||||
void A();
|
int Next(int last);
|
||||||
}
|
int Last(int next);
|
||||||
|
void C();
|
||||||
|
void A();
|
||||||
|
|
||||||
|
Task AsyncTest(CancellationToken token = default);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Shared;
|
namespace Example.Shared
|
||||||
|
|
||||||
[SharedObjectInterface]
|
|
||||||
public interface IPage
|
|
||||||
{
|
{
|
||||||
byte[] GetData();
|
[SharedObjectInterface]
|
||||||
|
public interface IPage : IShared
|
||||||
|
{
|
||||||
|
byte[] GetData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace Example.Shared
|
||||||
|
{
|
||||||
|
[SharedObjectInterface]
|
||||||
|
public partial interface IPagesList : IDataList<IPage>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Shared;
|
namespace Example.Shared
|
||||||
|
|
||||||
[SharedObjectInterface]
|
|
||||||
public interface IPrinter
|
|
||||||
{
|
{
|
||||||
string GetName();
|
[SharedObjectInterface]
|
||||||
Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken);
|
public partial interface IPrinter : IDisposable, IShared
|
||||||
|
{
|
||||||
|
double Resource { get; set; }
|
||||||
|
string GetName();
|
||||||
|
Task<IPage> Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken);
|
||||||
|
event Action<IPage, RequestContext> OnPrint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Shared;
|
namespace Example.Shared
|
||||||
|
|
||||||
[SharedObjectInterface]
|
|
||||||
public interface IPrinterFactory
|
|
||||||
{
|
{
|
||||||
SharedObject<IPrinter> Create(string printerName);
|
[SharedObjectInterface]
|
||||||
void Register(SharedObject<IPrinter> printer);
|
public interface IPrinterFactory : IShared
|
||||||
SharedObject<IPrinter> GetPrinterByName(string printerName);
|
{
|
||||||
SharedObject<IPrinter> GetFirstPrinter();
|
IPrinter Create(string printerName);
|
||||||
string[] CollectAllNames();
|
void Register(IPrinter printer);
|
||||||
|
IPrinter GetPrinterByName(string printerName);
|
||||||
|
IPrinter GetFirstPrinter();
|
||||||
|
string[] CollectAllNames();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+40
-39
@@ -1,50 +1,51 @@
|
|||||||
using BenchmarkDotNet.Attributes;
|
using System.Collections.Generic;
|
||||||
using BenchmarkDotNet.Running;
|
using System.Linq;
|
||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
|
||||||
namespace mROA.Benchmark;
|
namespace mROA.Benchmark
|
||||||
|
|
||||||
class Program
|
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
class Program
|
||||||
{
|
{
|
||||||
Console.WriteLine("Hello, World!");
|
static void Main(string[] args)
|
||||||
var summary = BenchmarkRunner.Run<CollectionsSpeed>();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class CollectionsSpeed
|
|
||||||
{
|
|
||||||
private const int N = 1000;
|
|
||||||
|
|
||||||
private readonly List<int> _immutable;
|
|
||||||
private readonly int[] _array;
|
|
||||||
|
|
||||||
public CollectionsSpeed()
|
|
||||||
{
|
|
||||||
_array = Enumerable.Range(0, N).ToArray();
|
|
||||||
_immutable = [.._array];
|
|
||||||
}
|
|
||||||
|
|
||||||
[Benchmark]
|
|
||||||
public int DefaultArray()
|
|
||||||
{
|
|
||||||
var sum = 0;
|
|
||||||
for (int i = 0; i < N; i++)
|
|
||||||
{
|
{
|
||||||
sum += _array[i];
|
// Console.WriteLine("Hello, World!");
|
||||||
|
// var summary = BenchmarkRunner.Run<CollectionsSpeed>();
|
||||||
}
|
}
|
||||||
return sum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
public class CollectionsSpeed
|
||||||
public int ImmutableArray()
|
|
||||||
{
|
{
|
||||||
var sum = 0;
|
private const int N = 1000;
|
||||||
for (int i = 0; i < N; i++)
|
|
||||||
|
private readonly List<int> _immutable;
|
||||||
|
private readonly int[] _array;
|
||||||
|
|
||||||
|
public CollectionsSpeed()
|
||||||
{
|
{
|
||||||
sum += _immutable[i];
|
_array = Enumerable.Range(0, N).ToArray();
|
||||||
|
// _immutable = [.._array];
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public int DefaultArray()
|
||||||
|
{
|
||||||
|
var sum = 0;
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
sum += _array[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public int ImmutableArray()
|
||||||
|
{
|
||||||
|
var sum = 0;
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
sum += _immutable[i];
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
return sum;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,442 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Formats.Cbor;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation;
|
||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace mROA.Cbor
|
||||||
|
{
|
||||||
|
public class CborSerializationToolkit : IContextualSerializationToolKit
|
||||||
|
{
|
||||||
|
public byte[] Serialize(object objectToSerialize, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var writer = new CborWriter();
|
||||||
|
WriteData(objectToSerialize, writer, context);
|
||||||
|
return writer.Encode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var writer = new CborWriter();
|
||||||
|
WriteData(objectToSerialize, writer, context);
|
||||||
|
writer.Encode(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Deserialize<T>(byte[] rawData, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
return (T)Deserialize(rawData, typeof(T), context) ?? default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Deserialize(byte[] rawData, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
return Deserialize(rawData.AsMemory(), type, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Deserialize<T>(ReadOnlyMemory<byte> rawMemory, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
return (T)Deserialize(rawMemory, typeof(T), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Deserialize(ReadOnlyMemory<byte> rawMemory, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var reader = new CborReader(rawMemory);
|
||||||
|
return ReadData(reader, type, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Cast<T>(object nonCasted, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
return (T)Cast(nonCasted, typeof(T), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Cast(object? nonCasted, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
if (nonCasted == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (nonCasted.GetType() == type)
|
||||||
|
return nonCasted;
|
||||||
|
|
||||||
|
if (nonCasted is PreParsedValue preParsed)
|
||||||
|
return preParsed.ToObject(type, context);
|
||||||
|
|
||||||
|
|
||||||
|
if (type == typeof(Guid))
|
||||||
|
{
|
||||||
|
return new Guid((byte[])nonCasted);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Convert.ChangeType(nonCasted, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize<T>(T objectToSerialize)
|
||||||
|
{
|
||||||
|
return Serialize(objectToSerialize, typeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Serialize(object objectToSerialize, Type type)
|
||||||
|
{
|
||||||
|
return Serialize(objectToSerialize, context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Deserialize<T>(byte[] rawData)
|
||||||
|
{
|
||||||
|
return Deserialize<T>(rawData: rawData, context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Deserialize(byte[] rawData, Type type)
|
||||||
|
{
|
||||||
|
return Deserialize(rawData: rawData, type, context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Deserialize<T>(Span<byte> rawData)
|
||||||
|
{
|
||||||
|
return Deserialize<T>(rawData.ToArray().AsMemory(), context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? Deserialize(Span<byte> rawData, Type type)
|
||||||
|
{
|
||||||
|
return Deserialize(rawData: rawData.ToArray(), type: type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Cast<T>(object nonCasted)
|
||||||
|
{
|
||||||
|
return Cast<T>(nonCasted: nonCasted, context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Cast(object nonCasted, Type type)
|
||||||
|
{
|
||||||
|
return Cast(nonCasted: nonCasted, type: type, context: null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteData(object? obj, CborWriter writer, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
switch (obj)
|
||||||
|
{
|
||||||
|
case int i:
|
||||||
|
writer.WriteInt32(i);
|
||||||
|
break;
|
||||||
|
case long l:
|
||||||
|
writer.WriteInt64(l);
|
||||||
|
break;
|
||||||
|
case float f:
|
||||||
|
writer.WriteSingle(f);
|
||||||
|
break;
|
||||||
|
case double d:
|
||||||
|
writer.WriteDouble(d);
|
||||||
|
break;
|
||||||
|
case bool b:
|
||||||
|
writer.WriteBoolean(b);
|
||||||
|
break;
|
||||||
|
case string s:
|
||||||
|
writer.WriteTextString(s);
|
||||||
|
break;
|
||||||
|
case null:
|
||||||
|
writer.WriteNull();
|
||||||
|
break;
|
||||||
|
case uint ui:
|
||||||
|
writer.WriteUInt32(ui);
|
||||||
|
break;
|
||||||
|
case ulong ul:
|
||||||
|
writer.WriteUInt64(ul);
|
||||||
|
break;
|
||||||
|
case DateTimeOffset dto:
|
||||||
|
writer.WriteDateTimeOffset(dto);
|
||||||
|
break;
|
||||||
|
case Guid g:
|
||||||
|
writer.WriteByteString(g.ToByteArray());
|
||||||
|
break;
|
||||||
|
case byte[] bytes:
|
||||||
|
writer.WriteByteString(bytes);
|
||||||
|
break;
|
||||||
|
case IDictionary dictionary:
|
||||||
|
WriteDictionary(dictionary, writer, context);
|
||||||
|
break;
|
||||||
|
case IList enumerable:
|
||||||
|
WriteList(enumerable, writer, context);
|
||||||
|
break;
|
||||||
|
case ISharedObjectShell sharedObject:
|
||||||
|
if (context != null)
|
||||||
|
sharedObject.EndPointContext = context;
|
||||||
|
WriteObject(sharedObject, writer, context);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (obj.GetType().IsEnum)
|
||||||
|
{
|
||||||
|
writer.WriteInt32((int)obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteObject(obj, writer, context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteList(IList list, CborWriter writer, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
writer.WriteStartArray(list.Count);
|
||||||
|
|
||||||
|
foreach (var element in list)
|
||||||
|
WriteData(element, writer, context);
|
||||||
|
|
||||||
|
writer.WriteEndArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteDictionary(IDictionary dictionary, CborWriter writer, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
writer.WriteStartMap(dictionary.Count);
|
||||||
|
var keysEnumerator = dictionary.Keys.GetEnumerator();
|
||||||
|
var valuesEnumerator = dictionary.Values.GetEnumerator();
|
||||||
|
for (int i = 0; i < dictionary.Count; i++)
|
||||||
|
{
|
||||||
|
keysEnumerator.MoveNext();
|
||||||
|
valuesEnumerator.MoveNext();
|
||||||
|
WriteData(keysEnumerator.Current, writer, context);
|
||||||
|
WriteData(valuesEnumerator.Current, writer, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteEndMap();
|
||||||
|
(keysEnumerator as IDisposable)?.Dispose();
|
||||||
|
(valuesEnumerator as IDisposable)?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteObject(object obj, CborWriter writer, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var type = obj.GetType();
|
||||||
|
|
||||||
|
if (obj is IShared)
|
||||||
|
{
|
||||||
|
var generic = obj.GetType().GetInterfaces().FirstOrDefault(i => typeof(IShared).IsAssignableFrom(i));
|
||||||
|
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(generic);
|
||||||
|
var so =
|
||||||
|
Activator.CreateInstance(sharedShell, obj) as
|
||||||
|
ISharedObjectShell;
|
||||||
|
if (context != null)
|
||||||
|
so.EndPointContext = context;
|
||||||
|
|
||||||
|
writer.WriteStartArray(1);
|
||||||
|
writer.WriteUInt64(so.Identifier.Flat);
|
||||||
|
writer.WriteEndArray();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = FilterProperties(type.GetProperties());
|
||||||
|
var values = properties.Select(property => property.GetValue(obj)).ToList();
|
||||||
|
WriteList(values, writer, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
private object? ReadData(CborReader reader, Type? type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var state = reader.PeekState();
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case CborReaderState.Boolean:
|
||||||
|
return reader.ReadBoolean();
|
||||||
|
case CborReaderState.UnsignedInteger:
|
||||||
|
case CborReaderState.NegativeInteger:
|
||||||
|
if (type == typeof(int) || type is { IsEnum: true })
|
||||||
|
return reader.ReadInt32();
|
||||||
|
if (type == typeof(long))
|
||||||
|
return reader.ReadInt64();
|
||||||
|
if (type == typeof(uint))
|
||||||
|
return reader.ReadUInt32();
|
||||||
|
if (type == typeof(ulong))
|
||||||
|
return reader.ReadUInt64();
|
||||||
|
|
||||||
|
return reader.ReadUInt64();
|
||||||
|
case CborReaderState.ByteString:
|
||||||
|
if (type == typeof(Guid))
|
||||||
|
return new Guid(reader.ReadByteString());
|
||||||
|
return reader.ReadByteString();
|
||||||
|
case CborReaderState.TextString:
|
||||||
|
return reader.ReadTextString();
|
||||||
|
case CborReaderState.Null:
|
||||||
|
reader.ReadNull();
|
||||||
|
return null;
|
||||||
|
case CborReaderState.DoublePrecisionFloat:
|
||||||
|
return reader.ReadDouble();
|
||||||
|
case CborReaderState.SinglePrecisionFloat:
|
||||||
|
return reader.ReadSingle();
|
||||||
|
case CborReaderState.HalfPrecisionFloat:
|
||||||
|
return type == typeof(float) ? reader.ReadSingle() : reader.ReadDouble();
|
||||||
|
|
||||||
|
case CborReaderState.StartArray:
|
||||||
|
if (type == null)
|
||||||
|
return ReadList(reader, null, context);
|
||||||
|
|
||||||
|
if (type.IsSubclassOf(typeof(ISharedObjectShell)))
|
||||||
|
return ReadSharedObject(reader, type, context);
|
||||||
|
|
||||||
|
if (typeof(IList).IsAssignableFrom(type) || type.IsArray)
|
||||||
|
return ReadList(reader, type, context);
|
||||||
|
|
||||||
|
return ReadObject(reader, type, context);
|
||||||
|
|
||||||
|
case CborReaderState.StartMap:
|
||||||
|
return ReadDictionary(reader, type, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type == typeof(DateTimeOffset))
|
||||||
|
return reader.ReadDateTimeOffset();
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private IList ReadList(CborReader reader, Type? type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var length = reader.ReadStartArray();
|
||||||
|
if (length != null)
|
||||||
|
{
|
||||||
|
var elementType = typeof(object);
|
||||||
|
if (type is { IsArray: true })
|
||||||
|
{
|
||||||
|
elementType = type.GetElementType();
|
||||||
|
Array values = Array.CreateInstance(elementType, length.Value);
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
values.SetValue(ReadData(reader, elementType, context), i);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndArray();
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof(IList).IsAssignableFrom(type))
|
||||||
|
elementType = type.GetGenericArguments()[0];
|
||||||
|
else elementType = typeof(object);
|
||||||
|
Type genericListType = typeof(List<>).MakeGenericType(elementType);
|
||||||
|
var list = (IList)Activator.CreateInstance(genericListType, length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
list.Add(ReadData(reader, elementType, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndArray();
|
||||||
|
|
||||||
|
|
||||||
|
return list;
|
||||||
|
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IDictionary ReadDictionary(CborReader reader, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var dictionaryInstance = (Activator.CreateInstance(type) as IDictionary)!;
|
||||||
|
var length = reader.ReadStartArray();
|
||||||
|
if (length != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
var key = ReadData(reader, type, context);
|
||||||
|
var value = ReadData(reader, type, context);
|
||||||
|
dictionaryInstance.Add(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionaryInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ReadObject(CborReader reader, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
if (type == typeof(object))
|
||||||
|
{
|
||||||
|
return new PreParsedValue(ReadList(reader, null, context) as List<object>);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type.IsInterface)
|
||||||
|
{
|
||||||
|
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type);
|
||||||
|
var so =
|
||||||
|
Activator.CreateInstance(sharedShell) as
|
||||||
|
ISharedObjectShell;
|
||||||
|
if (context != null)
|
||||||
|
so.EndPointContext = context;
|
||||||
|
|
||||||
|
reader.ReadStartArray();
|
||||||
|
var identifier = reader.ReadUInt64();
|
||||||
|
reader.ReadEndArray();
|
||||||
|
|
||||||
|
so.Identifier = ComplexObjectIdentifier.FromFlat(identifier);
|
||||||
|
return so.UniversalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance = Activator.CreateInstance(type)!;
|
||||||
|
|
||||||
|
FillObject(instance, type, reader, context);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ISharedObjectShell ReadSharedObject(CborReader reader, Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var sharedObject = (Activator.CreateInstance(type) as ISharedObjectShell)!;
|
||||||
|
if (context != null)
|
||||||
|
{
|
||||||
|
sharedObject.EndPointContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillObject(sharedObject, type, reader, context);
|
||||||
|
|
||||||
|
return sharedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillObject(object obj, Type type, CborReader reader, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
var propertyInfos = type.GetProperties();
|
||||||
|
var properties = FilterProperties(propertyInfos);
|
||||||
|
|
||||||
|
var length = reader.ReadStartArray();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine($"Reading list of {length} objects, {properties.Count} properties found");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (var index = 0; index < length; index++)
|
||||||
|
{
|
||||||
|
var property = properties[index];
|
||||||
|
var value = ReadData(reader, property.PropertyType, context);
|
||||||
|
property.SetValue(obj, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndArray();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
reader.ReadEndArray();
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<PropertyInfo> FilterProperties(PropertyInfo[] properties)
|
||||||
|
{
|
||||||
|
var finalProperties = new List<PropertyInfo>(properties.Length);
|
||||||
|
foreach (var property in properties.Where(i => i.CanWrite && i.CanRead))
|
||||||
|
{
|
||||||
|
if (property.GetCustomAttribute<SerializationIgnoreAttribute>() == null)
|
||||||
|
finalProperties.Add(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
return finalProperties;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Cbor
|
||||||
|
{
|
||||||
|
public interface IContextualSerializationToolKit : ISerializationToolkit
|
||||||
|
{
|
||||||
|
byte[] Serialize(object objectToSerialize, IEndPointContext? context);
|
||||||
|
void Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext? context);
|
||||||
|
T Deserialize<T>(byte[] rawData, IEndPointContext? context);
|
||||||
|
object? Deserialize(byte[] rawData, Type type, IEndPointContext? context);
|
||||||
|
T Deserialize<T>(ReadOnlyMemory<byte> rawMemory, IEndPointContext? context);
|
||||||
|
object? Deserialize(ReadOnlyMemory<byte> rawMemory, Type type, IEndPointContext? context);
|
||||||
|
T Cast<T>(object nonCasted, IEndPointContext? context);
|
||||||
|
object? Cast(object nonCasted, Type type, IEndPointContext? context);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Cbor
|
||||||
|
{
|
||||||
|
public interface IPreParsedValue
|
||||||
|
{
|
||||||
|
object? ToObject(Type type, IEndPointContext? context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PreParsedValue : IPreParsedValue
|
||||||
|
{
|
||||||
|
public PreParsedValue(List<object> properties)
|
||||||
|
{
|
||||||
|
_properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<object> _properties { get; set; }
|
||||||
|
|
||||||
|
public object? ToObject(Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
if (type.IsInterface)
|
||||||
|
{
|
||||||
|
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type);
|
||||||
|
var so =
|
||||||
|
Activator.CreateInstance(sharedShell) as
|
||||||
|
ISharedObjectShell;
|
||||||
|
if (context != null)
|
||||||
|
so.EndPointContext = context;
|
||||||
|
|
||||||
|
so.Identifier = ComplexObjectIdentifier.FromFlat((ulong)_properties[0]);
|
||||||
|
return so.UniversalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance = Activator.CreateInstance(type);
|
||||||
|
if (instance == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (instance is ISharedObjectShell sharedObject && context != null)
|
||||||
|
{
|
||||||
|
sharedObject.EndPointContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = CborSerializationToolkit.FilterProperties(type.GetProperties());
|
||||||
|
for (var index = 0; index < properties.Count; index++)
|
||||||
|
{
|
||||||
|
var property = properties[index];
|
||||||
|
property.SetValue(instance,
|
||||||
|
_properties[index] is IPreParsedValue ppv
|
||||||
|
? ppv.ToObject(property.PropertyType, context)
|
||||||
|
: _properties[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParsedValue : IPreParsedValue
|
||||||
|
{
|
||||||
|
private object? _value;
|
||||||
|
|
||||||
|
public ParsedValue(object? value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public object? ToObject(Type type, IEndPointContext? context)
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
<DefineConstants />
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||||
|
<DefineConstants />
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\mROA\mROA.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Formats.Cbor" Version="9.0.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -25,13 +25,17 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" />
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
|
||||||
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="test.tpt" />
|
||||||
|
<EmbeddedResource Include="test.tpt" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
+628
-232
@@ -1,3 +1,6 @@
|
|||||||
|
// #define DONT_ADD
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -6,174 +9,146 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
|
||||||
|
namespace mROA.Codegen
|
||||||
namespace mROA.Codegen;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A sample source generator that creates a custom report based on class properties. The target class should be annotated with the 'Generators.ReportAttribute' attribute.
|
|
||||||
/// When using the source code as a baseline, an incremental source generator is preferable because it reduces the performance overhead.
|
|
||||||
/// </summary>
|
|
||||||
[Generator]
|
|
||||||
public class mROASourceGenerator : IIncrementalGenerator
|
|
||||||
{
|
{
|
||||||
private const string Namespace = "mROA.Implementation";
|
|
||||||
private const string AttributeName = "SharedObjectInterafceAttribute";
|
|
||||||
|
|
||||||
private const string AttributeSourceCode = $@"// <auto-generated/>
|
|
||||||
|
|
||||||
namespace {Namespace}
|
|
||||||
{{
|
|
||||||
[System.AttributeUsage(System.AttributeTargets.Class)]
|
|
||||||
public class {AttributeName} : System.Attribute
|
|
||||||
{{
|
|
||||||
}}
|
|
||||||
}}";
|
|
||||||
|
|
||||||
public void Initialize(IncrementalGeneratorInitializationContext context)
|
|
||||||
{
|
|
||||||
// Filter classes annotated with the [Report] attribute. Only filtered Syntax Nodes can trigger code generation.
|
|
||||||
var provider = context.SyntaxProvider
|
|
||||||
.CreateSyntaxProvider(
|
|
||||||
(s, _) => s is InterfaceDeclarationSyntax,
|
|
||||||
(ctx, _) => GetClassDeclarationForSourceGen(ctx))
|
|
||||||
.Where(t => t.reportAttributeFound)
|
|
||||||
.Select((t, _) => t.Item1);
|
|
||||||
|
|
||||||
// Generate the source code.
|
|
||||||
context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()),
|
|
||||||
((ctx, t) => GenerateCode(ctx, t.Left, t.Right)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whether the Node is annotated with the [Report] attribute and maps syntax context to the specific node type (ClassDeclarationSyntax).
|
/// A sample source generator that creates a custom report based on class properties. The target class should be annotated with the 'Generators.ReportAttribute' attribute.
|
||||||
|
/// When using the source code as a baseline, an incremental source generator is preferable because it reduces the performance overhead.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context">Syntax context, based on CreateSyntaxProvider predicate</param>
|
[Generator]
|
||||||
/// <returns>The specific cast and whether the attribute was found.</returns>
|
public class mROASourceGenerator : ISourceGenerator
|
||||||
private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen(
|
|
||||||
GeneratorSyntaxContext context)
|
|
||||||
{
|
{
|
||||||
var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node;
|
private static Predicate<IParameterSymbol> ParameterFilter =
|
||||||
|
i => i.Type.Name is "CancellationToken" or "RequestContext";
|
||||||
|
|
||||||
// Go through all attributes of the class.
|
private static Predicate<ITypeSymbol> ParameterFilterForType =
|
||||||
foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists)
|
i => i.Name is "CancellationToken" or "RequestContext";
|
||||||
foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
|
|
||||||
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
{
|
{
|
||||||
if (context.SemanticModel.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
|
||||||
continue; // if we can't get the symbol, ignore it
|
|
||||||
|
|
||||||
string attributeName = attributeSymbol.ContainingType.ToDisplayString();
|
|
||||||
|
|
||||||
// Check the full name of the [Report] attribute.
|
|
||||||
if (attributeName == "mROA.Implementation.Attributes.SharedObjectInterfaceAttribute")
|
|
||||||
return (classDeclarationSyntax, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (classDeclarationSyntax, false);
|
public void Execute(GeneratorExecutionContext context)
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate code action.
|
|
||||||
/// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Source generation context used to add source files.</param>
|
|
||||||
/// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
|
|
||||||
/// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
|
|
||||||
private void GenerateCode(SourceProductionContext context, Compilation compilation,
|
|
||||||
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
|
||||||
{
|
|
||||||
var methods = new List<(string, IMethodSymbol)>();
|
|
||||||
var frontendContextRepo = new List<string>();
|
|
||||||
// Go through all filtered class declarations.
|
|
||||||
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
|
||||||
foreach (var classDeclarationSyntax in declarations)
|
|
||||||
{
|
{
|
||||||
// We need to get semantic model of the class to retrieve metadata.
|
var trees = context.Compilation.SyntaxTrees;
|
||||||
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
|
||||||
|
|
||||||
|
var interfaces = new List<InterfaceDeclarationSyntax>();
|
||||||
// Symbols allow us to get the compile-time information.
|
foreach (var tree in trees)
|
||||||
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
|
|
||||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
|
||||||
|
|
||||||
// 'Identifier' means the token of the node. Get class name from the syntax node.
|
|
||||||
var className = classDeclarationSyntax.Identifier.Text;
|
|
||||||
|
|
||||||
// Go through all class members with a particular type (property) to generate method lines.
|
|
||||||
var methodBody = classSymbol.GetMembers()
|
|
||||||
.OfType<IMethodSymbol>().OrderBy(i => i.Name);
|
|
||||||
|
|
||||||
var originalName = className;
|
|
||||||
// Build up the source code
|
|
||||||
className = className.TrimStart('I') + "RemoteEndpoint";
|
|
||||||
|
|
||||||
|
|
||||||
var methodsText = new List<string>();
|
|
||||||
|
|
||||||
foreach (var method in methodBody)
|
|
||||||
{
|
{
|
||||||
var index = methods.Count;
|
var node = tree.GetRoot() as CompilationUnitSyntax;
|
||||||
methods.Add((namespaceName + "." + originalName, method));
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
|
|
||||||
|
foreach (var member in node.Members)
|
||||||
|
{
|
||||||
|
if (member is InterfaceDeclarationSyntax ids)
|
||||||
|
{
|
||||||
|
interfaces.Add(ids);
|
||||||
|
}
|
||||||
|
else if (member is NamespaceDeclarationSyntax nds)
|
||||||
|
{
|
||||||
|
foreach (var inside in nds.Members)
|
||||||
|
|
||||||
bool isAsync = method.ReturnType.Name == "Task";
|
if (inside is InterfaceDeclarationSyntax ids2)
|
||||||
bool isVoid = method.ReturnType.Name == "Void" || method.ReturnType.ToString() == "Task";
|
if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2))
|
||||||
bool isParametrized = method.Parameters.Length == 1 && !isAsync ||
|
interfaces.Add(ids2);
|
||||||
method.Parameters.Length == 2 && isAsync;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Creating signature
|
|
||||||
sb.AppendLine("public" + (isAsync
|
|
||||||
? " async "
|
|
||||||
: " ") +
|
|
||||||
$"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
|
|
||||||
|
|
||||||
|
|
||||||
var prefix = isAsync ? "await " : "";
|
|
||||||
var postfix = !isAsync ? (isVoid? ".Wait()" : ".GetAwaiter().GetResult()") : "";
|
|
||||||
var parameterLink = isParametrized ? ", " + method.Parameters.First().Name : string.Empty;
|
|
||||||
var caller = isVoid ? $"CallAsync({index}{parameterLink})" :
|
|
||||||
isAsync ? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink})" :
|
|
||||||
$"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink})";
|
|
||||||
|
|
||||||
if (!isVoid)
|
|
||||||
prefix = "return " + prefix;
|
|
||||||
|
|
||||||
// if (method.ReturnType.OriginalDefinition.ToString() == "System.Threading.Tasks.Task<TResult>")
|
|
||||||
// {
|
|
||||||
// var type = method.ReturnType.ToString();
|
|
||||||
// type = type.Substring(type.IndexOf('<') + 1);
|
|
||||||
// type = type.Substring(0, type.Length - 1);
|
|
||||||
// sb.AppendLine(
|
|
||||||
// $"\t\tvar response = await serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId);");
|
|
||||||
// sb.AppendLine($"\t\treturn ({type})response.Result;");
|
|
||||||
// }
|
|
||||||
// else if (!isAsync && method.ReturnType.ToDisplayString() != "void")
|
|
||||||
// {
|
|
||||||
// var type = method.ReturnType.ToDisplayString();
|
|
||||||
// sb.AppendLine(
|
|
||||||
// $"\t\tvar response = serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId).GetAwaiter().GetResult();");
|
|
||||||
// sb.AppendLine($"\t\treturn ({type})response.Result;");
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// sb.AppendLine(
|
|
||||||
// "\t\tserialisationModule.GetNextCommandExecution<FinalCommandExecution>(defaultCallRequestCodegen.CallRequestId).Wait();");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// sb.AppendLine("\t}");
|
|
||||||
|
|
||||||
sb.AppendLine("\t\t" + prefix + caller + postfix+ ";");
|
|
||||||
|
|
||||||
sb.AppendLine("\t}");
|
|
||||||
|
|
||||||
methodsText.Add(sb.ToString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var code = $@"// <auto-generated/>
|
GenerateCode(context, context.Compilation, interfaces.ToImmutableArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
|
||||||
|
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
||||||
|
{
|
||||||
|
// For future
|
||||||
|
// var asm = Assembly.GetAssembly(typeof(mROASourceGenerator));
|
||||||
|
// var files = asm.GetManifestResourceNames();
|
||||||
|
// var test = asm.GetManifestResourceStream("mROA.Codegen.test.tpt");
|
||||||
|
// var reader = new StreamReader(test);
|
||||||
|
// var allText = reader.ReadToEnd();
|
||||||
|
var frontendContextRepo = new List<string>();
|
||||||
|
var eventBinders = new List<string>();
|
||||||
|
List<IMethodSymbol> totalMethods = new List<IMethodSymbol>();
|
||||||
|
|
||||||
|
|
||||||
|
List<string> invokers = new List<string>();
|
||||||
|
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
||||||
|
foreach (var classDeclarationSyntax in declarations)
|
||||||
|
{
|
||||||
|
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
||||||
|
|
||||||
|
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
||||||
|
continue;
|
||||||
|
List<IMethodSymbol> innerMethods = new List<IMethodSymbol>();
|
||||||
|
|
||||||
|
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||||
|
var className = classDeclarationSyntax.Identifier.Text;
|
||||||
|
innerMethods = CollectMembers(classSymbol);
|
||||||
|
var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null)
|
||||||
|
.Distinct(SymbolEqualityComparer.Default).Cast<ISymbol>().ToList();
|
||||||
|
|
||||||
|
innerMethods = innerMethods.Where(i =>
|
||||||
|
i.MethodKind != MethodKind.EventAdd && i.MethodKind != MethodKind.EventRemove)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
totalMethods.AddRange(innerMethods);
|
||||||
|
|
||||||
|
var originalName = className;
|
||||||
|
|
||||||
|
className = className.TrimStart('I') + "RemoteEndpoint";
|
||||||
|
|
||||||
|
|
||||||
|
var declaredMethods = new List<string>();
|
||||||
|
var propertiesAccessMethods = new List<(string, IMethodSymbol)>();
|
||||||
|
|
||||||
|
foreach (var method in innerMethods)
|
||||||
|
{
|
||||||
|
switch (method.MethodKind)
|
||||||
|
{
|
||||||
|
case MethodKind.PropertyGet or MethodKind.PropertySet:
|
||||||
|
GeneratePropertyMethod(method, propertiesAccessMethods, invokers,
|
||||||
|
classSymbol);
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
GenerateDeclaredMethod(method, declaredMethods, invokers, classSymbol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var symbol in associated)
|
||||||
|
{
|
||||||
|
switch (symbol)
|
||||||
|
{
|
||||||
|
case IPropertySymbol propertySymbol:
|
||||||
|
|
||||||
|
var setter = propertiesAccessMethods.FirstOrDefault(i =>
|
||||||
|
i.Item2.AssociatedSymbol!.Name == propertySymbol.Name && i.Item2.ReturnsVoid);
|
||||||
|
var getter = propertiesAccessMethods.FirstOrDefault(i =>
|
||||||
|
i.Item2.AssociatedSymbol!.Name == propertySymbol.Name && !i.Item2.ReturnsVoid);
|
||||||
|
string impl;
|
||||||
|
if (propertySymbol.IsIndexer)
|
||||||
|
{
|
||||||
|
impl =
|
||||||
|
$"public {propertySymbol.Type.ToDisplayString()} this[{string.Join(", ", propertySymbol.Parameters.Select(p => p.ToDisplayString()))}] {{ {getter.Item1} {setter.Item1} }}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
impl =
|
||||||
|
$"public {propertySymbol.Type.ToDisplayString()} {symbol.Name} {{ {getter.Item1} {setter.Item1} }}";
|
||||||
|
}
|
||||||
|
|
||||||
|
declaredMethods.Add(impl);
|
||||||
|
break;
|
||||||
|
case IEventSymbol eventSymbol:
|
||||||
|
declaredMethods.Add(
|
||||||
|
$"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateEventImplementation(classSymbol, invokers, declaredMethods, context, eventBinders);
|
||||||
|
|
||||||
|
var code = $@"// <auto-generated/>
|
||||||
|
|
||||||
using mROA;
|
using mROA;
|
||||||
using System;
|
using System;
|
||||||
@@ -181,106 +156,527 @@ using mROA.Implementation;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace {namespaceName};
|
namespace {namespaceName}
|
||||||
|
|
||||||
partial class {className} : RemoteObjectBase, {originalName}
|
|
||||||
{{
|
{{
|
||||||
public {className}(int id, IRepresentationModule representationModule) : base(id, representationModule)
|
partial class {className} : RemoteObjectBase, {originalName}
|
||||||
{{
|
{{
|
||||||
}}
|
public {className}(int id, IRepresentationModule representationModule) : base(id, representationModule)
|
||||||
|
{{
|
||||||
|
}}
|
||||||
|
|
||||||
{string.Join("\r\n\t", methodsText)}
|
{string.Join("\r\n\t\t", declaredMethods)}
|
||||||
|
}}
|
||||||
}}
|
}}
|
||||||
";
|
";
|
||||||
|
|
||||||
|
|
||||||
// Add the source code to the compilation.
|
// Add the source code to the compilation.
|
||||||
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
#if !DONT_ADD
|
||||||
|
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
||||||
|
#endif
|
||||||
|
frontendContextRepo.Add(
|
||||||
|
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
|
||||||
|
}
|
||||||
|
|
||||||
frontendContextRepo.Add(
|
if (totalMethods.Count != 0)
|
||||||
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
|
{
|
||||||
}
|
var methodsStringed = invokers;
|
||||||
|
|
||||||
if (methods.Count != 0)
|
var coCodegenRepoCode = @$"// <auto-generated/>
|
||||||
{
|
|
||||||
var methodsStringed = methods.Select(i =>
|
|
||||||
$"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", [{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}])")
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var coCodegenRepoCode = @$"// <auto-generated/>
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Codegen;
|
|
||||||
|
|
||||||
public class CoCodegenMethodRepository : IMethodRepository
|
|
||||||
{{
|
|
||||||
private readonly List<MethodInfo> _methods = [
|
|
||||||
{string.Join(", // test comment\r\n\t\t", methodsStringed)}
|
|
||||||
];
|
|
||||||
public MethodInfo GetMethod(int id)
|
|
||||||
{{
|
|
||||||
if (_methods.Count <= id)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
return _methods[id];
|
|
||||||
}}
|
|
||||||
|
|
||||||
public int RegisterMethod(MethodInfo method)
|
|
||||||
{{
|
|
||||||
_methods.Add(method);
|
|
||||||
return _methods.Count - 1;
|
|
||||||
}}
|
|
||||||
|
|
||||||
public IEnumerable<MethodInfo> GetMethods()
|
|
||||||
{{
|
|
||||||
return _methods;
|
|
||||||
}}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{{
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
";
|
|
||||||
context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frontendContextRepo.Count != 0)
|
|
||||||
{
|
|
||||||
var fronendRepoCode = @$"// <auto-generated/>
|
|
||||||
using System.Collections.Frozen;
|
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
using mROA.Abstract;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace mROA.Codegen;
|
namespace mROA.Codegen
|
||||||
|
|
||||||
public sealed class RemoteTypeBinder
|
|
||||||
{{
|
{{
|
||||||
static RemoteTypeBinder(){{
|
public class CoCodegenMethodRepository : IMethodRepository
|
||||||
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {{
|
{{
|
||||||
{string.Join(", \r\n\t\t", frontendContextRepo)}}}.ToFrozenDictionary();
|
private readonly List<IMethodInvoker> _methods = new () {{
|
||||||
|
{string.Join(",\r\n\t\t\t", methodsStringed)}
|
||||||
|
}};
|
||||||
|
|
||||||
|
public IMethodInvoker GetMethod(int id)
|
||||||
|
{{
|
||||||
|
if (id == -1)
|
||||||
|
return mROA.Implementation.MethodInvoker.Dispose;
|
||||||
|
|
||||||
|
if (_methods.Count <= id)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return _methods[id];
|
||||||
|
}}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{{
|
||||||
|
}}
|
||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
";
|
";
|
||||||
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
#if !DONT_ADD
|
||||||
|
context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (frontendContextRepo.Count != 0)
|
||||||
|
{
|
||||||
|
var fronendRepoCode = @$"// <auto-generated/>
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation.Backend;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Codegen
|
||||||
|
{{
|
||||||
|
public sealed class RemoteTypeBinder
|
||||||
|
{{
|
||||||
|
static RemoteTypeBinder(){{
|
||||||
|
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {{
|
||||||
|
{string.Join(", \r\n\t\t\t", frontendContextRepo)}}};
|
||||||
|
ContextRepository.EventBinders = new object[] {{
|
||||||
|
{string.Join(",\r\n\t\t\t", eventBinders)}}};
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
";
|
||||||
|
#if !DONT_ADD
|
||||||
|
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static string ToFullString(IParameterSymbol parameter)
|
private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List<string> invokers,
|
||||||
=> /*parameter.Type.ContainingNamespace is null*/
|
List<string> declaredMethods, GeneratorExecutionContext context, List<string> binders)
|
||||||
/*?*/ parameter.ToDisplayString();
|
{
|
||||||
/*: $"{parameter.Type.ContainingNamespace.ToDisplayString()}.{parameter.Type.MetadataName} {parameter.Name}";*/
|
var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers())
|
||||||
|
.OfType<IEventSymbol>().ToList();
|
||||||
|
if (events.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
private static string ToFullString(ITypeSymbol type) =>
|
var additionalSignatures = new List<string>(events.Count);
|
||||||
// => type.ContainingNamespace is null || type.Name == "Void"
|
var singleEventBinder = new List<string>(events.Count);
|
||||||
type.ToDisplayString();
|
for (int i = 0; i < events.Count; i++)
|
||||||
// : $"{type.ContainingNamespace.ToDisplayString()}.{type.MetadataName}";
|
{
|
||||||
|
var currentEvent = events[i];
|
||||||
|
|
||||||
private string ExtractTaskType(ITypeSymbol taskType)
|
var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature);
|
||||||
{
|
declaredMethods.Add(additionalMethod);
|
||||||
var type = taskType.ToString();
|
additionalSignatures.Add(signature);
|
||||||
type = type.Substring(type.IndexOf('<') + 1);
|
GenerateEventCode(currentEvent, invokers, classSymbol);
|
||||||
return type.Substring(0, type.Length - 1);
|
GenerateBinderCode(currentEvent, invokers, classSymbol, singleEventBinder);
|
||||||
|
}
|
||||||
|
|
||||||
|
var partialInterface = $@"
|
||||||
|
namespace {classSymbol.ContainingNamespace.ToDisplayString()}
|
||||||
|
{{
|
||||||
|
public partial interface {classSymbol.Name}
|
||||||
|
{{
|
||||||
|
{string.Join("\r\n", additionalSignatures)}
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
";
|
||||||
|
var binder = $@"new EventBinder<{classSymbol.ToDisplayString()}>
|
||||||
|
{{
|
||||||
|
BindAction = (instance, context, representationProducer, index) =>
|
||||||
|
{{
|
||||||
|
var ownerId = context.OwnerId;
|
||||||
|
var module = representationProducer.Produce(ownerId);
|
||||||
|
{string.Join("\r\n", singleEventBinder)}
|
||||||
|
}}
|
||||||
|
}}";
|
||||||
|
binders.Add(binder);
|
||||||
|
#if !DONT_ADD
|
||||||
|
context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateMethodExternalCaller(IEventSymbol eventSymbol, out string interfaceSignature)
|
||||||
|
{
|
||||||
|
var level = "\t\t";
|
||||||
|
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments;
|
||||||
|
var parameterIndex = 0;
|
||||||
|
var parametersDeclaration =
|
||||||
|
string.Join(", ", parameters.Select(i => $"{i.ToDisplayString()} p{parameterIndex++}"));
|
||||||
|
var signature = $@"public void {EventExternalName(eventSymbol)}({parametersDeclaration})";
|
||||||
|
interfaceSignature = level + signature + ";";
|
||||||
|
var caller = $@"{signature}
|
||||||
|
{level}{{
|
||||||
|
{level} {eventSymbol.Name}?.Invoke({string.Join(", ", Enumerable.Range(0, parameterIndex).Select(i => "p" + i))});
|
||||||
|
{level}}}
|
||||||
|
";
|
||||||
|
return caller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string EventExternalName(IEventSymbol eventSymbol) => $"{eventSymbol.Name}External";
|
||||||
|
|
||||||
|
private static string Caster(ITypeSymbol type, string inner)
|
||||||
|
{
|
||||||
|
if (!type.IsValueType)
|
||||||
|
return inner +
|
||||||
|
" as " +
|
||||||
|
type.ToDisplayString();
|
||||||
|
return $"({type.ToDisplayString()})" + inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateDeclaredMethod(IMethodSymbol method, List<string> declaredMethods, List<string> invokers,
|
||||||
|
INamedTypeSymbol baseInterace)
|
||||||
|
{
|
||||||
|
var index = invokers.Count;
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
bool isParametrized;
|
||||||
|
|
||||||
|
bool isAsync;
|
||||||
|
bool isVoid;
|
||||||
|
|
||||||
|
List<IParameterSymbol>? parameters;
|
||||||
|
|
||||||
|
switch (method.ReturnType)
|
||||||
|
{
|
||||||
|
case INamedTypeSymbol namedType:
|
||||||
|
isAsync = namedType.Name == "Task";
|
||||||
|
isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void";
|
||||||
|
parameters = method.Parameters.ToList();
|
||||||
|
parameters.RemoveAll(ParameterFilter);
|
||||||
|
isParametrized = parameters.Count != 0;
|
||||||
|
break;
|
||||||
|
case IArrayTypeSymbol:
|
||||||
|
isAsync = false;
|
||||||
|
isVoid = false;
|
||||||
|
parameters = new List<IParameterSymbol>();
|
||||||
|
isParametrized = method.Parameters.Length != 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Creating signature
|
||||||
|
sb.AppendLine("public" + (isAsync
|
||||||
|
? " async "
|
||||||
|
: " ") +
|
||||||
|
$"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
|
||||||
|
|
||||||
|
|
||||||
|
var prefix = isAsync ? "await " : "";
|
||||||
|
var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : "";
|
||||||
|
var parameterLink = isParametrized
|
||||||
|
? ", new object[] {" + string.Join(", ", parameters.Select(i => i.Name)) + "}"
|
||||||
|
: string.Empty;
|
||||||
|
var tokenInsert = isAsync && method.Parameters.FirstOrDefault(i => i.Type.Name == "CancellationToken") is
|
||||||
|
{ } tokenSymbol
|
||||||
|
? ", cancellationToken : " + tokenSymbol.Name
|
||||||
|
: String.Empty;
|
||||||
|
var caller = isVoid
|
||||||
|
? $"CallAsync({index}{parameterLink}{tokenInsert})"
|
||||||
|
: isAsync
|
||||||
|
? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink}{tokenInsert})"
|
||||||
|
: $"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink}{tokenInsert})";
|
||||||
|
|
||||||
|
if (!isVoid)
|
||||||
|
prefix = "return " + prefix;
|
||||||
|
|
||||||
|
sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";");
|
||||||
|
|
||||||
|
sb.AppendLine("\t\t}");
|
||||||
|
|
||||||
|
declaredMethods.Add(sb.ToString());
|
||||||
|
var parameterTypes = string.Join(", ",
|
||||||
|
$"{string.Join(", ", parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}");
|
||||||
|
var level = "\t\t\t";
|
||||||
|
|
||||||
|
var parametersInsertList = new List<string>();
|
||||||
|
|
||||||
|
for (var i = 0; i < method.Parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameter = method.Parameters[i];
|
||||||
|
switch (parameter.Type.Name)
|
||||||
|
{
|
||||||
|
case "CancellationToken":
|
||||||
|
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||||
|
break;
|
||||||
|
case "RequestContext":
|
||||||
|
parametersInsertList.Add("special[0] as RequestContext");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parametersInsertList.Add(Caster(parameter.Type,
|
||||||
|
$"parameters[{parameters.IndexOf(parameter)}]"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parametersInsert = string.Join(", ", parametersInsertList);
|
||||||
|
var backend = string.Empty;
|
||||||
|
|
||||||
|
var funcInvoking = string.Empty;
|
||||||
|
|
||||||
|
if (isAsync && !isVoid)
|
||||||
|
funcInvoking =
|
||||||
|
$"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(t.Result); }})";
|
||||||
|
else if (isAsync && isVoid)
|
||||||
|
funcInvoking =
|
||||||
|
$"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert}).ContinueWith(t => {{ post(null); }})";
|
||||||
|
else if (!isAsync && isVoid)
|
||||||
|
{
|
||||||
|
funcInvoking = $@"{{
|
||||||
|
{level} (i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert});
|
||||||
|
{level} return null;
|
||||||
|
{level} }}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
funcInvoking = $"(i as {method.ContainingType.ToDisplayString()}).{method.Name}({parametersInsert})";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAsync)
|
||||||
|
backend = $@"new mROA.Implementation.AsyncMethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = {isVoid.ToString().ToLower()},
|
||||||
|
{(isVoid ? String.Empty : (level + "\t" + "ReturnType = typeof(" + ExtractTaskType(method.ReturnType)) + "),")}
|
||||||
|
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, special, post) => {funcInvoking},
|
||||||
|
{level}}}";
|
||||||
|
else
|
||||||
|
backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = {isVoid.ToString().ToLower()},
|
||||||
|
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||||
|
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, special) => {funcInvoking}
|
||||||
|
{level}}}";
|
||||||
|
|
||||||
|
invokers.Add(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateBinderCode(IEventSymbol eventSymbol, List<string> invokers, INamedTypeSymbol baseType,
|
||||||
|
List<string> binders)
|
||||||
|
{
|
||||||
|
var index = invokers.Count - 1;
|
||||||
|
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments.ToList();
|
||||||
|
int parameterIndex = 0;
|
||||||
|
var parametersDeclaration = string.Join(", ",
|
||||||
|
JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i++)));
|
||||||
|
|
||||||
|
var transferParameters =
|
||||||
|
JoinWithComa(parameters.Where(i => !ParameterFilterForType(i))
|
||||||
|
.Select(i => "p" + parameters.IndexOf(i)));
|
||||||
|
|
||||||
|
var callFilter = "";
|
||||||
|
|
||||||
|
var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext");
|
||||||
|
if (requestIndex != -1)
|
||||||
|
{
|
||||||
|
callFilter = $"\n\r\t\t\tif(ownerId == p{requestIndex}.OwnerId) return;";
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventBinderCode =
|
||||||
|
$@" (instance as {baseType.ToDisplayString()}).{eventSymbol.Name} += ({parametersDeclaration}) =>
|
||||||
|
{{
|
||||||
|
Console.WriteLine($""Try to send to {{ownerId}} with hash code {{context.GetHashCode()}}"");
|
||||||
|
{callFilter}
|
||||||
|
Console.WriteLine(""Sending event..."");
|
||||||
|
var request = new DefaultCallRequest
|
||||||
|
{{
|
||||||
|
CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, ownerId), Parameters = new object[] {{ {transferParameters} }}
|
||||||
|
}};
|
||||||
|
module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request);
|
||||||
|
}};
|
||||||
|
";
|
||||||
|
binders.Add(eventBinderCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string JoinWithComa(IEnumerable<string> parts) => string.Join(", ", parts);
|
||||||
|
|
||||||
|
private void GenerateEventCode(IEventSymbol eventSymbol, List<string> invokers, ITypeSymbol baseInterface)
|
||||||
|
{
|
||||||
|
var level = "\t\t\t";
|
||||||
|
|
||||||
|
var parameters = (eventSymbol.Type as INamedTypeSymbol).TypeArguments;
|
||||||
|
var parsingParameters = parameters.RemoveAll(ParameterFilterForType).ToList();
|
||||||
|
var parameterTypes = string.Join(", ",
|
||||||
|
$"{string.Join(", ", parsingParameters.Select(p => $"typeof({p.ToDisplayString()})"))}");
|
||||||
|
|
||||||
|
var parametersInsertList = new List<string>();
|
||||||
|
|
||||||
|
for (var i = 0; i < parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameter = parameters[i];
|
||||||
|
switch (parameter.Name)
|
||||||
|
{
|
||||||
|
case "CancellationToken":
|
||||||
|
parametersInsertList.Add("(CancellationToken)special[1]");
|
||||||
|
break;
|
||||||
|
case "RequestContext":
|
||||||
|
parametersInsertList.Add("special[0] as RequestContext");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parametersInsertList.Add(Caster(parameter,
|
||||||
|
$"parameters[{parameters.IndexOf(parameter)}]"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parametersInsert = string.Join(", ", parametersInsertList);
|
||||||
|
var backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = true,
|
||||||
|
{level} ReturnType = typeof(void),
|
||||||
|
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||||
|
{level} SuitableType = typeof({baseInterface.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, special) => {{
|
||||||
|
{level} (i as {baseInterface.ToDisplayString()}).{EventExternalName(eventSymbol)}({parametersInsert});
|
||||||
|
{level} return null;
|
||||||
|
{level} }}
|
||||||
|
{level}}}";
|
||||||
|
invokers.Add(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GeneratePropertyMethod(IMethodSymbol method,
|
||||||
|
List<(string, IMethodSymbol)> propsCollection, List<string> invokers, INamedTypeSymbol baseInterace)
|
||||||
|
{
|
||||||
|
var level = "\t\t\t";
|
||||||
|
var index = invokers.Count;
|
||||||
|
string frontend;
|
||||||
|
string backend = string.Empty;
|
||||||
|
if (method.MethodKind == MethodKind.PropertyGet)
|
||||||
|
{
|
||||||
|
var parametersArray = "";
|
||||||
|
if (method.Parameters.Length != 0)
|
||||||
|
{
|
||||||
|
parametersArray = $", new object[] {{{string.Join(", ", method.Parameters.Select(p => p.Name))}}}";
|
||||||
|
|
||||||
|
var parameterTypes = string.Join(", ",
|
||||||
|
$"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToDisplayString() + ")"))}");
|
||||||
|
var parameterInserts = string.Join(", ",
|
||||||
|
method.Parameters.Select(
|
||||||
|
p => Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]")));
|
||||||
|
backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = false,
|
||||||
|
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||||
|
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}],
|
||||||
|
{level}}}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = false,
|
||||||
|
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name},
|
||||||
|
{level}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend =
|
||||||
|
$"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).GetAwaiter().GetResult();";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parametersArray = "value";
|
||||||
|
if (method.Parameters.Length != 1)
|
||||||
|
{
|
||||||
|
parametersArray = string.Join(", ", method.Parameters.Select(p => p.Name));
|
||||||
|
|
||||||
|
var parameterTypes = string.Join(", ",
|
||||||
|
$"{string.Join(", ", method.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}");
|
||||||
|
var parameterInserts = string.Join(", ",
|
||||||
|
method.Parameters.Take(method.Parameters.Length - 1).Select(p =>
|
||||||
|
{
|
||||||
|
return Caster(p.Type, "parameters[" + method.Parameters.IndexOf(p) + "]");
|
||||||
|
// if (!p.Type.IsValueType)
|
||||||
|
// return "parameters[" + method.Parameters.IndexOf(p) + "] as " +
|
||||||
|
// p.Type.ToDisplayString();
|
||||||
|
// return $"({p.Type.ToDisplayString()})parameters[{method.Parameters.IndexOf(p)}]";
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
// var valueInsert = !method.Parameters.Last().Type.IsValueType
|
||||||
|
// ? "parameters[" + (method.Parameters.Length - 1) + "] as " +
|
||||||
|
// method.Parameters.Last().Type.ToDisplayString()
|
||||||
|
// : $"({method.Parameters.Last().Type.ToDisplayString()})parameters[{method.Parameters.Length - 1}]";
|
||||||
|
var valueInsert = Caster(method.Parameters.Last().Type,
|
||||||
|
"parameters[" + (method.Parameters.Length - 1) + "]");
|
||||||
|
backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = true,
|
||||||
|
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||||
|
{level} ParameterTypes = new Type[] {{ {parameterTypes} }},
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert},
|
||||||
|
{level}}}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
backend = $@"new mROA.Implementation.MethodInvoker
|
||||||
|
{level}{{
|
||||||
|
{level} IsVoid = true,
|
||||||
|
{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}),
|
||||||
|
{level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.ToDisplayString()}) }},
|
||||||
|
{level} SuitableType = typeof({baseInterace.ToDisplayString()}),
|
||||||
|
{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")},
|
||||||
|
{level}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
frontend = $"set => CallAsync({index}, new object[] {{ {parametersArray} }}).Wait();";
|
||||||
|
}
|
||||||
|
|
||||||
|
propsCollection.Add((frontend, method));
|
||||||
|
invokers.Add(backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToFullString(IParameterSymbol parameter)
|
||||||
|
=> /*parameter.Type.ContainingNamespace is null*/
|
||||||
|
/*?*/ parameter.ToDisplayString();
|
||||||
|
/*: $"{parameter.Type.ContainingNamespace.ToDisplayString()}.{parameter.Type.MetadataName} {parameter.Name}";*/
|
||||||
|
|
||||||
|
private static string ToFullString(ITypeSymbol type) =>
|
||||||
|
// => type.ContainingNamespace is null || type.Name == "Void"
|
||||||
|
type.ToDisplayString();
|
||||||
|
// : $"{type.ContainingNamespace.ToDisplayString()}.{type.MetadataName}";
|
||||||
|
|
||||||
|
private string ExtractTaskType(ITypeSymbol taskType)
|
||||||
|
{
|
||||||
|
return (taskType as INamedTypeSymbol).TypeArguments[0].ToDisplayString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
|
||||||
|
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
|
||||||
|
{
|
||||||
|
foreach (var attributeSyntax in
|
||||||
|
attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes))
|
||||||
|
{
|
||||||
|
if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree)
|
||||||
|
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
||||||
|
continue; // if we can't get the symbol, ignore it
|
||||||
|
|
||||||
|
string attributeName = attributeSymbol.ContainingType.ToDisplayString();
|
||||||
|
|
||||||
|
// Check the full name of the [Report] attribute.
|
||||||
|
if (attributeName == "mROA.Implementation.Attributes.SharedObjectInterfaceAttribute")
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<IMethodSymbol> CollectMembers(INamedTypeSymbol type)
|
||||||
|
{
|
||||||
|
var methods = type.GetMembers().OfType<IMethodSymbol>().ToList();
|
||||||
|
foreach (var inner in type.AllInterfaces)
|
||||||
|
{
|
||||||
|
methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
|
||||||
|
}
|
||||||
|
|
||||||
|
methods.RemoveAll(m => m.Name == "Dispose");
|
||||||
|
return methods.OrderBy(i => i.Name).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
test text
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+63
-57
@@ -1,71 +1,77 @@
|
|||||||
using System.Net;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
namespace mROA.Test;
|
namespace mROA.Test
|
||||||
|
|
||||||
public class NextGenTest
|
|
||||||
{
|
{
|
||||||
private TcpListener _listener;
|
public class NextGenTest
|
||||||
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);
|
private TcpListener _listener;
|
||||||
_interactionModuleA = new NextGenerationInteractionModule();
|
private NextGenerationInteractionModule _interactionModuleA;
|
||||||
_interactionModuleA.Inject(new JsonSerializationToolkit());
|
private NextGenerationInteractionModule _interactionModuleB;
|
||||||
_interactionModuleB = new NextGenerationInteractionModule();
|
private Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||||
_interactionModuleB.Inject(new JsonSerializationToolkit());
|
|
||||||
|
|
||||||
}
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
[Test]
|
|
||||||
public void MultithreadedTest()
|
|
||||||
{
|
|
||||||
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
{
|
||||||
_listener.Start();
|
_listener = new TcpListener(IPAddress.Loopback, 4567);
|
||||||
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
|
_interactionModuleA = new NextGenerationInteractionModule();
|
||||||
foreach (var guid in guids)
|
_interactionModuleA.Inject(new JsonSerializationToolkit());
|
||||||
{
|
_interactionModuleB = new NextGenerationInteractionModule();
|
||||||
_interactionModuleB.PostMessage(new NetworkMessage { Id = guid, Data = "Hello user"u8.ToArray() });
|
_interactionModuleB.Inject(new JsonSerializationToolkit());
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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");
|
[Test]
|
||||||
}
|
public void MultithreadedTest()
|
||||||
|
{
|
||||||
|
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
_listener.Start();
|
||||||
|
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
|
||||||
|
|
||||||
[TearDown]
|
foreach (var guid in guids)
|
||||||
public void TearDown()
|
{
|
||||||
{
|
_interactionModuleB.PostMessage(new NetworkMessage { Id = guid, Data = "Hello user"u8.ToArray() });
|
||||||
_listener.Dispose();
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" />
|
||||||
<ProjectReference Include="..\mROA\mROA.csproj" />
|
<ProjectReference Include="..\mROA\mROA.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -19,24 +19,38 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA.Cbor.csproj", "{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Events", "Events", "{032E1288-4D26-4FA5-ABB6-E7D738F319DE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Events.Shared", "Example.Events.Shared\Example.Events.Shared.csproj", "{6342C7FC-12B4-4BC6-BA25-159B1400D952}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Events.Backend", "Example.Events.Backend\Example.Events.Backend.csproj", "{B63F58B2-8D86-42F3-96A5-470CB449BFD3}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Events.Client", "Example.Events.Client\Example.Events.Client.csproj", "{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.CodegenTools", "mROA.CodegenTools\mROA.CodegenTools.csproj", "{2A2821B7-E5C5-443A-9801-9622493594A0}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Debug|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{AE4E93F6-7B91-41FC-9BEA-2C8C2CBE1CB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D0E5760B-BB6E-453A-B396-A972CD94F133}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Debug|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Debug|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6CE0ED21-88FD-44B3-B9C6-9B8FA4E07E89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{A9BB364E-0BA6-40B9-A293-757BC48EFC06}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
@@ -53,13 +67,38 @@ Global
|
|||||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.Build.0 = Release|Any CPU
|
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{6342C7FC-12B4-4BC6-BA25-159B1400D952}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{6342C7FC-12B4-4BC6-BA25-159B1400D952}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{6342C7FC-12B4-4BC6-BA25-159B1400D952}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{6342C7FC-12B4-4BC6-BA25-159B1400D952}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B63F58B2-8D86-42F3-96A5-470CB449BFD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B63F58B2-8D86-42F3-96A5-470CB449BFD3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B63F58B2-8D86-42F3-96A5-470CB449BFD3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B63F58B2-8D86-42F3-96A5-470CB449BFD3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2A2821B7-E5C5-443A-9801-9622493594A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2A2821B7-E5C5-443A-9801-9622493594A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2A2821B7-E5C5-443A-9801-9622493594A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
||||||
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
|
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
|
||||||
|
{032E1288-4D26-4FA5-ABB6-E7D738F319DE} = {EAE92F5A-664C-41AB-8811-5885524B5347}
|
||||||
|
{6342C7FC-12B4-4BC6-BA25-159B1400D952} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
|
||||||
|
{B63F58B2-8D86-42F3-96A5-470CB449BFD3} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
|
||||||
|
{98451C0E-E179-4F5F-9F1A-8B353EDE2EBC} = {032E1288-4D26-4FA5-ABB6-E7D738F319DE}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface ICancellationRepository : IInjectableModule
|
||||||
|
{
|
||||||
|
void RegisterCancellation(Guid id, CancellationTokenSource cts);
|
||||||
|
CancellationTokenSource? GetCancellation(Guid id);
|
||||||
|
void FreeCancelation(Guid id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
namespace mROA.Abstract;
|
using System;
|
||||||
|
|
||||||
public interface ICommandExecution
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
Guid Id { get; init; }
|
public interface ICommandExecution
|
||||||
int ClientId { get; set; }
|
{
|
||||||
int CommandId { get; }
|
Guid Id { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public delegate void ConnectionHandler(IRepresentationModule representationModule);
|
|
||||||
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
|
|
||||||
|
|
||||||
public interface IConnectionHub : IInjectableModule
|
|
||||||
{
|
{
|
||||||
void RegisterInteraction(INextGenerationInteractionModule interaction);
|
public delegate void ConnectionHandler(IRepresentationModule representationModule);
|
||||||
INextGenerationInteractionModule GetInteracion(int id);
|
|
||||||
event ConnectionHandler? OnConnected;
|
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
|
||||||
event DisconnectionHandler? OnDisconnected;
|
|
||||||
|
public interface IConnectionHub : IInjectableModule
|
||||||
|
{
|
||||||
|
void RegisterInteraction(INextGenerationInteractionModule interaction);
|
||||||
|
INextGenerationInteractionModule GetInteracion(int id);
|
||||||
|
event ConnectionHandler? OnConnected;
|
||||||
|
event DisconnectionHandler? OnDisconnected;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
namespace mROA.Abstract;
|
using System;
|
||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
public interface IContextRepository : IInjectableModule
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
int ResisterObject(object o);
|
public interface IContextRepository : IInjectableModule
|
||||||
void ClearObject(int id);
|
{
|
||||||
object GetObject(int id);
|
int HostId { get; set; }
|
||||||
T? GetObject<T>(int id);
|
int ResisterObject<T>(object o, IEndPointContext context);
|
||||||
T GetSingleObject<T>();
|
void ClearObject(ComplexObjectIdentifier id);
|
||||||
object GetSingleObject(Type type);
|
T GetObject<T>(ComplexObjectIdentifier id);
|
||||||
int GetObjectIndex(object o);
|
object GetSingleObject(Type type, int ownerId);
|
||||||
|
int GetObjectIndex<T>(object o, IEndPointContext context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IContextRepositoryHub
|
|
||||||
{
|
{
|
||||||
IContextRepository GetRepository(int clientId);
|
public interface IContextRepositoryHub
|
||||||
|
{
|
||||||
|
IContextRepository GetRepository(int clientId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IEndPointContext
|
||||||
|
{
|
||||||
|
IContextRepository RealRepository { get; }
|
||||||
|
IContextRepository RemoteRepository { get; }
|
||||||
|
int HostId { get; }
|
||||||
|
int OwnerId { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IEventBinder<T>
|
||||||
|
{
|
||||||
|
public void BindEvents(T source, IEndPointContext context,
|
||||||
|
IRepresentationModuleProducer representationModuleProducer, int index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IExecuteModule : IInjectableModule
|
|
||||||
{
|
{
|
||||||
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository);
|
public interface IExecuteModule : IInjectableModule
|
||||||
|
{
|
||||||
|
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
||||||
|
IRepresentationModule representationModule);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
public interface IFrontendBridge : IInjectableModule;
|
public interface IFrontendBridge : IInjectableModule
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
namespace mROA.Abstract;
|
using System;
|
||||||
|
|
||||||
public interface IGatewayModule : IDisposable, IInjectableModule
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
void Run();
|
public interface IGatewayModule : IDisposable, IInjectableModule
|
||||||
|
{
|
||||||
|
void Run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IIdentityGenerator : IInjectableModule
|
|
||||||
{
|
{
|
||||||
int GetNextIdentity();
|
public interface IIdentityGenerator : IInjectableModule
|
||||||
|
{
|
||||||
|
int GetNextIdentity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IInjectableModule
|
|
||||||
{
|
{
|
||||||
void Inject<T>(T dependency);
|
public interface IInjectableModule
|
||||||
|
{
|
||||||
|
void Inject<T>(T dependency);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
|
|
||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface INextGenerationInteractionModule : IInjectableModule
|
|
||||||
{
|
{
|
||||||
int ConnectionId { get; }
|
public interface INextGenerationInteractionModule : IInjectableModule
|
||||||
public Stream BaseStream { get; set; }
|
{
|
||||||
NetworkMessage[] UnhandledMessages { get; }
|
int ConnectionId { get; }
|
||||||
NetworkMessage LastMessage { get; }
|
public Stream? BaseStream { get; set; }
|
||||||
EventWaitHandle CurrentReceivingHandle { get; }
|
Task<NetworkMessage> GetNextMessageReceiving();
|
||||||
void StartInfiniteReceiving();
|
Task PostMessage(NetworkMessage message);
|
||||||
Task<NetworkMessage> GetNextMessageReceiving();
|
void HandleMessage(NetworkMessage message);
|
||||||
Task PostMessage(NetworkMessage message);
|
NetworkMessage[] UnhandledMessages { get; }
|
||||||
void HandleMessage(NetworkMessage message);
|
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate);
|
||||||
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate);
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IMethodInvoker
|
||||||
|
{
|
||||||
|
bool IsVoid { get; }
|
||||||
|
Type[] ParameterTypes { get; }
|
||||||
|
Type? ReturnType { get; }
|
||||||
|
Type SuitableType { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
using System.Reflection;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
namespace mROA.Abstract;
|
|
||||||
|
|
||||||
public interface IMethodRepository : IInjectableModule
|
|
||||||
{
|
{
|
||||||
MethodInfo GetMethod(int id);
|
public interface IMethodRepository : IInjectableModule
|
||||||
int RegisterMethod(MethodInfo method);
|
{
|
||||||
|
IMethodInvoker GetMethod(int id);
|
||||||
IEnumerable<MethodInfo> GetMethods();
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IOwnershipRepository
|
|
||||||
{
|
{
|
||||||
int GetOwnershipId();
|
public interface IOwnershipRepository
|
||||||
int GetHostOwnershipId();
|
{
|
||||||
|
int GetOwnershipId();
|
||||||
|
int GetHostOwnershipId();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IRemoteObjectFactory : IInjectableModule
|
||||||
|
{
|
||||||
|
T Produce<T>(ComplexObjectIdentifier id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface IRepresentationModuleProducer : IInjectableModule
|
|
||||||
{
|
{
|
||||||
IRepresentationModule Produce(int id);
|
public interface IRepresentationModuleProducer : IInjectableModule
|
||||||
|
{
|
||||||
|
IRepresentationModule Produce(int id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
namespace mROA.Abstract;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
public interface IRequestExtractor : IInjectableModule
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
Task StartExtraction();
|
public interface IRequestExtractor : IInjectableModule
|
||||||
|
{
|
||||||
|
Task StartExtraction();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,33 +1,25 @@
|
|||||||
using System.Windows.Input;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Implementation;
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.CommandExecution;
|
|
||||||
|
|
||||||
namespace mROA.Abstract;
|
namespace mROA.Abstract
|
||||||
|
|
||||||
public interface ISerialisationModule : IInjectableModule
|
|
||||||
{
|
{
|
||||||
void HandleIncomingRequest(int clientId, byte[] message);
|
public interface IRepresentationModule : IInjectableModule
|
||||||
void PostResponse(NetworkMessage message, int clientId);
|
|
||||||
void SendWelcomeMessage(int clientId);
|
|
||||||
public interface IFrontendSerialisationModule : IInjectableModule
|
|
||||||
{
|
{
|
||||||
int ClientId { get; }
|
int Id { get; }
|
||||||
Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution;
|
|
||||||
Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId);
|
|
||||||
void PostCallRequest(ICallRequest callRequest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IRepresentationModule : IInjectableModule
|
Task<T> GetMessageAsync<T>(Guid? requestId = null, MessageType? messageType = null,
|
||||||
{
|
CancellationToken token = default);
|
||||||
int Id { get; }
|
|
||||||
Task<T> GetMessageAsync<T>(Guid? requestId = null, EMessageType? messageType = null, CancellationToken token = default);
|
T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null);
|
||||||
T GetMessage<T>(Guid? requestId = null, EMessageType? messageType = null);
|
|
||||||
T GetMessage<T>(Predicate<NetworkMessage> filter);
|
Task<byte[]> GetRawMessage(Guid? requestId = null, MessageType? messageType = null,
|
||||||
Task<byte[]> GetRawMessage(Predicate<NetworkMessage> filter, CancellationToken token = default);
|
CancellationToken token = default);
|
||||||
|
|
||||||
Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
|
Task PostCallMessageAsync<T>(Guid id, MessageType messageType, T payload) where T : notnull;
|
||||||
Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType);
|
Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType);
|
||||||
void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
|
void PostCallMessage<T>(Guid id, MessageType messageType, T payload) where T : notnull;
|
||||||
void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType);
|
void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
namespace mROA.Abstract;
|
using System;
|
||||||
|
|
||||||
public interface ISerializationToolkit : IInjectableModule
|
namespace mROA.Abstract
|
||||||
{
|
{
|
||||||
byte[] Serialize<T>(T objectToSerialize);
|
public interface ISerializationToolkit : IInjectableModule
|
||||||
byte[] Serialize(object objectToSerialize, Type type);
|
{
|
||||||
T? Deserialize<T>(byte[] rawData);
|
byte[] Serialize<T>(T objectToSerialize);
|
||||||
object? Deserialize(byte[] rawData, Type type);
|
byte[] Serialize(object objectToSerialize, Type type);
|
||||||
T? Deserialize<T>(Span<byte> rawData);
|
T? Deserialize<T>(byte[] rawData);
|
||||||
object? Deserialize(Span<byte> rawData, Type type);
|
object? Deserialize(byte[] rawData, Type type);
|
||||||
T Cast<T>(object nonCasted);
|
T? Deserialize<T>(Span<byte> rawData);
|
||||||
object Cast(object nonCasted, Type type);
|
object? Deserialize(Span<byte> rawData, Type type);
|
||||||
|
T? Cast<T>(object? nonCasted);
|
||||||
|
object? Cast(object? nonCasted, Type type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
#pragma warning disable CS8618, CS9264
|
||||||
|
public interface IShared
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public interface IStorage<T> where T : class
|
||||||
|
{
|
||||||
|
T? GetValue(int index);
|
||||||
|
int GetIndex(T value);
|
||||||
|
int Place(T value);
|
||||||
|
void Free(int index);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.Attributes
|
||||||
|
{
|
||||||
|
public class SerializationIgnoreAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
namespace mROA.Implementation.Attributes;
|
using System;
|
||||||
|
|
||||||
public class SharedObjectInterfaceAttribute : Attribute;
|
namespace mROA.Implementation.Attributes
|
||||||
|
{
|
||||||
|
public class SharedObjectInterfaceAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
namespace mROA.Implementation.Attributes;
|
using System;
|
||||||
|
|
||||||
public class SharedObjectSingletonAttribute : Attribute;
|
namespace mROA.Implementation.Attributes
|
||||||
|
{
|
||||||
|
public class SharedObjectSingletonAttribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,18 @@
|
|||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class BackendIdentityGenerator : IIdentityGenerator
|
|
||||||
{
|
{
|
||||||
private int _currentId;
|
public class BackendIdentityGenerator : IIdentityGenerator
|
||||||
|
|
||||||
public int GetNextIdentity()
|
|
||||||
{
|
|
||||||
return ++_currentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
{
|
||||||
|
private int _currentId;
|
||||||
|
|
||||||
|
public int GetNextIdentity()
|
||||||
|
{
|
||||||
|
return ++_currentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,37 +1,35 @@
|
|||||||
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.Bootstrap;
|
using mROA.Implementation.Bootstrap;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public static class BasicConfigurationExtensions
|
|
||||||
{
|
{
|
||||||
public static void UseJsonSerialisation(this FullMixBuilder builder)
|
public static class BasicConfigurationExtensions
|
||||||
{
|
{
|
||||||
builder.Modules.Add(new JsonSerializationToolkit());
|
public static void UseNetworkGateway(this FullMixBuilder builder, IPEndPoint endPoint,
|
||||||
}
|
Type interactionModuleType, params IInjectableModule[] injectableModules)
|
||||||
|
{
|
||||||
|
builder.Modules.Add(new NetworkGatewayModule(endPoint, interactionModuleType, injectableModules));
|
||||||
|
}
|
||||||
|
|
||||||
public static void UseNetworkGateway(this FullMixBuilder builder, IPEndPoint endPoint, Type interactionModuleType, params IInjectableModule[] injectableModules)
|
public static void UseBasicExecution(this FullMixBuilder builder)
|
||||||
{
|
{
|
||||||
builder.Modules.Add(new NetworkGatewayModule(endPoint, interactionModuleType, injectableModules));
|
builder.Modules.Add(new BasicExecutionModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UseBasicExecution(this FullMixBuilder builder)
|
|
||||||
{
|
|
||||||
builder.Modules.Add(new BasicExecutionModule());
|
|
||||||
}
|
|
||||||
|
|
||||||
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 ContextRepository();
|
||||||
repo.FillSingletons(assemblies);
|
repo.FillSingletons(assemblies);
|
||||||
TransmissionConfig.RealContextRepository = repo;
|
TransmissionConfig.RealContextRepository = repo;
|
||||||
builder.Modules.Add(repo);
|
builder.Modules.Add(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository)
|
public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository)
|
||||||
{
|
{
|
||||||
builder.Modules.Add(methodRepository);
|
builder.Modules.Add(methodRepository);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,122 +1,263 @@
|
|||||||
using System.Reflection;
|
using System;
|
||||||
|
using System.Threading;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.CommandExecution;
|
using mROA.Implementation.CommandExecution;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class BasicExecutionModule : IExecuteModule
|
|
||||||
{
|
{
|
||||||
private IMethodRepository? _methodRepo;
|
public class BasicExecutionModule : IExecuteModule
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
{
|
||||||
if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo;
|
private ICancellationRepository? _cancellationRepo;
|
||||||
}
|
private IMethodRepository? _methodRepo;
|
||||||
|
private ISerializationToolkit? _serialization;
|
||||||
|
|
||||||
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository)
|
public void Inject<T>(T dependency)
|
||||||
{
|
|
||||||
if (_methodRepo is null)
|
|
||||||
throw new NullReferenceException("Method repository was not defined");
|
|
||||||
|
|
||||||
if (contextRepository is null)
|
|
||||||
throw new NullReferenceException("Context repository was not defined");
|
|
||||||
|
|
||||||
var currentCommand = _methodRepo.GetMethod(command.CommandId);
|
|
||||||
if (currentCommand == null)
|
|
||||||
throw new Exception($"Command {command.CommandId} not found");
|
|
||||||
|
|
||||||
var context = command.ObjectId != -1
|
|
||||||
? contextRepository.GetObject(command.ObjectId)
|
|
||||||
: contextRepository.GetSingleObject(currentCommand.DeclaringType!);
|
|
||||||
|
|
||||||
var parameter = command.Parameter;
|
|
||||||
|
|
||||||
if (currentCommand.ReturnType.BaseType == typeof(Task) &&
|
|
||||||
currentCommand.ReturnType.GenericTypeArguments.Length == 1)
|
|
||||||
return TypedExecuteAsync(currentCommand, context, parameter, command);
|
|
||||||
|
|
||||||
if (currentCommand.ReturnType == typeof(Task))
|
|
||||||
return ExecuteAsync(currentCommand, context, parameter, command);
|
|
||||||
|
|
||||||
return Execute(currentCommand, context, parameter, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter,
|
|
||||||
ICallRequest command)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var finalResult = currentCommand.Invoke(context, parameter is null ? [] : [parameter]);
|
switch (dependency)
|
||||||
return new TypedFinalCommandExecution
|
|
||||||
{
|
{
|
||||||
CommandId = command.CommandId, Result = finalResult,
|
case IMethodRepository methodRepo:
|
||||||
Id = command.Id,
|
_methodRepo = methodRepo;
|
||||||
Type = currentCommand.ReturnType
|
break;
|
||||||
|
case ICancellationRepository cancellationRepo:
|
||||||
|
_cancellationRepo = cancellationRepo;
|
||||||
|
break;
|
||||||
|
case ISerializationToolkit serializationToolkit:
|
||||||
|
_serialization = serializationToolkit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
||||||
|
IRepresentationModule representationModule)
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine(command.GetType().Name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ThrowIfNotInjected(contextRepository);
|
||||||
|
if (command is CancelRequest)
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine("Final cancelling request");
|
||||||
|
#endif
|
||||||
|
return CancelExecution(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoker = _methodRepo!.GetMethod(command.CommandId);
|
||||||
|
if (invoker == null)
|
||||||
|
throw new Exception($"Command {command.CommandId} not found");
|
||||||
|
|
||||||
|
var context = GetContext(command, contextRepository, invoker);
|
||||||
|
|
||||||
|
if (context == null)
|
||||||
|
throw new NullReferenceException("Instance can't be null");
|
||||||
|
|
||||||
|
|
||||||
|
object?[]? castedParams = null;
|
||||||
|
|
||||||
|
if (invoker.ParameterTypes.Length != 0)
|
||||||
|
castedParams = CastedParams(command, invoker);
|
||||||
|
|
||||||
|
|
||||||
|
var execContext = new RequestContext(command.Id, representationModule.Id);
|
||||||
|
|
||||||
|
switch (invoker)
|
||||||
|
{
|
||||||
|
case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker:
|
||||||
|
return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command,
|
||||||
|
_cancellationRepo!,
|
||||||
|
representationModule, execContext);
|
||||||
|
case AsyncMethodInvoker asyncMethodInvoker:
|
||||||
|
return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo!,
|
||||||
|
representationModule, execContext);
|
||||||
|
default:
|
||||||
|
var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext);
|
||||||
|
if (command.CommandId == -1)
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine("Disposing object");
|
||||||
|
#endif
|
||||||
|
contextRepository.ClearObject(command.ObjectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ExceptionCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object GetContext(ICallRequest command, IContextRepository contextRepository, IMethodInvoker invoker)
|
||||||
|
{
|
||||||
|
var context = command.ObjectId.ContextId != -1
|
||||||
|
? contextRepository.GetObject<object>(command.ObjectId)
|
||||||
|
: contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId);
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object?[] CastedParams(ICallRequest command, IMethodInvoker invoker)
|
||||||
|
{
|
||||||
|
object?[] castedParams = new object[invoker.ParameterTypes.Length];
|
||||||
|
for (var i = 0; i < castedParams.Length; i++)
|
||||||
|
{
|
||||||
|
castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return castedParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThrowIfNotInjected(IContextRepository contextRepository)
|
||||||
|
{
|
||||||
|
if (_cancellationRepo is null)
|
||||||
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
|
|
||||||
|
if (_methodRepo is null)
|
||||||
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
|
|
||||||
|
if (contextRepository is null)
|
||||||
|
throw new NullReferenceException("Context repository was not defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
private FinalCommandExecution CancelExecution(ICallRequest command)
|
||||||
|
{
|
||||||
|
var cts = _cancellationRepo!.GetCancellation(command.Id);
|
||||||
|
if (cts == null)
|
||||||
|
throw new NullReferenceException("Can't find cancellation for this request");
|
||||||
|
cts.Cancel();
|
||||||
|
_cancellationRepo.FreeCancelation(command.Id);
|
||||||
|
|
||||||
|
return new FinalCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
private static ICommandExecution Execute(MethodInvoker invoker, object instance, object?[] parameter,
|
||||||
|
ICallRequest command, RequestContext executionContext)
|
||||||
{
|
{
|
||||||
return new ExceptionCommandExecution
|
try
|
||||||
{
|
{
|
||||||
Id = command.Id, CommandId = command.CommandId,
|
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||||
Exception = e.ToString()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
if (invoker.IsVoid)
|
||||||
ICallRequest command)
|
{
|
||||||
{
|
return new FinalCommandExecution
|
||||||
var tokenSource = new CancellationTokenSource();
|
{
|
||||||
var token = tokenSource.Token;
|
Id = command.Id
|
||||||
try
|
};
|
||||||
{
|
}
|
||||||
var result = (Task)currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token])!;
|
|
||||||
|
|
||||||
|
return new FinalCommandExecution<object>
|
||||||
result.Wait(token);
|
{
|
||||||
|
Result = finalResult,
|
||||||
|
Id = command.Id
|
||||||
return new FinalCommandExecution { CommandId = command.CommandId, Id = command.Id };
|
};
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
|
||||||
return new ExceptionCommandExecution
|
|
||||||
{
|
{
|
||||||
Id = command.Id, CommandId = command.CommandId,
|
return new ExceptionCommandExecution
|
||||||
Exception = e.ToString()
|
{
|
||||||
};
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
ICallRequest command)
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
{
|
IRepresentationModule representationModule, RequestContext executionContext)
|
||||||
var tokenSource = new CancellationTokenSource();
|
|
||||||
var token = tokenSource.Token;
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
var result =
|
var tokenSource = new CancellationTokenSource();
|
||||||
(Task)currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token])!;
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
|
var token = tokenSource.Token;
|
||||||
result.Wait(token);
|
#if TRACE
|
||||||
|
token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}"));
|
||||||
var finalResult = result.GetType().GetProperty("Result")?.GetValue(result);
|
#endif
|
||||||
return new TypedFinalCommandExecution
|
try
|
||||||
{
|
{
|
||||||
Id = command.Id,
|
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
|
||||||
Result = finalResult,
|
{
|
||||||
CommandId = command.CommandId,
|
if (token.IsCancellationRequested)
|
||||||
Type = finalResult?.GetType()
|
return;
|
||||||
};
|
|
||||||
|
var payload = new FinalCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id
|
||||||
|
};
|
||||||
|
_cancellationRepo?.FreeCancelation(command.Id);
|
||||||
|
|
||||||
|
var multiClientOwnershipRepository =
|
||||||
|
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
||||||
|
|
||||||
|
multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id);
|
||||||
|
representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload);
|
||||||
|
multiClientOwnershipRepository?.FreeOwnership();
|
||||||
|
});
|
||||||
|
|
||||||
|
return new AsyncCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ExceptionCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
|
IRepresentationModule representationModule, RequestContext executionContext)
|
||||||
{
|
{
|
||||||
return new ExceptionCommandExecution
|
var tokenSource = new CancellationTokenSource();
|
||||||
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
|
|
||||||
|
var token = tokenSource.Token;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Id = command.Id, CommandId = command.CommandId,
|
invoker.Invoke(instance, parameters, new object[] { executionContext, token },
|
||||||
Exception = e.ToString()
|
finalResult =>
|
||||||
};
|
{
|
||||||
|
var payload = new FinalCommandExecution<object>
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Result = finalResult
|
||||||
|
};
|
||||||
|
_cancellationRepo!.FreeCancelation(command.Id);
|
||||||
|
|
||||||
|
var multiClientOwnershipRepository =
|
||||||
|
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
||||||
|
multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id);
|
||||||
|
representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution,
|
||||||
|
payload);
|
||||||
|
multiClientOwnershipRepository?.FreeOwnership();
|
||||||
|
});
|
||||||
|
|
||||||
|
return new AsyncCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return new ExceptionCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,35 +1,38 @@
|
|||||||
using mROA.Abstract;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class ConnectionHub : IConnectionHub
|
|
||||||
{
|
{
|
||||||
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
|
public class ConnectionHub : IConnectionHub
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
|
||||||
|
|
||||||
public void RegisterInteraction(INextGenerationInteractionModule interaction)
|
|
||||||
{
|
{
|
||||||
if (_serializationToolkit is null)
|
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
|
||||||
throw new NullReferenceException("Serialization toolkit is null");
|
private ISerializationToolkit? _serializationToolkit;
|
||||||
|
|
||||||
_connections.Add(interaction.ConnectionId, interaction);
|
|
||||||
var module = new RepresentationModule();
|
|
||||||
module.Inject(_serializationToolkit);
|
|
||||||
module.Inject(interaction);
|
|
||||||
OnConnected?.Invoke(module);
|
|
||||||
}
|
|
||||||
|
|
||||||
public INextGenerationInteractionModule GetInteracion(int id)
|
public void RegisterInteraction(INextGenerationInteractionModule interaction)
|
||||||
{
|
{
|
||||||
return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
|
if (_serializationToolkit is null)
|
||||||
}
|
throw new NullReferenceException("Serialization toolkit is null");
|
||||||
|
|
||||||
public event ConnectionHandler? OnConnected;
|
_connections.Add(interaction.ConnectionId, interaction);
|
||||||
public event DisconnectionHandler? OnDisconnected;
|
var module = new RepresentationModule();
|
||||||
public void Inject<T>(T dependency)
|
module.Inject(_serializationToolkit);
|
||||||
{
|
module.Inject(interaction);
|
||||||
if (dependency is ISerializationToolkit serializationToolkit)
|
OnConnected?.Invoke(module);
|
||||||
_serializationToolkit = serializationToolkit;
|
}
|
||||||
|
|
||||||
|
public INextGenerationInteractionModule GetInteracion(int id)
|
||||||
|
{
|
||||||
|
return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public event ConnectionHandler? OnConnected;
|
||||||
|
public event DisconnectionHandler? OnDisconnected;
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
if (dependency is ISerializationToolkit serializationToolkit)
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,97 +1,95 @@
|
|||||||
using System.Collections.Frozen;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
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
|
|
||||||
{
|
{
|
||||||
private FrozenDictionary<int, object?>? _singletons;
|
public class ContextRepository : IContextRepository
|
||||||
private object?[] _storage = new object[StartupSize];
|
|
||||||
|
|
||||||
private Task<int> _lastIndexFinder = Task.FromResult(0);
|
|
||||||
|
|
||||||
private const int StartupSize = 1024;
|
|
||||||
private const int GrowSize = 128;
|
|
||||||
|
|
||||||
|
|
||||||
public void FillSingletons(params Assembly[] assembly)
|
|
||||||
{
|
{
|
||||||
var types = assembly.SelectMany(x => x.GetTypes()).Where(type =>
|
private const int StartupSize = 1024;
|
||||||
type is { IsClass: true, IsAbstract: false, IsGenericType: false } &&
|
private const int GrowSize = 128;
|
||||||
type.GetCustomAttributes(typeof(SharedObjectSingletonAttribute), true).Length > 0);
|
public static object[] EventBinders = { };
|
||||||
_singletons =
|
|
||||||
types.ToFrozenDictionary(
|
|
||||||
t => t.GetInterfaces().FirstOrDefault(i =>
|
|
||||||
i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(),
|
|
||||||
Activator.CreateInstance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ResisterObject(object o)
|
private static int LastDebugId = -1;
|
||||||
{
|
private int _debugId = -1;
|
||||||
if (!_lastIndexFinder.IsCompleted)
|
|
||||||
_lastIndexFinder.Wait();
|
|
||||||
|
|
||||||
_storage[_lastIndexFinder.Result] = o;
|
private Task<int> _lastIndexFinder = Task.FromResult(0);
|
||||||
|
|
||||||
var last = _lastIndexFinder.Result;
|
private IRepresentationModuleProducer? _representationModuleProducer;
|
||||||
_lastIndexFinder = Task.Run(FindLastIndex);
|
|
||||||
|
|
||||||
return last;
|
// [CanBeNull]
|
||||||
}
|
private Dictionary<int, object?> _singletons;
|
||||||
|
private IStorage<object> _storage;
|
||||||
|
|
||||||
public void ClearObject(int id)
|
|
||||||
{
|
|
||||||
_storage[id] = null;
|
|
||||||
_lastIndexFinder = Task.FromResult(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetObject(int id)
|
public ContextRepository()
|
||||||
{
|
|
||||||
return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetObject<T>(int id)
|
|
||||||
{
|
|
||||||
return id == -1 || _storage.Length <= id
|
|
||||||
? throw new NullReferenceException("Cannot find that object. It is null")
|
|
||||||
: (T)_storage[id]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetSingleObject<T>()
|
|
||||||
{
|
|
||||||
var result = GetSingleObject(typeof(T));
|
|
||||||
return (T)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetSingleObject(Type type)
|
|
||||||
{
|
|
||||||
return _singletons!.GetValueOrDefault(type.GetHashCode()) ??
|
|
||||||
throw new ArgumentException("Unregistered singleton type");
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetObjectIndex(object o)
|
|
||||||
{
|
|
||||||
var index = Array.IndexOf(_storage, o);
|
|
||||||
return index == -1 ? ResisterObject(o) : index;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int FindLastIndex()
|
|
||||||
{
|
|
||||||
for (var i = 0; i < _storage.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (_storage[i] is null)
|
_storage = new ExtensibleStorage<object>();
|
||||||
return i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextStorage = new object[_storage.Length + GrowSize];
|
public int HostId { get; set; }
|
||||||
Array.Copy(_storage, nextStorage, _storage.Length);
|
|
||||||
_storage = nextStorage;
|
|
||||||
return _storage.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public int ResisterObject<T>(object o, IEndPointContext context)
|
||||||
{
|
{
|
||||||
|
var last = _storage.Place(o);
|
||||||
|
|
||||||
|
EventBinders.OfType<IEventBinder<T>>().FirstOrDefault()
|
||||||
|
?.BindEvents((T)o, context, _representationModuleProducer!, last);
|
||||||
|
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearObject(ComplexObjectIdentifier id)
|
||||||
|
{
|
||||||
|
_storage.Free(id.ContextId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetObject<T>(ComplexObjectIdentifier id)
|
||||||
|
{
|
||||||
|
var value = _storage.GetValue(id.ContextId);
|
||||||
|
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new NullReferenceException("Cannot find that object. It is null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object GetSingleObject(Type type, int ownerId)
|
||||||
|
{
|
||||||
|
return _singletons.GetValueOrDefault(type.GetHashCode()) ??
|
||||||
|
throw new ArgumentException("Unregistered singleton type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetObjectIndex<T>(object o, IEndPointContext context)
|
||||||
|
{
|
||||||
|
var index = _storage.GetIndex(o);
|
||||||
|
return index == -1 ? ResisterObject<T>(o, context) : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
if (dependency is IRepresentationModuleProducer moduleProducer)
|
||||||
|
{
|
||||||
|
_representationModuleProducer = moduleProducer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FillSingletons(params Assembly[] assembly)
|
||||||
|
{
|
||||||
|
var types = assembly.SelectMany(x => x.GetTypes()).Where(type =>
|
||||||
|
type is { IsClass: true, IsAbstract: false, IsGenericType: false } &&
|
||||||
|
type.GetCustomAttributes(typeof(SharedObjectSingletonAttribute), true).Length > 0);
|
||||||
|
_singletons =
|
||||||
|
types.ToDictionary(
|
||||||
|
t => t.GetInterfaces().FirstOrDefault(i =>
|
||||||
|
i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(),
|
||||||
|
Activator.CreateInstance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,50 +1,70 @@
|
|||||||
|
using System;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class HubRequestExtractor(Type extractoType) : IInjectableModule
|
|
||||||
{
|
{
|
||||||
private IConnectionHub? _hub;
|
public class HubRequestExtractor : IInjectableModule
|
||||||
|
|
||||||
private IContextRepository? _contextRepository;
|
|
||||||
private IMethodRepository? _methodRepository;
|
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
|
||||||
private IExecuteModule? _executeModule;
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
{
|
||||||
switch (dependency)
|
private IConnectionHub? _hub;
|
||||||
|
|
||||||
|
private IContextRepository? _contextRepository;
|
||||||
|
private IContextRepository? _remoteContextRepository;
|
||||||
|
private IMethodRepository? _methodRepository;
|
||||||
|
private ISerializationToolkit? _serializationToolkit;
|
||||||
|
private IExecuteModule? _executeModule;
|
||||||
|
private readonly Type _extractorType;
|
||||||
|
|
||||||
|
public HubRequestExtractor(Type extractorType)
|
||||||
{
|
{
|
||||||
case IConnectionHub connectionHub:
|
_extractorType = extractorType;
|
||||||
_hub = connectionHub;
|
}
|
||||||
_hub.OnConnected += HubOnOnConnected;
|
|
||||||
break;
|
public void Inject<T>(T dependency)
|
||||||
case IContextRepository contextRepository:
|
{
|
||||||
_contextRepository = contextRepository;
|
switch (dependency)
|
||||||
break;
|
{
|
||||||
case IMethodRepository methodRepository:
|
case IConnectionHub connectionHub:
|
||||||
_methodRepository = methodRepository;
|
_hub = connectionHub;
|
||||||
break;
|
_hub.OnConnected += HubOnOnConnected;
|
||||||
case ISerializationToolkit serializationToolkit:
|
break;
|
||||||
_serializationToolkit = serializationToolkit;
|
case MultiClientContextRepository:
|
||||||
break;
|
case ContextRepository:
|
||||||
case IExecuteModule executeModule:
|
_contextRepository = dependency as IContextRepository;
|
||||||
_executeModule = executeModule;
|
break;
|
||||||
break;
|
case RemoteContextRepository remoteContextRepository:
|
||||||
|
_remoteContextRepository = remoteContextRepository;
|
||||||
|
break;
|
||||||
|
case IMethodRepository methodRepository:
|
||||||
|
_methodRepository = methodRepository;
|
||||||
|
break;
|
||||||
|
case ISerializationToolkit serializationToolkit:
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
|
break;
|
||||||
|
case IExecuteModule executeModule:
|
||||||
|
_executeModule = executeModule;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HubOnOnConnected(IRepresentationModule interaction)
|
||||||
|
{
|
||||||
|
var extractor = CreateExtractor(interaction);
|
||||||
|
_ = extractor.StartExtraction();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IRequestExtractor CreateExtractor(IRepresentationModule interaction)
|
||||||
|
{
|
||||||
|
var extractor = (IRequestExtractor)Activator.CreateInstance(_extractorType)!;
|
||||||
|
extractor.Inject(interaction);
|
||||||
|
if (_contextRepository is IContextRepositoryHub contextHub)
|
||||||
|
extractor.Inject(contextHub.GetRepository(interaction.Id));
|
||||||
|
else
|
||||||
|
extractor.Inject(interaction);
|
||||||
|
extractor.Inject(_methodRepository);
|
||||||
|
extractor.Inject(_serializationToolkit);
|
||||||
|
extractor.Inject(_executeModule);
|
||||||
|
extractor.Inject(_remoteContextRepository);
|
||||||
|
return extractor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HubOnOnConnected(IRepresentationModule interaction)
|
|
||||||
{
|
|
||||||
var extractor = (IRequestExtractor)Activator.CreateInstance(extractoType)!;
|
|
||||||
extractor.Inject(interaction);
|
|
||||||
if (_contextRepository is IContextRepositoryHub contextHub)
|
|
||||||
extractor.Inject(contextHub.GetRepository(interaction.Id));
|
|
||||||
else
|
|
||||||
extractor.Inject(interaction);
|
|
||||||
extractor.Inject(_methodRepository);
|
|
||||||
extractor.Inject(_serializationToolkit);
|
|
||||||
extractor.Inject(_executeModule);
|
|
||||||
_ = extractor.StartExtraction();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// using System.Text;
|
|
||||||
// using System.Text.Json;
|
|
||||||
// using mROA.Abstract;
|
|
||||||
//
|
|
||||||
// namespace mROA.Implementation.Backend;
|
|
||||||
//
|
|
||||||
// public class JsonSerialisationModule : ISerialisationModule
|
|
||||||
// {
|
|
||||||
// private IInteractionModule? _dataSource;
|
|
||||||
// private IExecuteModule? _executeModule;
|
|
||||||
// private IMethodRepository? _methodRepository;
|
|
||||||
// private IContextRepository? _contextRepo;
|
|
||||||
//
|
|
||||||
// public void HandleIncomingRequest(int clientId, byte[] message)
|
|
||||||
// {
|
|
||||||
// MultiClientOwnershipRepository? ownership = null;
|
|
||||||
// if (TransmissionConfig.OwnershipRepository is MultiClientOwnershipRepository)
|
|
||||||
// {
|
|
||||||
// ownership = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
|
||||||
// ownership.RegisterOwnership(clientId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// NetworkMessage input = JsonSerializer.Deserialize<NetworkMessage>(message)!;
|
|
||||||
// Console.WriteLine(Encoding.Default.GetString(input.Data));
|
|
||||||
// if (input.SchemaId == MessageType.CallRequest)
|
|
||||||
// {
|
|
||||||
// var command = JsonSerializer.Deserialize<DefaultCallRequest>(input.Data)!;
|
|
||||||
// if (command.Parameter is not null)
|
|
||||||
// {
|
|
||||||
// var parameter = _methodRepository!.GetMethod(command.CommandId).GetParameters().First().ParameterType;
|
|
||||||
// var jsElement = (JsonElement)command.Parameter;
|
|
||||||
// command.Parameter = jsElement.Deserialize(parameter);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var response = _executeModule!.Execute(command, _contextRepo);
|
|
||||||
// response.ClientId = clientId;
|
|
||||||
// var resultType = response is FinalCommandExecution
|
|
||||||
// ? MessageType.FinishedCommandExecution
|
|
||||||
// : MessageType.ErrorCommandExecution;
|
|
||||||
// PostResponse(
|
|
||||||
// new NetworkMessage
|
|
||||||
// {
|
|
||||||
// SchemaId = resultType,
|
|
||||||
// Id = command.CallRequestId,
|
|
||||||
// Data = JsonSerializer.SerializeToUtf8Bytes(response, response.GetType())
|
|
||||||
// }, clientId);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ownership?.FreeOwnership();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void PostResponse(NetworkMessage message, int clientId)
|
|
||||||
// {
|
|
||||||
// _dataSource!.SendTo(clientId, JsonSerializer.SerializeToUtf8Bytes(message));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void SendWelcomeMessage(int clientId)
|
|
||||||
// {
|
|
||||||
// _dataSource!.SendTo(clientId, JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage { Data = JsonSerializer.SerializeToUtf8Bytes(new IdAssingnment { Id = clientId }), SchemaId = MessageType.IdAssigning}));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void Inject<T>(T dependency)
|
|
||||||
// {
|
|
||||||
// switch (dependency)
|
|
||||||
// {
|
|
||||||
// case IInteractionModule interactionModule:
|
|
||||||
// _dataSource = interactionModule;
|
|
||||||
// break;
|
|
||||||
// case IExecuteModule executeModule:
|
|
||||||
// _executeModule = executeModule;
|
|
||||||
// break;
|
|
||||||
// case IMethodRepository methodRepository:
|
|
||||||
// _methodRepository = methodRepository;
|
|
||||||
// break;
|
|
||||||
// case IContextRepository contextRepository:
|
|
||||||
// _contextRepo = contextRepository;
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,62 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class MultiClientContextRepository(Func<int, IContextRepository> produceRepository) : IContextRepository, IContextRepositoryHub
|
|
||||||
{
|
{
|
||||||
private Dictionary<int, IContextRepository> _repositories = new();
|
public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub
|
||||||
|
|
||||||
private IContextRepository GetRepositoryByClientId(int clientId)
|
|
||||||
{
|
{
|
||||||
if (_repositories.TryGetValue(clientId, out var repository))
|
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;
|
return repository;
|
||||||
|
}
|
||||||
var created = produceRepository(clientId);
|
|
||||||
_repositories.Add(clientId, created);
|
|
||||||
return created;
|
|
||||||
}
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ResisterObject(object o)
|
private IContextRepository GetRepositoryByClientId(int clientId)
|
||||||
{
|
{
|
||||||
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o);
|
if (_repositories.TryGetValue(clientId, out var repository))
|
||||||
}
|
return repository;
|
||||||
|
|
||||||
public void ClearObject(int id)
|
var created = _produceRepository(clientId);
|
||||||
{
|
_repositories.Add(clientId, created);
|
||||||
GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id);
|
return created;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object GetObject(int id)
|
|
||||||
{
|
|
||||||
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T? GetObject<T>(int id)
|
|
||||||
{
|
|
||||||
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject<T>(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T GetSingleObject<T>()
|
|
||||||
{
|
|
||||||
var result = GetSingleObject(typeof(T));
|
|
||||||
return (T)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object GetSingleObject(Type type)
|
|
||||||
{
|
|
||||||
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetSingleObject(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetObjectIndex(object o)
|
|
||||||
{
|
|
||||||
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObjectIndex(o);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IContextRepository GetRepository(int clientId)
|
|
||||||
{
|
|
||||||
return GetRepositoryByClientId(clientId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,31 @@
|
|||||||
using mROA.Abstract;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class MultiClientOwnershipRepository : IOwnershipRepository
|
|
||||||
{
|
{
|
||||||
private Dictionary<int, int> _ownerships = new();
|
public class MultiClientOwnershipRepository : IOwnershipRepository
|
||||||
|
|
||||||
public int GetOwnershipId()
|
|
||||||
{
|
{
|
||||||
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
|
private Dictionary<int, int> _ownerships = new();
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHostOwnershipId()
|
public int GetOwnershipId()
|
||||||
{
|
{
|
||||||
return 0;
|
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterOwnership(int ownershipId)
|
public int GetHostOwnershipId()
|
||||||
{
|
{
|
||||||
_ownerships.TryAdd(Environment.CurrentManagedThreadId, ownershipId);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FreeOwnership()
|
public void RegisterOwnership(int ownershipId)
|
||||||
{
|
{
|
||||||
_ownerships.Remove(Environment.CurrentManagedThreadId);
|
_ownerships.TryAdd(Environment.CurrentManagedThreadId, ownershipId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FreeOwnership()
|
||||||
|
{
|
||||||
|
_ownerships.Remove(Environment.CurrentManagedThreadId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,89 +1,102 @@
|
|||||||
using System.Net;
|
using System;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Backend;
|
namespace mROA.Implementation.Backend
|
||||||
|
|
||||||
public class NetworkGatewayModule : IGatewayModule
|
|
||||||
{
|
{
|
||||||
private readonly Type? _interactionModuleType;
|
public class NetworkGatewayModule : IGatewayModule
|
||||||
private readonly IInjectableModule[]? _injectableModules;
|
|
||||||
private readonly TcpListener _tcpListener;
|
|
||||||
private IConnectionHub? _hub;
|
|
||||||
private ISerializationToolkit? _serialization;
|
|
||||||
|
|
||||||
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules)
|
|
||||||
{
|
{
|
||||||
_tcpListener = new(endpoint);
|
private readonly IInjectableModule[]? _injectableModules;
|
||||||
_interactionModuleType = interactionModuleType;
|
private readonly Type? _interactionModuleType;
|
||||||
_injectableModules = injectableModules;
|
private readonly TcpListener _tcpListener;
|
||||||
}
|
private IConnectionHub? _hub;
|
||||||
|
private ISerializationToolkit? _serialization;
|
||||||
|
|
||||||
public void Run()
|
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType,
|
||||||
{
|
IInjectableModule[] injectableModules)
|
||||||
_tcpListener.Start();
|
|
||||||
Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
|
|
||||||
Console.WriteLine("Enter Backspace to stop");
|
|
||||||
|
|
||||||
Task.Run(HandleIncomingConnections);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
var key = Console.ReadKey();
|
_tcpListener = new(endpoint);
|
||||||
if (key.Key == ConsoleKey.Backspace)
|
_interactionModuleType = interactionModuleType;
|
||||||
break;
|
_injectableModules = injectableModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine("Stopping");
|
public void Run()
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
_tcpListener.Stop();
|
|
||||||
_tcpListener.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleIncomingConnections()
|
|
||||||
{
|
|
||||||
if (_hub is null)
|
|
||||||
throw new NullReferenceException("Hub module is null");
|
|
||||||
if (_tcpListener == null)
|
|
||||||
throw new NullReferenceException("TcpListener is null");
|
|
||||||
if (_injectableModules is null)
|
|
||||||
throw new NullReferenceException("InjectableModules is null");
|
|
||||||
if (_interactionModuleType is null)
|
|
||||||
throw new NullReferenceException("InteractionModuleType is null");
|
|
||||||
if (_serialization is null)
|
|
||||||
throw new NullReferenceException("Serialization is null");
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
var client = _tcpListener.AcceptTcpClient();
|
_tcpListener.Start();
|
||||||
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
|
||||||
var interaction = Activator.CreateInstance(_interactionModuleType) as INextGenerationInteractionModule;
|
Console.WriteLine("Enter Backspace to stop");
|
||||||
|
|
||||||
foreach (var injectableModule in _injectableModules)
|
Task.Run(HandleIncomingConnections);
|
||||||
interaction!.Inject(injectableModule);
|
|
||||||
|
|
||||||
interaction!.Inject(_serialization);
|
while (true)
|
||||||
|
|
||||||
interaction.BaseStream = client.GetStream();
|
|
||||||
interaction.StartInfiniteReceiving();
|
|
||||||
interaction.PostMessage(new NetworkMessage
|
|
||||||
{
|
{
|
||||||
Id = Guid.NewGuid(), MessageType = EMessageType.IdAssigning,
|
var key = Console.ReadKey();
|
||||||
Data = _serialization.Serialize(new IdAssingnment { Id = interaction.ConnectionId })
|
if (key.Key == ConsoleKey.Backspace)
|
||||||
});
|
break;
|
||||||
_hub.RegisterInteraction(interaction);
|
}
|
||||||
Console.WriteLine("Client registered");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
Console.WriteLine("Stopping");
|
||||||
{
|
}
|
||||||
if (dependency is IConnectionHub interactionModule)
|
|
||||||
_hub = interactionModule;
|
public void Dispose()
|
||||||
if (dependency is ISerializationToolkit serializationToolkit)
|
{
|
||||||
_serialization = serializationToolkit;
|
_tcpListener.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
switch (dependency)
|
||||||
|
{
|
||||||
|
case IConnectionHub interactionModule:
|
||||||
|
_hub = interactionModule;
|
||||||
|
break;
|
||||||
|
case ISerializationToolkit serializationToolkit:
|
||||||
|
_serialization = serializationToolkit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleIncomingConnections()
|
||||||
|
{
|
||||||
|
ThrowIfNotInjected();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var client = _tcpListener.AcceptTcpClient();
|
||||||
|
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
|
||||||
|
var interaction = Activator.CreateInstance(_interactionModuleType!) as INextGenerationInteractionModule;
|
||||||
|
|
||||||
|
foreach (var injectableModule in _injectableModules!)
|
||||||
|
interaction!.Inject(injectableModule);
|
||||||
|
|
||||||
|
interaction!.Inject(_serialization);
|
||||||
|
|
||||||
|
interaction.BaseStream = client.GetStream();
|
||||||
|
|
||||||
|
interaction.PostMessage(new NetworkMessage
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(), SchemaId = MessageType.IdAssigning,
|
||||||
|
Data = _serialization!.Serialize(new IdAssignment { Id = -interaction.ConnectionId })
|
||||||
|
});
|
||||||
|
_hub!.RegisterInteraction(interaction);
|
||||||
|
Console.WriteLine("Client registered");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThrowIfNotInjected()
|
||||||
|
{
|
||||||
|
if (_hub is null)
|
||||||
|
throw new NullReferenceException("Hub module is null");
|
||||||
|
if (_tcpListener == null)
|
||||||
|
throw new NullReferenceException("TcpListener is null");
|
||||||
|
if (_injectableModules is null)
|
||||||
|
throw new NullReferenceException("InjectableModules is null");
|
||||||
|
if (_interactionModuleType is null)
|
||||||
|
throw new NullReferenceException("InteractionModuleType is null");
|
||||||
|
if (_serialization is null)
|
||||||
|
throw new NullReferenceException("Serialization is null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
// using mROA.Abstract;
|
|
||||||
//
|
|
||||||
// namespace mROA.Implementation.Backend;
|
|
||||||
//
|
|
||||||
// public class StreamBasedInteractionModule : IInteractionModule
|
|
||||||
// {
|
|
||||||
// internal ISerialisationModule _serialisationModule;
|
|
||||||
// private readonly Dictionary<int, Stream> _streams = new();
|
|
||||||
// internal Action<int, byte[]>? _handler;
|
|
||||||
//
|
|
||||||
// public void RegisterSource(Stream stream)
|
|
||||||
// {
|
|
||||||
// var id = Random.Shared.Next();
|
|
||||||
// _streams.Add(id, stream);
|
|
||||||
// _ = ListenTo((id, stream), _handler!);
|
|
||||||
// _serialisationModule.SendWelcomeMessage(id);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public Stream GetSource(int clientId)
|
|
||||||
// {
|
|
||||||
// return _streams.GetValueOrDefault(clientId, Stream.Null);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void SendTo(int clientId, byte[] message)
|
|
||||||
// {
|
|
||||||
// if (!_streams.TryGetValue(clientId, out var stream))
|
|
||||||
// {
|
|
||||||
// throw new KeyNotFoundException($"Client {clientId} not found");
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// stream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
|
|
||||||
// stream.Write(message, 0, message.Length);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private async Task ListenTo((int id, Stream stream) client, Action<int, byte[]> action)
|
|
||||||
// {
|
|
||||||
// TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
|
|
||||||
// const int bufferSize = ushort.MaxValue;
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// byte[] buffer = new byte[bufferSize];
|
|
||||||
// while (client.stream.CanRead)
|
|
||||||
// {
|
|
||||||
// await client.stream.ReadExactlyAsync(buffer, 0, 2);
|
|
||||||
// var len = BitConverter.ToUInt16(buffer, 0);
|
|
||||||
// await client.stream.ReadExactlyAsync(buffer, 0, len);
|
|
||||||
// _ = Task.Run(() => action(client.id, buffer[..len]));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// catch (Exception)
|
|
||||||
// {
|
|
||||||
// Console.WriteLine($"Client handling finished:{client.id}");
|
|
||||||
// _streams.Remove(client.id);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void Inject<T>(T dependency)
|
|
||||||
// {
|
|
||||||
// if (dependency is ISerialisationModule serialisationModule)
|
|
||||||
// {
|
|
||||||
// _handler = serialisationModule.HandleIncomingRequest;
|
|
||||||
// _serialisationModule = serialisationModule;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Bootstrap;
|
namespace mROA.Implementation.Bootstrap
|
||||||
|
|
||||||
public class FullMixBuilder
|
|
||||||
{
|
{
|
||||||
public List<IInjectableModule> Modules { get; } = [];
|
public class FullMixBuilder
|
||||||
|
|
||||||
public void Build()
|
|
||||||
{
|
{
|
||||||
foreach (var module in Modules)
|
public List<IInjectableModule> Modules { get; } = new() { };
|
||||||
foreach (var injection in Modules)
|
|
||||||
module.Inject(injection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T? GetModule<T>()
|
public void Build()
|
||||||
{
|
{
|
||||||
return Modules.OfType<T>().FirstOrDefault();
|
foreach (var module in Modules)
|
||||||
|
foreach (var injection in Modules)
|
||||||
|
module.Inject(injection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetModule<T>()
|
||||||
|
{
|
||||||
|
return Modules.OfType<T>().FirstOrDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,42 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System;
|
||||||
|
|
||||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
|
||||||
|
|
||||||
namespace mROA.Implementation;
|
namespace mROA.Implementation
|
||||||
|
|
||||||
public interface ICallRequest
|
|
||||||
{
|
{
|
||||||
Guid Id { get; }
|
public interface ICallRequest
|
||||||
int CommandId { get; }
|
{
|
||||||
int ObjectId { get; }
|
Guid Id { get; }
|
||||||
object? Parameter { get; }
|
int CommandId { get; }
|
||||||
}
|
ComplexObjectIdentifier ObjectId { get; }
|
||||||
|
object?[]? Parameters { get; }
|
||||||
|
}
|
||||||
|
|
||||||
public class DefaultCallRequest : ICallRequest
|
public class DefaultCallRequest : ICallRequest
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; } = Guid.NewGuid();
|
public Guid Id { get; set; } = Guid.NewGuid();
|
||||||
public int CommandId { get; init; }
|
public int CommandId { get; set; }
|
||||||
public int ObjectId { get; init; } = -1;
|
public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null;
|
||||||
|
|
||||||
[JsonIgnore]
|
public object?[]? Parameters { get; set; }
|
||||||
public Type? ParameterType { get; init; }
|
|
||||||
public object? Parameter { get; set; }
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CancelRequest : ICallRequest
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public int CommandId { get; set; } = -2;
|
||||||
|
public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null;
|
||||||
|
public object?[]? Parameters { get; set; } = null;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
public class CancellationRepository : ICancellationRepository
|
||||||
|
{
|
||||||
|
private Dictionary<Guid, CancellationTokenSource> _cancellations = new();
|
||||||
|
|
||||||
|
public void RegisterCancellation(Guid id, CancellationTokenSource cts)
|
||||||
|
{
|
||||||
|
_cancellations.TryAdd(id, cts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CancellationTokenSource? GetCancellation(Guid id)
|
||||||
|
{
|
||||||
|
return _cancellations.GetValueOrDefault(id, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FreeCancelation(Guid id)
|
||||||
|
{
|
||||||
|
_cancellations.Remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.CommandExecution
|
||||||
|
{
|
||||||
|
public class AsyncCommandExecution : ICommandExecution
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
using mROA.Abstract;
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.Frontend;
|
using mROA.Implementation.Frontend;
|
||||||
|
|
||||||
namespace mROA.Implementation.CommandExecution;
|
namespace mROA.Implementation.CommandExecution
|
||||||
|
|
||||||
public class ExceptionCommandExecution : ICommandExecution
|
|
||||||
{
|
{
|
||||||
public Guid Id { get; init; }
|
public class ExceptionCommandExecution : ICommandExecution
|
||||||
public int ClientId { get; set; }
|
|
||||||
public int CommandId { get; init; }
|
|
||||||
public required string Exception { get; set; }
|
|
||||||
|
|
||||||
public RemoteException GetException()
|
|
||||||
{
|
{
|
||||||
return new RemoteException(Exception) { CallRequestId = Id };
|
public Guid Id { get; set; }
|
||||||
|
public string Exception { get; set; }
|
||||||
|
|
||||||
|
public RemoteException GetException()
|
||||||
|
{
|
||||||
|
return new RemoteException(Exception) { CallRequestId = Id };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,20 +1,17 @@
|
|||||||
using System.Text.Json.Serialization;
|
using System;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
// ReSharper disable UnusedAutoPropertyAccessor.Global
|
||||||
|
|
||||||
namespace mROA.Implementation.CommandExecution;
|
namespace mROA.Implementation.CommandExecution
|
||||||
|
|
||||||
public class FinalCommandExecution : ICommandExecution
|
|
||||||
{
|
{
|
||||||
public Guid Id { get; init; }
|
public class FinalCommandExecution : ICommandExecution
|
||||||
[JsonIgnore]
|
{
|
||||||
public int ClientId { get; set; }
|
public Guid Id { get; set; }
|
||||||
[JsonIgnore]
|
}
|
||||||
public int CommandId { get; init; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FinalCommandExecution<T> : FinalCommandExecution
|
public class FinalCommandExecution<T> : FinalCommandExecution
|
||||||
{
|
{
|
||||||
public T? Result { get; init; }
|
public T? Result { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace mROA.Implementation.CommandExecution;
|
|
||||||
|
|
||||||
public class TypedFinalCommandExecution : FinalCommandExecution<object>
|
|
||||||
{
|
|
||||||
[JsonIgnore]
|
|
||||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
|
||||||
public Type? Type { get; set; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
#pragma warning disable CS8618, CS9264
|
||||||
|
public struct ComplexObjectIdentifier : IEquatable<ComplexObjectIdentifier>
|
||||||
|
{
|
||||||
|
public int ContextId;
|
||||||
|
public int OwnerId;
|
||||||
|
|
||||||
|
public ComplexObjectIdentifier(int contextId, int ownerId)
|
||||||
|
{
|
||||||
|
ContextId = contextId;
|
||||||
|
OwnerId = ownerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ComplexObjectIdentifier Singleton(int ownerId) => new() { ContextId = -1, OwnerId = ownerId };
|
||||||
|
|
||||||
|
public static ComplexObjectIdentifier Null = new ComplexObjectIdentifier { ContextId = -2, OwnerId = 0 };
|
||||||
|
public static ComplexObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat };
|
||||||
|
|
||||||
|
public int ClientId => Math.Abs(OwnerId);
|
||||||
|
public bool IsSererStored => OwnerId > 0;
|
||||||
|
public bool IsClientStored => OwnerId < 0;
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{{ {nameof(ContextId)}: {ContextId}, {nameof(OwnerId)}: {OwnerId} }}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsStatic => ContextId == -1;
|
||||||
|
|
||||||
|
public ulong Flat
|
||||||
|
{
|
||||||
|
get => (ulong)OwnerId << 32 | (uint)ContextId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
OwnerId = (int)(value >> 32);
|
||||||
|
ContextId = (int)(value & 0xFFFFFFFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ComplexObjectIdentifier other)
|
||||||
|
{
|
||||||
|
return ContextId == other.ContextId && OwnerId == other.OwnerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ComplexObjectIdentifier other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(ContextId, OwnerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +1,43 @@
|
|||||||
using mROA.Abstract;
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation;
|
namespace mROA.Implementation
|
||||||
|
|
||||||
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
|
|
||||||
{
|
{
|
||||||
private Type _reprModuleType;
|
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
|
||||||
private IInjectableModule[] _creationModules;
|
|
||||||
private IConnectionHub? _hub;
|
|
||||||
|
|
||||||
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
|
|
||||||
{
|
{
|
||||||
_creationModules = creationModules;
|
private Type _reprModuleType;
|
||||||
_reprModuleType = reprModuleType;
|
private IInjectableModule[] _creationModules;
|
||||||
}
|
private IConnectionHub? _hub;
|
||||||
|
|
||||||
|
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
|
||||||
|
{
|
||||||
|
_creationModules = creationModules;
|
||||||
|
_reprModuleType = reprModuleType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
if (dependency is IConnectionHub interactionModule)
|
if (dependency is IConnectionHub interactionModule)
|
||||||
_hub = interactionModule;
|
_hub = interactionModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IRepresentationModule Produce(int id)
|
public IRepresentationModule Produce(int id)
|
||||||
{
|
{
|
||||||
if (_hub == null)
|
if (_hub == null)
|
||||||
throw new NullReferenceException("Interaction module is null");
|
throw new NullReferenceException("Interaction module is null");
|
||||||
|
|
||||||
var produced =
|
var produced =
|
||||||
Activator.CreateInstance(_reprModuleType) as IRepresentationModule ??
|
Activator.CreateInstance(_reprModuleType) as IRepresentationModule ??
|
||||||
throw new Exception("Bad serialization module type");
|
throw new Exception("Bad serialization module type");
|
||||||
|
|
||||||
foreach (var creationModule in _creationModules)
|
foreach (var creationModule in _creationModules)
|
||||||
produced.Inject(creationModule);
|
produced.Inject(creationModule);
|
||||||
|
|
||||||
produced.Inject(_hub.GetInteracion(id));
|
var interaction = _hub.GetInteracion(id);
|
||||||
|
produced.Inject(interaction);
|
||||||
return produced;
|
|
||||||
|
return produced;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
public class EndPointContext : IEndPointContext
|
||||||
|
{
|
||||||
|
public Func<int> OwnerFunc;
|
||||||
|
public IContextRepository RealRepository { get; set; }
|
||||||
|
public IContextRepository RemoteRepository { get; set; }
|
||||||
|
public int HostId { get; set; }
|
||||||
|
|
||||||
|
public int OwnerId
|
||||||
|
{
|
||||||
|
get => OwnerFunc();
|
||||||
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
set { OwnerFunc = () => value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Abstract
|
||||||
|
{
|
||||||
|
public class EventBinder<T> : IEventBinder<T>
|
||||||
|
{
|
||||||
|
public Action<T, IEndPointContext, IRepresentationModuleProducer, int> BindAction { get; set; }
|
||||||
|
|
||||||
|
public void BindEvents(T source, IEndPointContext context,
|
||||||
|
IRepresentationModuleProducer representationModuleProducer, int index)
|
||||||
|
{
|
||||||
|
BindAction(source, context, representationModuleProducer, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using mROA.Abstract;
|
||||||
|
|
||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
public class ExtensibleStorage<T> : IStorage<T> where T : class
|
||||||
|
{
|
||||||
|
private const int StartupSize = 1024;
|
||||||
|
private const int GrowSize = 128;
|
||||||
|
private T?[] _array = new T?[StartupSize];
|
||||||
|
private readonly LinkedList<int> _freePlaces = new(Enumerable.Range(0, StartupSize));
|
||||||
|
|
||||||
|
public T? GetValue(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= _array.Length)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _array[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetIndex(T value)
|
||||||
|
{
|
||||||
|
return Array.IndexOf(_array, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Place(T value)
|
||||||
|
{
|
||||||
|
if (_freePlaces.Count == 0)
|
||||||
|
{
|
||||||
|
Grow();
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = _freePlaces.First.Value;
|
||||||
|
|
||||||
|
_freePlaces.RemoveFirst();
|
||||||
|
_array[index] = value;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Grow()
|
||||||
|
{
|
||||||
|
foreach (var index in Enumerable.Range(_array.Length, GrowSize))
|
||||||
|
_freePlaces.AddLast(index);
|
||||||
|
|
||||||
|
T?[] nextStorage = new T[_array.Length + GrowSize];
|
||||||
|
Array.Copy(_array, nextStorage, _array.Length);
|
||||||
|
_array = nextStorage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(int index)
|
||||||
|
{
|
||||||
|
_freePlaces.AddFirst(index);
|
||||||
|
_array[index] = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
namespace mROA.Implementation.Frontend;
|
|
||||||
|
|
||||||
// public class JsonFrontendSerialisationModule
|
|
||||||
// : ISerialisationModule.IFrontendSerialisationModule
|
|
||||||
// {
|
|
||||||
// private IInteractionModule.IFrontendInteractionModule? _interactionModule;
|
|
||||||
// public int ClientId => _interactionModule!.ClientId;
|
|
||||||
//
|
|
||||||
// public async Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution
|
|
||||||
// {
|
|
||||||
// if (_interactionModule is null)
|
|
||||||
// throw new Exception("Interaction module not initialized");
|
|
||||||
//
|
|
||||||
// var receiveMessage = await _interactionModule.ReceiveMessage();
|
|
||||||
// var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
|
|
||||||
//
|
|
||||||
// while (message.Id != requestId)
|
|
||||||
// {
|
|
||||||
// receiveMessage = await _interactionModule.ReceiveMessage();
|
|
||||||
// message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// var parsed = JsonSerializer.Deserialize<T>(message.Data)!;
|
|
||||||
//
|
|
||||||
// if (message.SchemaId == MessageType.ErrorCommandExecution)
|
|
||||||
// {
|
|
||||||
// throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
|
|
||||||
// { CallRequestId = requestId };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return parsed;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public async Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId)
|
|
||||||
// {
|
|
||||||
// if (_interactionModule is null)
|
|
||||||
// throw new Exception("Interaction module not initialized");
|
|
||||||
//
|
|
||||||
// var receiveMessage = await _interactionModule.ReceiveMessage();
|
|
||||||
//
|
|
||||||
// var message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
|
|
||||||
// while (message.Id != requestId)
|
|
||||||
// {
|
|
||||||
// receiveMessage = await _interactionModule.ReceiveMessage();
|
|
||||||
//
|
|
||||||
// message = JsonSerializer.Deserialize<NetworkMessage>(receiveMessage)!;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (message.SchemaId == MessageType.ErrorCommandExecution)
|
|
||||||
// {
|
|
||||||
// throw new RemoteException(JsonSerializer.Deserialize<ExceptionCommandExecution>(message.Data)!.Exception)
|
|
||||||
// { CallRequestId = requestId };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return JsonSerializer.Deserialize<FinalCommandExecution<T>>(message.Data)!;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void PostCallRequest(ICallRequest callRequest)
|
|
||||||
// {
|
|
||||||
// if (_interactionModule is null)
|
|
||||||
// throw new Exception("Interaction module not initialized");
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// var post = JsonSerializer.SerializeToUtf8Bytes(callRequest, callRequest.GetType());
|
|
||||||
// _interactionModule.PostMessage(JsonSerializer.SerializeToUtf8Bytes(new NetworkMessage
|
|
||||||
// {
|
|
||||||
// Id = callRequest.CallRequestId,
|
|
||||||
// Data = post,
|
|
||||||
// SchemaId = MessageType.CallRequest
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void Inject<T>(T dependency)
|
|
||||||
// {
|
|
||||||
// if (dependency is IInteractionModule.IFrontendInteractionModule interactionModule)
|
|
||||||
// _interactionModule = interactionModule;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
public class RemoteException(string error) : Exception
|
|
||||||
{
|
|
||||||
public Guid CallRequestId;
|
|
||||||
public override string Message => $"Error in request {CallRequestId} : {error}";
|
|
||||||
}
|
|
||||||
@@ -1,47 +1,55 @@
|
|||||||
|
using System;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Frontend;
|
namespace mROA.Implementation.Frontend
|
||||||
|
|
||||||
public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
|
|
||||||
{
|
{
|
||||||
private readonly TcpClient _tcpClient = new();
|
public class NetworkFrontendBridge : IFrontendBridge
|
||||||
private NextGenerationInteractionModule? _interactionModule;
|
|
||||||
private ISerializationToolkit? _serialization;
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
{
|
||||||
switch (dependency)
|
private readonly IPEndPoint _ipEndPoint;
|
||||||
{
|
private readonly TcpClient _tcpClient = new();
|
||||||
case NextGenerationInteractionModule interactionModule:
|
private NextGenerationInteractionModule? _interactionModule;
|
||||||
_interactionModule = interactionModule;
|
private ISerializationToolkit? _serialization;
|
||||||
break;
|
|
||||||
case ISerializationToolkit toolkit:
|
|
||||||
_serialization = toolkit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Connect()
|
public NetworkFrontendBridge(IPEndPoint ipEndPoint)
|
||||||
{
|
|
||||||
if (_interactionModule is null)
|
|
||||||
throw new Exception("Interaction module was not injected");
|
|
||||||
if (_serialization == null)
|
|
||||||
throw new NullReferenceException("Serialization toolkit is not initialized");
|
|
||||||
|
|
||||||
_tcpClient.Connect(ipEndPoint);
|
|
||||||
_interactionModule.BaseStream = _tcpClient.GetStream();
|
|
||||||
_interactionModule.StartInfiniteReceiving();
|
|
||||||
|
|
||||||
var handle = _interactionModule.CurrentReceivingHandle;
|
|
||||||
handle.WaitOne();
|
|
||||||
var welcomeMessage = _interactionModule.LastMessage;
|
|
||||||
if (welcomeMessage.MessageType != EMessageType.IdAssigning)
|
|
||||||
{
|
{
|
||||||
throw new Exception($"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.MessageType.ToString()}");
|
_ipEndPoint = ipEndPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
|
{
|
||||||
|
switch (dependency)
|
||||||
|
{
|
||||||
|
case NextGenerationInteractionModule interactionModule:
|
||||||
|
_interactionModule = interactionModule;
|
||||||
|
break;
|
||||||
|
case ISerializationToolkit toolkit:
|
||||||
|
_serialization = toolkit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Connect()
|
||||||
|
{
|
||||||
|
if (_interactionModule is null)
|
||||||
|
throw new Exception("Interaction module was not injected");
|
||||||
|
if (_serialization == null)
|
||||||
|
throw new NullReferenceException("Serialization toolkit is not initialized");
|
||||||
|
|
||||||
|
_tcpClient.Connect(_ipEndPoint);
|
||||||
|
_interactionModule.BaseStream = _tcpClient.GetStream();
|
||||||
|
var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
|
||||||
|
if (welcomeMessage.SchemaId != MessageType.IdAssigning)
|
||||||
|
{
|
||||||
|
throw new Exception(
|
||||||
|
$"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.SchemaId.ToString()}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var assignment = _serialization.Deserialize<IdAssignment>(welcomeMessage.Data)!;
|
||||||
|
_interactionModule.ConnectionId = -assignment.Id;
|
||||||
|
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id);
|
||||||
}
|
}
|
||||||
_interactionModule.HandleMessage(welcomeMessage);
|
|
||||||
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize<IdAssingnment>(welcomeMessage.Data)!.Id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Implementation.Frontend
|
||||||
|
{
|
||||||
|
public class RemoteException : Exception
|
||||||
|
{
|
||||||
|
public Guid CallRequestId;
|
||||||
|
private readonly string _error;
|
||||||
|
|
||||||
|
public RemoteException(string error)
|
||||||
|
{
|
||||||
|
_error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string Message => $"Error in request {CallRequestId} : {_error}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,88 +1,158 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Implementation.Backend;
|
using mROA.Implementation.Backend;
|
||||||
using mROA.Implementation.CommandExecution;
|
using mROA.Implementation.CommandExecution;
|
||||||
|
|
||||||
// ReSharper disable MethodHasAsyncOverload
|
// ReSharper disable MethodHasAsyncOverload
|
||||||
|
|
||||||
namespace mROA.Implementation.Frontend;
|
namespace mROA.Implementation.Frontend
|
||||||
|
|
||||||
public class RequestExtractor : IRequestExtractor
|
|
||||||
{
|
{
|
||||||
private IRepresentationModule? _representationModule;
|
public class RequestExtractor : IRequestExtractor
|
||||||
private IContextRepository? _contextRepository;
|
|
||||||
private IMethodRepository? _methodRepository;
|
|
||||||
private IExecuteModule? _executeModule;
|
|
||||||
private ISerializationToolkit? _serializationToolkit;
|
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
|
||||||
{
|
{
|
||||||
switch (dependency)
|
private IExecuteModule? _executeModule;
|
||||||
|
private IMethodRepository? _methodRepository;
|
||||||
|
private IContextRepository? _realContextRepository;
|
||||||
|
private IContextRepository? _remoteContextRepository;
|
||||||
|
private IRepresentationModule? _representationModule;
|
||||||
|
private ISerializationToolkit? _serializationToolkit;
|
||||||
|
|
||||||
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
case IExecuteModule executeModule:
|
switch (dependency)
|
||||||
_executeModule = executeModule;
|
|
||||||
break;
|
|
||||||
case IContextRepository contextRepository:
|
|
||||||
_contextRepository = contextRepository;
|
|
||||||
break;
|
|
||||||
case IMethodRepository methodRepository:
|
|
||||||
_methodRepository = methodRepository;
|
|
||||||
break;
|
|
||||||
case IRepresentationModule representationModule:
|
|
||||||
_representationModule = representationModule;
|
|
||||||
break;
|
|
||||||
case ISerializationToolkit serializationToolkit:
|
|
||||||
_serializationToolkit = serializationToolkit;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task StartExtraction()
|
|
||||||
{
|
|
||||||
if (_serializationToolkit == null)
|
|
||||||
throw new NullReferenceException("Serializing toolkit is null.");
|
|
||||||
if (_executeModule == null)
|
|
||||||
throw new NullReferenceException("Execute module is null.");
|
|
||||||
if (_contextRepository == null)
|
|
||||||
throw new NullReferenceException("Context repository is null.");
|
|
||||||
if (_representationModule == null)
|
|
||||||
throw new NullReferenceException("Representation module is null.");
|
|
||||||
if (_methodRepository == null)
|
|
||||||
throw new NullReferenceException("Method repository is null.");
|
|
||||||
|
|
||||||
await Task.Yield();
|
|
||||||
|
|
||||||
var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
|
||||||
multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var lastCommandId = Guid.Empty;
|
|
||||||
while (true)
|
|
||||||
{
|
{
|
||||||
|
case IExecuteModule executeModule:
|
||||||
var request =
|
_executeModule = executeModule;
|
||||||
_representationModule!.GetMessage<DefaultCallRequest>(m => m.Id != lastCommandId && m.MessageType == EMessageType.CallRequest);
|
break;
|
||||||
lastCommandId = request.Id;
|
case MultiClientContextRepository:
|
||||||
if (request.Parameter is not null)
|
case ContextRepository:
|
||||||
{
|
_realContextRepository = dependency as IContextRepository;
|
||||||
var parameterType = _methodRepository!.GetMethod(request.CommandId).GetParameters().First()
|
break;
|
||||||
.ParameterType;
|
case RemoteContextRepository remoteContextRepository:
|
||||||
|
_remoteContextRepository = remoteContextRepository;
|
||||||
request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType);
|
break;
|
||||||
}
|
case IMethodRepository methodRepository:
|
||||||
|
_methodRepository = methodRepository;
|
||||||
var result = _executeModule.Execute(request, _contextRepository);
|
break;
|
||||||
|
case IRepresentationModule representationModule:
|
||||||
var resultType = result is FinalCommandExecution
|
_representationModule = representationModule;
|
||||||
? EMessageType.FinishedCommandExecution
|
break;
|
||||||
: EMessageType.ExceptionCommandExecution;
|
case ISerializationToolkit serializationToolkit:
|
||||||
|
_serializationToolkit = serializationToolkit;
|
||||||
_representationModule.PostCallMessage(request.Id, resultType, result, result.GetType());
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
|
public Task StartExtraction()
|
||||||
{
|
{
|
||||||
multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
|
return Task.Run(() =>
|
||||||
|
{
|
||||||
|
ThrowIfNotInjected();
|
||||||
|
var multiClientOwnershipRepository =
|
||||||
|
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
||||||
|
multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
var sw = new Stopwatch();
|
||||||
|
#endif
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine("Waiting for request...");
|
||||||
|
if (sw.IsRunning)
|
||||||
|
{
|
||||||
|
sw.Stop();
|
||||||
|
Console.WriteLine($"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
var tokenSource = new CancellationTokenSource();
|
||||||
|
var token = tokenSource.Token;
|
||||||
|
var defaultRequest =
|
||||||
|
_representationModule!.GetMessageAsync<DefaultCallRequest>(
|
||||||
|
messageType: MessageType.CallRequest, token: token);
|
||||||
|
var cancelRequest =
|
||||||
|
_representationModule!.GetMessageAsync<CancelRequest>(
|
||||||
|
messageType: MessageType.CancelRequest, token: token);
|
||||||
|
var eventRequest =
|
||||||
|
_representationModule!.GetMessageAsync<DefaultCallRequest>(
|
||||||
|
messageType: MessageType.EventRequest, token: token);
|
||||||
|
Task.WaitAny(defaultRequest, cancelRequest, eventRequest);
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
HandleEventRequest(tokenSource, eventRequest.Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
multiClientOwnershipRepository?.FreeOwnership();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThrowIfNotInjected()
|
||||||
|
{
|
||||||
|
if (_serializationToolkit == null)
|
||||||
|
throw new NullReferenceException("Serializing toolkit is null.");
|
||||||
|
if (_executeModule == null)
|
||||||
|
throw new NullReferenceException("Execute module is null.");
|
||||||
|
if (_realContextRepository == null)
|
||||||
|
throw new NullReferenceException("Context repository is null.");
|
||||||
|
if (_representationModule == null)
|
||||||
|
throw new NullReferenceException("Representation module is null.");
|
||||||
|
if (_methodRepository == null)
|
||||||
|
throw new NullReferenceException("Method repository is null.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCancelRequest(CancellationTokenSource tokenSource, CancelRequest req)
|
||||||
|
{
|
||||||
|
tokenSource.Cancel();
|
||||||
|
_executeModule!.Execute(req, _realContextRepository!, _representationModule!);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCallRequest(CancellationTokenSource tokenSource, DefaultCallRequest request)
|
||||||
|
{
|
||||||
|
tokenSource.Cancel();
|
||||||
|
|
||||||
|
var result = _executeModule!.Execute(request, _realContextRepository!, _representationModule!);
|
||||||
|
|
||||||
|
var resultType = result switch
|
||||||
|
{
|
||||||
|
FinalCommandExecution => MessageType.FinishedCommandExecution,
|
||||||
|
ExceptionCommandExecution => MessageType.ExceptionCommandExecution,
|
||||||
|
_ => MessageType.Unknown
|
||||||
|
};
|
||||||
|
if (resultType == MessageType.Unknown)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleEventRequest(CancellationTokenSource tokenSource, DefaultCallRequest request)
|
||||||
|
{
|
||||||
|
tokenSource.Cancel();
|
||||||
|
_executeModule!.Execute(request, _remoteContextRepository!, _representationModule!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,24 @@
|
|||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
|
||||||
namespace mROA.Implementation.Frontend;
|
namespace mROA.Implementation.Frontend
|
||||||
|
|
||||||
public class StaticOwnershipRepository(int id) : IOwnershipRepository
|
|
||||||
{
|
{
|
||||||
public int GetOwnershipId()
|
public class StaticOwnershipRepository : IOwnershipRepository
|
||||||
{
|
{
|
||||||
return id;
|
private readonly int _id;
|
||||||
}
|
|
||||||
|
|
||||||
public int GetHostOwnershipId()
|
public StaticOwnershipRepository(int id)
|
||||||
{
|
{
|
||||||
return id;
|
_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetOwnershipId()
|
||||||
|
{
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetHostOwnershipId()
|
||||||
|
{
|
||||||
|
return _id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
// public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontendInteractionModule
|
|
||||||
// {
|
|
||||||
// public Stream? ServerStream { get; set; }
|
|
||||||
// public int ClientId { get; set; }
|
|
||||||
//
|
|
||||||
// public NetworkMessage[] UnhandledMessages()
|
|
||||||
// {
|
|
||||||
// return Array.Empty<NetworkMessage>();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public NetworkMessage LastMessage()
|
|
||||||
// {
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// public async Task<byte[]> ReceiveMessage()
|
|
||||||
// {
|
|
||||||
// if (ServerStream is null)
|
|
||||||
// throw new IOException("Server is not connected.");
|
|
||||||
//
|
|
||||||
// const int bufferSize = ushort.MaxValue;
|
|
||||||
//
|
|
||||||
// var buffer = new byte[bufferSize];
|
|
||||||
// if (!ServerStream.CanRead) throw new IOException("Server is not connected.");
|
|
||||||
//
|
|
||||||
// await ServerStream.ReadExactlyAsync(buffer, 0, 2);
|
|
||||||
// var len = BitConverter.ToUInt16(buffer, 0);
|
|
||||||
// await ServerStream.ReadExactlyAsync(buffer, 0, len);
|
|
||||||
//
|
|
||||||
// return buffer[..len];
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void PostMessage(byte[] message)
|
|
||||||
// {
|
|
||||||
// if (ServerStream is null)
|
|
||||||
// throw new IOException("Server is not connected.");
|
|
||||||
//
|
|
||||||
// ServerStream.Write(BitConverter.GetBytes((ushort)message.Length), 0, sizeof(ushort));
|
|
||||||
// ServerStream.Write(message, 0, message.Length);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public void Inject<T>(T dependency)
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
public class IdAssignment
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace mROA.Implementation;
|
|
||||||
|
|
||||||
public class IdAssingnment
|
|
||||||
{
|
|
||||||
public int Id { get; set; }
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user