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:
2025-03-19 09:37:00 +03:00
116 changed files with 4431 additions and 2120 deletions
+12 -1
View File
@@ -2,9 +2,20 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE;</DefineConstants>
</PropertyGroup>
<ItemGroup>
+42 -19
View File
@@ -1,28 +1,51 @@
using Example.Shared;
using System;
using System.Threading;
using System.Threading.Tasks;
using Example.Shared;
using mROA.Implementation.Attributes;
namespace Example.Backend;
[SharedObjectSingleton]
public class LoadTestImp : ILoadTest
namespace Example.Backend
{
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)
{
return next - 1;
}
public int Last(int next)
{
return next - 1;
}
public void C()
{
throw new NotImplementedException();
}
public void C()
{
throw new NotImplementedException();
}
public void A()
{
throw new NotImplementedException();
public void A()
{
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");
}
}
}
+7 -6
View File
@@ -1,13 +1,14 @@
using System.Text;
using Example.Shared;
namespace Example.Backend;
public class Page : IPage
namespace Example.Backend
{
public string Text;
public byte[] GetData()
public class Page : IPage
{
return Encoding.UTF8.GetBytes(Text);
public string Text;
public byte[] GetData()
{
return Encoding.UTF8.GetBytes(Text);
}
}
}
+54
View File
@@ -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
View File
@@ -1,21 +1,44 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Example.Shared;
using mROA.Implementation;
namespace Example.Backend;
public class Printer : IPrinter
namespace Example.Backend
{
public string Name;
public string GetName()
public class Printer : IPrinter
{
return Name;
}
public string Name;
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken = default)
{
// throw new Exception("The method or operation is not implemented.");
// var sharedObject = new Page { Text = text };
return new Page { Text = text };
public void OnPrintExternal(IPage p0, RequestContext ro)
{
OnPrint?.Invoke(p0, ro);
}
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);
}
}
}
+32 -29
View File
@@ -1,40 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Example.Shared;
using mROA.Implementation;
using mROA.Implementation.Attributes;
namespace Example.Backend;
[SharedObjectSingleton]
public class PrinterFactory : IPrinterFactory
namespace Example.Backend
{
private List<IPrinter> _printers = new();
public SharedObject<IPrinter> Create(string printerName)
[SharedObjectSingleton]
public class PrinterFactory : IPrinterFactory
{
Console.WriteLine("Creating printer");
return new Printer { Name = printerName };
}
private List<IPrinter> _printers = new List<IPrinter>();
public void Register(SharedObject<IPrinter> printer)
{
_printers.Add(printer.Value);
Console.WriteLine("Registered printer");
}
public IPrinter Create(string printerName)
{
Console.WriteLine("Creating printer");
return new Printer { Name = printerName };
}
public SharedObject<IPrinter> GetPrinterByName(string printerName)
{
Console.WriteLine("Getting printer");
return new SharedObject<IPrinter>(_printers.Find(i => i.GetName() == printerName)!);
}
public void Register(IPrinter printer)
{
_printers.Add(printer);
Console.WriteLine("Registered printer");
}
public SharedObject<IPrinter> GetFirstPrinter()
{
return new SharedObject<IPrinter>(_printers.First());
}
public IPrinter GetPrinterByName(string printerName)
{
Console.WriteLine("Getting printer");
return (_printers.Find(i => i.GetName() == printerName)!);
}
public string[] CollectAllNames()
{
Console.WriteLine("Collecting all printers");
return _printers.Select(i => i.GetName()).ToArray();
public IPrinter GetFirstPrinter()
{
return _printers.First();
}
public string[] CollectAllNames()
{
Console.WriteLine("Collecting all printers");
return _printers.Select(i => i.GetName()).ToArray();
}
}
}
+43 -30
View File
@@ -1,43 +1,56 @@
using System.Net;
using System.Linq;
using System.Net;
using Example.Backend;
using mROA.Abstract;
using mROA.Cbor;
using mROA.Codegen;
using mROA.Implementation;
using mROA.Implementation.Backend;
using mROA.Implementation.Bootstrap;
using mROA.Implementation.Frontend;
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 =>
class Program
{
var repo = new ContextRepository();
repo.FillSingletons(typeof(PrinterFactory).Assembly);
return repo;
}));
builder.SetupMethodsRepository(new CoCodegenMethodRepository());
builder.Modules.Add(new CreativeRepresentationModuleProducer([builder.GetModule<JsonSerializationToolkit>()!],
typeof(RepresentationModule)));
public static void Main(string[] args)
{
var builder = new FullMixBuilder();
// builder.UseJsonSerialisation();
builder.Modules.Add(new CborSerializationToolkit());
builder.Modules.Add(new BackendIdentityGenerator());
// 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();
new RemoteTypeBinder();
builder.Modules.Add(new ConnectionHub());
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
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(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();
}
}
+18
View File
@@ -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)
{
}
}
+22
View File
@@ -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>
+53
View File
@@ -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>
+72
View File
@@ -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>
+13
View File
@@ -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;
}
}
+12
View File
@@ -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);
}
}
+38 -19
View File
@@ -1,28 +1,47 @@
using Example.Shared;
using System;
using System.Threading;
using System.Threading.Tasks;
using Example.Shared;
using mROA.Implementation;
namespace Example.Frontend;
public class ClientBasedPrinter : IPrinter
namespace Example.Frontend
{
public string GetName()
public class ClientBasedPrinter : IPrinter
{
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)");
return "ClientBasedPrinter from mroa";
public void OnPrintExternal(IPage p0, RequestContext ro)
{
}
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}");
await Task.Yield();
return new ClientBasedPage();
}
}
public class ClientBasedPage : IPage
{
public byte[] GetData()
{
return [1, 2, 3];
public byte[] GetData()
{
return new byte[] { 1, 2, 3 };
}
}
}
+37
View File
@@ -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();
}
}
}
}
+11 -1
View File
@@ -3,8 +3,18 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants>TRACE;</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants></DefineConstants>
</PropertyGroup>
<ItemGroup>
+106 -54
View File
@@ -1,80 +1,132 @@
using System.Diagnostics;
using System;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Example.Frontend;
using Example.Shared;
using mROA.Cbor;
using mROA.Codegen;
using mROA.Implementation;
using mROA.Implementation.Backend;
using mROA.Implementation.Bootstrap;
using mROA.Implementation.Frontend;
var builder = new FullMixBuilder();
new RemoteTypeBinder();
builder.Modules.Add(new JsonSerializationToolkit());
builder.Modules.Add(new RemoteContextRepository());
builder.Modules.Add(new NextGenerationInteractionModule());
builder.Modules.Add(new RepresentationModule());
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.Build();
class Program
{
public 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.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.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
builder.GetModule<NetworkFrontendBridge>()!.Connect();
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
var context = builder.GetModule<RemoteContextRepository>();
builder.GetModule<NetworkFrontendBridge>()!.Connect();
_ = builder.GetModule<RequestExtractor>()!.StartExtraction();
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
var context = builder.GetModule<RemoteContextRepository>();
var factory = context.GetSingleObject<IPrinterFactory>();
var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory;
//правильный порядок команд 8-5-10-7
var printer = factory.Create("Test");
Console.WriteLine("Printer created");
Thread.Sleep(100);
using (var disposingPrinter = factory.Create("Test"))
{
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();
Console.WriteLine("Printer name : {0}", name);
Thread.Sleep(100);
var name = disposingPrinter.GetName();
DemoCheck.BasicNonParamsCall = true;
Console.WriteLine("Printer name : {0}", name);
factory.Register(new SharedObject<IPrinter>(new ClientBasedPrinter()));
Console.WriteLine("Registered printer");
Thread.Sleep(100);
Thread.Sleep(100);
factory.Register(new ClientBasedPrinter());
DemoCheck.ClientBasedImplementation = true;
Console.WriteLine("Registered printer");
Thread.Sleep(100);
var registred = factory.GetFirstPrinter();
Console.WriteLine("First printer");
Thread.Sleep(100);
var registered = factory.GetFirstPrinter();
Console.WriteLine("First printer");
Thread.Sleep(100);
Console.WriteLine(registred.Value);
Console.WriteLine("Collecting all printers");
var names = factory.CollectAllNames();
Thread.Sleep(100);
Console.WriteLine(registered);
Console.WriteLine("Collecting all printers");
var names = factory.CollectAllNames();
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 data = page.Value.GetData();
Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data));
var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter()
.GetResult();
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;
var timer = Stopwatch.StartNew();
var x = 0;
for (int i = 0; i < iterations; i++)
{
x = loadSingleton.Next(x);
// Console.WriteLine(x);
Console.WriteLine("Restoring resource");
disposingPrinter.Resource = 100;
DemoCheck.PropertySet = true;
Console.WriteLine($"Printer resource again : {disposingPrinter.Resource}");
var data = page.GetData();
Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data));
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");
}
}
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 -1
View File
@@ -2,11 +2,12 @@
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<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"/>
+17
View File
@@ -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
View File
@@ -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;
[SharedObjectInterface]
public interface ILoadTest
namespace Example.Shared
{
int Next(int last);
int Last(int next);
void C();
void A();
}
[SharedObjectInterface]
public interface ILoadTest : IShared
{
int Next(int last);
int Last(int next);
void C();
void A();
Task AsyncTest(CancellationToken token = default);
}
}
+7 -5
View File
@@ -1,9 +1,11 @@
using mROA.Implementation;
using mROA.Implementation.Attributes;
namespace Example.Shared;
[SharedObjectInterface]
public interface IPage
namespace Example.Shared
{
byte[] GetData();
[SharedObjectInterface]
public interface IPage : IShared
{
byte[] GetData();
}
}
+9
View File
@@ -0,0 +1,9 @@
using mROA.Implementation.Attributes;
namespace Example.Shared
{
[SharedObjectInterface]
public partial interface IPagesList : IDataList<IPage>
{
}
}
+12 -7
View File
@@ -1,12 +1,17 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using mROA.Implementation;
using mROA.Implementation.Attributes;
namespace Example.Shared;
[SharedObjectInterface]
public interface IPrinter
namespace Example.Shared
{
string GetName();
Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken);
[SharedObjectInterface]
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;
}
}
+10 -10
View File
@@ -1,15 +1,15 @@
using mROA.Implementation;
using mROA.Implementation.Attributes;
namespace Example.Shared;
[SharedObjectInterface]
public interface IPrinterFactory
namespace Example.Shared
{
SharedObject<IPrinter> Create(string printerName);
void Register(SharedObject<IPrinter> printer);
SharedObject<IPrinter> GetPrinterByName(string printerName);
SharedObject<IPrinter> GetFirstPrinter();
string[] CollectAllNames();
[SharedObjectInterface]
public interface IPrinterFactory : IShared
{
IPrinter Create(string printerName);
void Register(IPrinter printer);
IPrinter GetPrinterByName(string printerName);
IPrinter GetFirstPrinter();
string[] CollectAllNames();
}
}
+45 -44
View File
@@ -1,50 +1,51 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
namespace mROA.Benchmark;
class Program
namespace mROA.Benchmark
{
static void Main(string[] args)
class Program
{
Console.WriteLine("Hello, World!");
var summary = BenchmarkRunner.Run<CollectionsSpeed>();
static void Main(string[] args)
{
// Console.WriteLine("Hello, World!");
// 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];
}
return sum;
}
[Benchmark]
public int ImmutableArray()
{
var sum = 0;
for (int i = 0; i < N; i++)
{
sum += _immutable[i];
}
return sum;
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];
}
return sum;
}
[Benchmark]
public int ImmutableArray()
{
var sum = 0;
for (int i = 0; i < N; i++)
{
sum += _immutable[i];
}
return sum;
}
}
}
+2 -2
View File
@@ -2,8 +2,8 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
+442
View File
@@ -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);
}
}
+75
View File
@@ -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;
}
}
}
+24
View File
@@ -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>
+6 -2
View File
@@ -25,13 +25,17 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
</ItemGroup>
<ItemGroup>
<None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
</ItemGroup>
<ItemGroup>
<None Remove="test.tpt" />
<EmbeddedResource Include="test.tpt" />
</ItemGroup>
</Project>
+628 -232
View File
@@ -1,3 +1,6 @@
// #define DONT_ADD
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@@ -6,174 +9,146 @@ using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
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
namespace mROA.Codegen
{
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>
/// 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>
/// <param name="context">Syntax context, based on CreateSyntaxProvider predicate</param>
/// <returns>The specific cast and whether the attribute was found.</returns>
private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen(
GeneratorSyntaxContext context)
[Generator]
public class mROASourceGenerator : ISourceGenerator
{
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.
foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists)
foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
private static Predicate<ITypeSymbol> ParameterFilterForType =
i => i.Name is "CancellationToken" or "RequestContext";
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);
}
/// <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)
public void Execute(GeneratorExecutionContext context)
{
// We need to get semantic model of the class to retrieve metadata.
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
var trees = context.Compilation.SyntaxTrees;
// Symbols allow us to get the compile-time information.
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 interfaces = new List<InterfaceDeclarationSyntax>();
foreach (var tree in trees)
{
var index = methods.Count;
methods.Add((namespaceName + "." + originalName, method));
var sb = new StringBuilder();
var node = tree.GetRoot() as CompilationUnitSyntax;
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";
bool isVoid = method.ReturnType.Name == "Void" || method.ReturnType.ToString() == "Task";
bool isParametrized = method.Parameters.Length == 1 && !isAsync ||
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());
if (inside is InterfaceDeclarationSyntax ids2)
if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2))
interfaces.Add(ids2);
}
}
}
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 System;
@@ -181,106 +156,527 @@ using mROA.Implementation;
using System.Collections.Generic;
using mROA.Abstract;
namespace {namespaceName};
partial class {className} : RemoteObjectBase, {originalName}
namespace {namespaceName}
{{
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.
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
// Add the source code to the compilation.
#if !DONT_ADD
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
#endif
frontendContextRepo.Add(
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
}
frontendContextRepo.Add(
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
}
if (totalMethods.Count != 0)
{
var methodsStringed = invokers;
if (methods.Count != 0)
{
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/>
var coCodegenRepoCode = @$"// <auto-generated/>
using System.Collections.Generic;
using System.Reflection;
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.Abstract;
using System;
using System.Threading;
namespace mROA.Codegen;
public sealed class RemoteTypeBinder
namespace mROA.Codegen
{{
static RemoteTypeBinder(){{
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {{
{string.Join(", \r\n\t\t", frontendContextRepo)}}}.ToFrozenDictionary();
public class CoCodegenMethodRepository : IMethodRepository
{{
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)
=> /*parameter.Type.ContainingNamespace is null*/
/*?*/ parameter.ToDisplayString();
/*: $"{parameter.Type.ContainingNamespace.ToDisplayString()}.{parameter.Type.MetadataName} {parameter.Name}";*/
private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List<string> invokers,
List<string> declaredMethods, GeneratorExecutionContext context, List<string> binders)
{
var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers())
.OfType<IEventSymbol>().ToList();
if (events.Count == 0)
return;
private static string ToFullString(ITypeSymbol type) =>
// => type.ContainingNamespace is null || type.Name == "Void"
type.ToDisplayString();
// : $"{type.ContainingNamespace.ToDisplayString()}.{type.MetadataName}";
var additionalSignatures = new List<string>(events.Count);
var singleEventBinder = new List<string>(events.Count);
for (int i = 0; i < events.Count; i++)
{
var currentEvent = events[i];
private string ExtractTaskType(ITypeSymbol taskType)
{
var type = taskType.ToString();
type = type.Substring(type.IndexOf('<') + 1);
return type.Substring(0, type.Length - 1);
var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature);
declaredMethods.Add(additionalMethod);
additionalSignatures.Add(signature);
GenerateEventCode(currentEvent, invokers, classSymbol);
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();
}
}
}
+1
View File
@@ -0,0 +1 @@
test text
@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
+125
View File
@@ -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
View File
@@ -1,71 +1,77 @@
using System.Net;
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using mROA.Implementation;
namespace mROA.Test;
public class NextGenTest
namespace mROA.Test
{
private TcpListener _listener;
private NextGenerationInteractionModule _interactionModuleA;
private NextGenerationInteractionModule _interactionModuleB;
private Guid[] guids = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
[SetUp]
public void Setup()
public class NextGenTest
{
_listener = new TcpListener(IPAddress.Loopback, 4567);
_interactionModuleA = new NextGenerationInteractionModule();
_interactionModuleA.Inject(new JsonSerializationToolkit());
_interactionModuleB = new NextGenerationInteractionModule();
_interactionModuleB.Inject(new JsonSerializationToolkit());
private TcpListener _listener;
private NextGenerationInteractionModule _interactionModuleA;
private NextGenerationInteractionModule _interactionModuleB;
private Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
}
[Test]
public void MultithreadedTest()
{
Task.Run(() =>
[SetUp]
public void Setup()
{
_listener.Start();
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
foreach (var guid in guids)
{
_interactionModuleB.PostMessage(new NetworkMessage { Id = guid, Data = "Hello user"u8.ToArray() });
}
});
_listener = new TcpListener(IPAddress.Loopback, 4567);
_interactionModuleA = new NextGenerationInteractionModule();
_interactionModuleA.Inject(new JsonSerializationToolkit());
_interactionModuleB = new NextGenerationInteractionModule();
_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()
{
[TearDown]
public void TearDown()
{
_listener.Dispose();
Task.Run(() =>
{
_listener.Start();
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
foreach (var guid in guids)
{
_interactionModuleB.PostMessage(new NetworkMessage { Id = guid, Data = "Hello user"u8.ToArray() });
}
});
var client = new TcpClient();
client.Connect(IPAddress.Loopback, 4567);
_interactionModuleA.BaseStream = client.GetStream();
var tasks = guids.Select(ReadStream);
Task.WaitAll(tasks.ToArray());
Assert.Pass();
}
private async Task ReadStream(Guid current)
{
var msg = await _interactionModuleA.GetNextMessageReceiving();
Console.WriteLine(
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
while (msg.Id != current)
{
msg = await _interactionModuleA.GetNextMessageReceiving();
Console.WriteLine(
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
}
Console.WriteLine($"{Environment.CurrentManagedThreadId} Good message received");
}
[TearDown]
public void TearDown()
{
_listener.Stop();
_listener.Dispose();
}
}
}
+26
View File
@@ -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));
}
}
+2 -1
View File
@@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
@@ -27,6 +27,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" />
<ProjectReference Include="..\mROA\mROA.csproj" />
</ItemGroup>
+46 -7
View File
@@ -19,24 +19,38 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Frontend", "Example
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Cbor", "mROA.Cbor\mROA.Cbor.csproj", "{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TotalDemo", "TotalDemo", "{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}"
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
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
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.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.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.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.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.Build.0 = Debug|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}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6868F42B-E30D-4040-AD4A-BC2A2E76D03A}.Release|Any CPU.Build.0 = Release|Any CPU
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6211E4EA-13FD-4EB1-8E6A-C0173DD0784A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{A9BB364E-0BA6-40B9-A293-757BC48EFC06} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{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
EndGlobal
+12
View File
@@ -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);
}
}
+6 -5
View File
@@ -1,8 +1,9 @@
namespace mROA.Abstract;
using System;
public interface ICommandExecution
namespace mROA.Abstract
{
Guid Id { get; init; }
int ClientId { get; set; }
int CommandId { get; }
public interface ICommandExecution
{
Guid Id { get; set; }
}
}
+12 -10
View File
@@ -1,12 +1,14 @@
namespace mROA.Abstract;
public delegate void ConnectionHandler(IRepresentationModule representationModule);
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
public interface IConnectionHub : IInjectableModule
namespace mROA.Abstract
{
void RegisterInteraction(INextGenerationInteractionModule interaction);
INextGenerationInteractionModule GetInteracion(int id);
event ConnectionHandler? OnConnected;
event DisconnectionHandler? OnDisconnected;
public delegate void ConnectionHandler(IRepresentationModule representationModule);
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
public interface IConnectionHub : IInjectableModule
{
void RegisterInteraction(INextGenerationInteractionModule interaction);
INextGenerationInteractionModule GetInteracion(int id);
event ConnectionHandler? OnConnected;
event DisconnectionHandler? OnDisconnected;
}
}
+12 -9
View File
@@ -1,12 +1,15 @@
namespace mROA.Abstract;
using System;
using mROA.Implementation;
public interface IContextRepository : IInjectableModule
namespace mROA.Abstract
{
int ResisterObject(object o);
void ClearObject(int id);
object GetObject(int id);
T? GetObject<T>(int id);
T GetSingleObject<T>();
object GetSingleObject(Type type);
int GetObjectIndex(object o);
public interface IContextRepository : IInjectableModule
{
int HostId { get; set; }
int ResisterObject<T>(object o, IEndPointContext context);
void ClearObject(ComplexObjectIdentifier id);
T GetObject<T>(ComplexObjectIdentifier id);
object GetSingleObject(Type type, int ownerId);
int GetObjectIndex<T>(object o, IEndPointContext context);
}
}
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract;
public interface IContextRepositoryHub
namespace mROA.Abstract
{
IContextRepository GetRepository(int clientId);
public interface IContextRepositoryHub
{
IContextRepository GetRepository(int clientId);
}
}
+10
View File
@@ -0,0 +1,10 @@
namespace mROA.Abstract
{
public interface IEndPointContext
{
IContextRepository RealRepository { get; }
IContextRepository RemoteRepository { get; }
int HostId { get; }
int OwnerId { get; }
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace mROA.Abstract
{
public interface IEventBinder<T>
{
public void BindEvents(T source, IEndPointContext context,
IRepresentationModuleProducer representationModuleProducer, int index);
}
}
+6 -4
View File
@@ -1,8 +1,10 @@
using mROA.Implementation;
namespace mROA.Abstract;
public interface IExecuteModule : IInjectableModule
namespace mROA.Abstract
{
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository);
public interface IExecuteModule : IInjectableModule
{
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
IRepresentationModule representationModule);
}
}
+6 -3
View File
@@ -1,3 +1,6 @@
namespace mROA.Abstract;
public interface IFrontendBridge : IInjectableModule;
namespace mROA.Abstract
{
public interface IFrontendBridge : IInjectableModule
{
}
}
+6 -3
View File
@@ -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();
}
}
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract;
public interface IIdentityGenerator : IInjectableModule
namespace mROA.Abstract
{
int GetNextIdentity();
public interface IIdentityGenerator : IInjectableModule
{
int GetNextIdentity();
}
}
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract;
public interface IInjectableModule
namespace mROA.Abstract
{
void Inject<T>(T dependency);
public interface IInjectableModule
{
void Inject<T>(T dependency);
}
}
+14 -13
View File
@@ -1,17 +1,18 @@
using System;
using System.IO;
using System.Threading.Tasks;
using mROA.Implementation;
namespace mROA.Abstract;
public interface INextGenerationInteractionModule : IInjectableModule
namespace mROA.Abstract
{
int ConnectionId { get; }
public Stream BaseStream { get; set; }
NetworkMessage[] UnhandledMessages { get; }
NetworkMessage LastMessage { get; }
EventWaitHandle CurrentReceivingHandle { get; }
void StartInfiniteReceiving();
Task<NetworkMessage> GetNextMessageReceiving();
Task PostMessage(NetworkMessage message);
void HandleMessage(NetworkMessage message);
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate);
public interface INextGenerationInteractionModule : IInjectableModule
{
int ConnectionId { get; }
public Stream? BaseStream { get; set; }
Task<NetworkMessage> GetNextMessageReceiving();
Task PostMessage(NetworkMessage message);
void HandleMessage(NetworkMessage message);
NetworkMessage[] UnhandledMessages { get; }
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate);
}
}
+12
View File
@@ -0,0 +1,12 @@
using System;
namespace mROA.Abstract
{
public interface IMethodInvoker
{
bool IsVoid { get; }
Type[] ParameterTypes { get; }
Type? ReturnType { get; }
Type SuitableType { get; }
}
}
+5 -9
View File
@@ -1,11 +1,7 @@
using System.Reflection;
namespace mROA.Abstract;
public interface IMethodRepository : IInjectableModule
namespace mROA.Abstract
{
MethodInfo GetMethod(int id);
int RegisterMethod(MethodInfo method);
IEnumerable<MethodInfo> GetMethods();
public interface IMethodRepository : IInjectableModule
{
IMethodInvoker GetMethod(int id);
}
}
+6 -5
View File
@@ -1,7 +1,8 @@
namespace mROA.Abstract;
public interface IOwnershipRepository
namespace mROA.Abstract
{
int GetOwnershipId();
int GetHostOwnershipId();
public interface IOwnershipRepository
{
int GetOwnershipId();
int GetHostOwnershipId();
}
}
+9
View File
@@ -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;
public interface IRepresentationModuleProducer : IInjectableModule
namespace mROA.Abstract
{
IRepresentationModule Produce(int id);
public interface IRepresentationModuleProducer : IInjectableModule
{
IRepresentationModule Produce(int id);
}
}
+6 -3
View File
@@ -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();
}
}
+19 -27
View File
@@ -1,33 +1,25 @@
using System.Windows.Input;
using System;
using System.Threading;
using System.Threading.Tasks;
using mROA.Implementation;
using mROA.Implementation.CommandExecution;
namespace mROA.Abstract;
public interface ISerialisationModule : IInjectableModule
namespace mROA.Abstract
{
void HandleIncomingRequest(int clientId, byte[] message);
void PostResponse(NetworkMessage message, int clientId);
void SendWelcomeMessage(int clientId);
public interface IFrontendSerialisationModule : IInjectableModule
public interface IRepresentationModule : IInjectableModule
{
int ClientId { get; }
Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution;
Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId);
void PostCallRequest(ICallRequest callRequest);
int Id { get; }
Task<T> GetMessageAsync<T>(Guid? requestId = null, MessageType? messageType = null,
CancellationToken token = default);
T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null);
Task<byte[]> GetRawMessage(Guid? requestId = null, MessageType? messageType = null,
CancellationToken token = default);
Task PostCallMessageAsync<T>(Guid id, MessageType messageType, T payload) where T : notnull;
Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType);
void PostCallMessage<T>(Guid id, MessageType messageType, T payload) where T : notnull;
void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType);
}
}
public interface IRepresentationModule : IInjectableModule
{
int Id { get; }
Task<T> GetMessageAsync<T>(Guid? requestId = null, EMessageType? messageType = null, CancellationToken token = default);
T GetMessage<T>(Guid? requestId = null, EMessageType? messageType = null);
T GetMessage<T>(Predicate<NetworkMessage> filter);
Task<byte[]> GetRawMessage(Predicate<NetworkMessage> filter, CancellationToken token = default);
Task PostCallMessageAsync<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType);
void PostCallMessage<T>(Guid id, EMessageType eMessageType, T payload) where T : notnull;
void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType);
}
+13 -11
View File
@@ -1,14 +1,16 @@
namespace mROA.Abstract;
using System;
public interface ISerializationToolkit : IInjectableModule
namespace mROA.Abstract
{
byte[] Serialize<T>(T objectToSerialize);
byte[] Serialize(object objectToSerialize, Type type);
T? Deserialize<T>(byte[] rawData);
object? Deserialize(byte[] rawData, Type type);
T? Deserialize<T>(Span<byte> rawData);
object? Deserialize(Span<byte> rawData, Type type);
T Cast<T>(object nonCasted);
object Cast(object nonCasted, Type type);
public interface ISerializationToolkit : IInjectableModule
{
byte[] Serialize<T>(T objectToSerialize);
byte[] Serialize(object objectToSerialize, Type type);
T? Deserialize<T>(byte[] rawData);
object? Deserialize(byte[] rawData, Type type);
T? Deserialize<T>(Span<byte> rawData);
object? Deserialize(Span<byte> rawData, Type type);
T? Cast<T>(object? nonCasted);
object? Cast(object? nonCasted, Type type);
}
}
+7
View File
@@ -0,0 +1,7 @@
namespace mROA.Implementation
{
#pragma warning disable CS8618, CS9264
public interface IShared
{
}
}
+10
View File
@@ -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;
namespace mROA.Implementation.Backend;
public class BackendIdentityGenerator : IIdentityGenerator
namespace mROA.Implementation.Backend
{
private int _currentId;
public int GetNextIdentity()
public class BackendIdentityGenerator : IIdentityGenerator
{
return ++_currentId;
}
private int _currentId;
public void Inject<T>(T dependency)
{
public int GetNextIdentity()
{
return ++_currentId;
}
public void Inject<T>(T dependency)
{
}
}
}
@@ -1,37 +1,35 @@
using System;
using System.Net;
using System.Reflection;
using mROA.Abstract;
using mROA.Implementation.Bootstrap;
namespace mROA.Implementation.Backend;
public static class BasicConfigurationExtensions
namespace mROA.Implementation.Backend
{
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)
{
builder.Modules.Add(new NetworkGatewayModule(endPoint, interactionModuleType, injectableModules));
}
public static void UseBasicExecution(this FullMixBuilder builder)
{
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)
{
var repo = new ContextRepository();
repo.FillSingletons(assemblies);
TransmissionConfig.RealContextRepository = repo;
builder.Modules.Add(repo);
}
public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies)
{
var repo = new ContextRepository();
repo.FillSingletons(assemblies);
TransmissionConfig.RealContextRepository = repo;
builder.Modules.Add(repo);
}
public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository)
{
builder.Modules.Add(methodRepository);
public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository)
{
builder.Modules.Add(methodRepository);
}
}
}
@@ -1,122 +1,263 @@
using System.Reflection;
using System;
using System.Threading;
using mROA.Abstract;
using mROA.Implementation.CommandExecution;
namespace mROA.Implementation.Backend;
public class BasicExecutionModule : IExecuteModule
namespace mROA.Implementation.Backend
{
private IMethodRepository? _methodRepo;
public void Inject<T>(T dependency)
public class BasicExecutionModule : IExecuteModule
{
if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo;
}
private ICancellationRepository? _cancellationRepo;
private IMethodRepository? _methodRepo;
private ISerializationToolkit? _serialization;
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository)
{
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
public void Inject<T>(T dependency)
{
var finalResult = currentCommand.Invoke(context, parameter is null ? [] : [parameter]);
return new TypedFinalCommandExecution
switch (dependency)
{
CommandId = command.CommandId, Result = finalResult,
Id = command.Id,
Type = currentCommand.ReturnType
case IMethodRepository methodRepo:
_methodRepo = methodRepo;
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,
Exception = e.ToString()
};
}
}
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
ICallRequest command)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
try
{
var result = (Task)currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token])!;
if (invoker.IsVoid)
{
return new FinalCommandExecution
{
Id = command.Id
};
}
result.Wait(token);
return new FinalCommandExecution { CommandId = command.CommandId, Id = command.Id };
}
catch (Exception e)
{
return new ExceptionCommandExecution
return new FinalCommandExecution<object>
{
Result = finalResult,
Id = command.Id
};
}
catch (Exception e)
{
Id = command.Id, CommandId = command.CommandId,
Exception = e.ToString()
};
return new ExceptionCommandExecution
{
Id = command.Id,
Exception = e.ToString()
};
}
}
}
private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
ICallRequest command)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
try
private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
ICallRequest command, ICancellationRepository cancellationRepository,
IRepresentationModule representationModule, RequestContext executionContext)
{
var result =
(Task)currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token])!;
result.Wait(token);
var finalResult = result.GetType().GetProperty("Result")?.GetValue(result);
return new TypedFinalCommandExecution
var tokenSource = new CancellationTokenSource();
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
var token = tokenSource.Token;
#if TRACE
token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}"));
#endif
try
{
Id = command.Id,
Result = finalResult,
CommandId = command.CommandId,
Type = finalResult?.GetType()
};
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
{
if (token.IsCancellationRequested)
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,
Exception = e.ToString()
};
invoker.Invoke(instance, parameters, new object[] { executionContext, token },
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()
};
}
}
}
}
+29 -26
View File
@@ -1,35 +1,38 @@
using mROA.Abstract;
using System;
using System.Collections.Generic;
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class ConnectionHub : IConnectionHub
namespace mROA.Implementation.Backend
{
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
private ISerializationToolkit? _serializationToolkit;
public void RegisterInteraction(INextGenerationInteractionModule interaction)
public class ConnectionHub : IConnectionHub
{
if (_serializationToolkit is null)
throw new NullReferenceException("Serialization toolkit is null");
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
private ISerializationToolkit? _serializationToolkit;
_connections.Add(interaction.ConnectionId, interaction);
var module = new RepresentationModule();
module.Inject(_serializationToolkit);
module.Inject(interaction);
OnConnected?.Invoke(module);
}
public void RegisterInteraction(INextGenerationInteractionModule interaction)
{
if (_serializationToolkit is null)
throw new NullReferenceException("Serialization toolkit is null");
public INextGenerationInteractionModule GetInteracion(int id)
{
return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
}
_connections.Add(interaction.ConnectionId, interaction);
var module = new RepresentationModule();
module.Inject(_serializationToolkit);
module.Inject(interaction);
OnConnected?.Invoke(module);
}
public event ConnectionHandler? OnConnected;
public event DisconnectionHandler? OnDisconnected;
public void Inject<T>(T dependency)
{
if (dependency is ISerializationToolkit serializationToolkit)
_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.Threading.Tasks;
using mROA.Abstract;
using mROA.Implementation.Attributes;
namespace mROA.Implementation.Backend;
public class ContextRepository : IContextRepository
namespace mROA.Implementation.Backend
{
private FrozenDictionary<int, object?>? _singletons;
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)
public class ContextRepository : IContextRepository
{
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.ToFrozenDictionary(
t => t.GetInterfaces().FirstOrDefault(i =>
i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(),
Activator.CreateInstance);
}
private const int StartupSize = 1024;
private const int GrowSize = 128;
public static object[] EventBinders = { };
public int ResisterObject(object o)
{
if (!_lastIndexFinder.IsCompleted)
_lastIndexFinder.Wait();
private static int LastDebugId = -1;
private int _debugId = -1;
_storage[_lastIndexFinder.Result] = o;
private Task<int> _lastIndexFinder = Task.FromResult(0);
var last = _lastIndexFinder.Result;
_lastIndexFinder = Task.Run(FindLastIndex);
private IRepresentationModuleProducer? _representationModuleProducer;
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)
{
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++)
public ContextRepository()
{
if (_storage[i] is null)
return i;
_storage = new ExtensibleStorage<object>();
}
var nextStorage = new object[_storage.Length + GrowSize];
Array.Copy(_storage, nextStorage, _storage.Length);
_storage = nextStorage;
return _storage.Length;
}
public int HostId { get; set; }
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;
namespace mROA.Implementation.Backend;
public class HubRequestExtractor(Type extractoType) : IInjectableModule
namespace mROA.Implementation.Backend
{
private IConnectionHub? _hub;
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private ISerializationToolkit? _serializationToolkit;
private IExecuteModule? _executeModule;
public void Inject<T>(T dependency)
public class HubRequestExtractor : IInjectableModule
{
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:
_hub = connectionHub;
_hub.OnConnected += HubOnOnConnected;
break;
case IContextRepository contextRepository:
_contextRepository = contextRepository;
break;
case IMethodRepository methodRepository:
_methodRepository = methodRepository;
break;
case ISerializationToolkit serializationToolkit:
_serializationToolkit = serializationToolkit;
break;
case IExecuteModule executeModule:
_executeModule = executeModule;
break;
_extractorType = extractorType;
}
public void Inject<T>(T dependency)
{
switch (dependency)
{
case IConnectionHub connectionHub:
_hub = connectionHub;
_hub.OnConnected += HubOnOnConnected;
break;
case MultiClientContextRepository:
case ContextRepository:
_contextRepository = dependency as IContextRepository;
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;
namespace mROA.Implementation.Backend;
public class MultiClientContextRepository(Func<int, IContextRepository> produceRepository) : IContextRepository, IContextRepositoryHub
namespace mROA.Implementation.Backend
{
private Dictionary<int, IContextRepository> _repositories = new();
private IContextRepository GetRepositoryByClientId(int clientId)
public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub
{
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;
}
var created = produceRepository(clientId);
_repositories.Add(clientId, created);
return created;
}
public void Inject<T>(T dependency)
{
}
private IContextRepository GetRepositoryByClientId(int clientId)
{
if (_repositories.TryGetValue(clientId, out var repository))
return repository;
public int ResisterObject(object o)
{
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o);
}
public void ClearObject(int id)
{
GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id);
}
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);
var created = _produceRepository(clientId);
_repositories.Add(clientId, created);
return created;
}
}
}
@@ -1,28 +1,31 @@
using mROA.Abstract;
using System;
using System.Collections.Generic;
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class MultiClientOwnershipRepository : IOwnershipRepository
namespace mROA.Implementation.Backend
{
private Dictionary<int, int> _ownerships = new();
public int GetOwnershipId()
public class MultiClientOwnershipRepository : IOwnershipRepository
{
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
}
private Dictionary<int, int> _ownerships = new();
public int GetHostOwnershipId()
{
return 0;
}
public int GetOwnershipId()
{
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
}
public void RegisterOwnership(int ownershipId)
{
_ownerships.TryAdd(Environment.CurrentManagedThreadId, ownershipId);
}
public int GetHostOwnershipId()
{
return 0;
}
public void FreeOwnership()
{
_ownerships.Remove(Environment.CurrentManagedThreadId);
public void RegisterOwnership(int ownershipId)
{
_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.Threading.Tasks;
using mROA.Abstract;
namespace mROA.Implementation.Backend;
public class NetworkGatewayModule : IGatewayModule
namespace mROA.Implementation.Backend
{
private readonly Type? _interactionModuleType;
private readonly IInjectableModule[]? _injectableModules;
private readonly TcpListener _tcpListener;
private IConnectionHub? _hub;
private ISerializationToolkit? _serialization;
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules)
public class NetworkGatewayModule : IGatewayModule
{
_tcpListener = new(endpoint);
_interactionModuleType = interactionModuleType;
_injectableModules = injectableModules;
}
private readonly IInjectableModule[]? _injectableModules;
private readonly Type? _interactionModuleType;
private readonly TcpListener _tcpListener;
private IConnectionHub? _hub;
private ISerializationToolkit? _serialization;
public void Run()
{
_tcpListener.Start();
Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
Console.WriteLine("Enter Backspace to stop");
Task.Run(HandleIncomingConnections);
while (true)
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType,
IInjectableModule[] injectableModules)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Backspace)
break;
_tcpListener = new(endpoint);
_interactionModuleType = interactionModuleType;
_injectableModules = injectableModules;
}
Console.WriteLine("Stopping");
}
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)
public void Run()
{
var client = _tcpListener.AcceptTcpClient();
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
var interaction = Activator.CreateInstance(_interactionModuleType) as INextGenerationInteractionModule;
_tcpListener.Start();
Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
Console.WriteLine("Enter Backspace to stop");
foreach (var injectableModule in _injectableModules)
interaction!.Inject(injectableModule);
Task.Run(HandleIncomingConnections);
interaction!.Inject(_serialization);
interaction.BaseStream = client.GetStream();
interaction.StartInfiniteReceiving();
interaction.PostMessage(new NetworkMessage
while (true)
{
Id = Guid.NewGuid(), MessageType = EMessageType.IdAssigning,
Data = _serialization.Serialize(new IdAssingnment { Id = interaction.ConnectionId })
});
_hub.RegisterInteraction(interaction);
Console.WriteLine("Client registered");
}
}
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Backspace)
break;
}
public void Inject<T>(T dependency)
{
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule;
if (dependency is ISerializationToolkit serializationToolkit)
_serialization = serializationToolkit;
Console.WriteLine("Stopping");
}
public void Dispose()
{
_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;
// }
// }
//
// }
+16 -13
View File
@@ -1,20 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using mROA.Abstract;
namespace mROA.Implementation.Bootstrap;
public class FullMixBuilder
namespace mROA.Implementation.Bootstrap
{
public List<IInjectableModule> Modules { get; } = [];
public void Build()
public class FullMixBuilder
{
foreach (var module in Modules)
foreach (var injection in Modules)
module.Inject(injection);
}
public List<IInjectableModule> Modules { get; } = new() { };
public T? GetModule<T>()
{
return Modules.OfType<T>().FirstOrDefault();
public void Build()
{
foreach (var module in Modules)
foreach (var injection in Modules)
module.Inject(injection);
}
public T? GetModule<T>()
{
return Modules.OfType<T>().FirstOrDefault();
}
}
}
+35 -17
View File
@@ -1,24 +1,42 @@
using System.Text.Json.Serialization;
using System;
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
namespace mROA.Implementation;
public interface ICallRequest
namespace mROA.Implementation
{
Guid Id { get; }
int CommandId { get; }
int ObjectId { get; }
object? Parameter { get; }
}
public interface ICallRequest
{
Guid Id { get; }
int CommandId { get; }
ComplexObjectIdentifier ObjectId { get; }
object?[]? Parameters { get; }
}
public class DefaultCallRequest : ICallRequest
{
public Guid Id { get; set; } = Guid.NewGuid();
public int CommandId { get; init; }
public int ObjectId { get; init; } = -1;
public class DefaultCallRequest : ICallRequest
{
public Guid Id { get; set; } = Guid.NewGuid();
public int CommandId { get; set; }
public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null;
[JsonIgnore]
public Type? ParameterType { get; init; }
public object? Parameter { get; set; }
public object?[]? Parameters { 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;
namespace mROA.Implementation.CommandExecution;
public class ExceptionCommandExecution : ICommandExecution
namespace mROA.Implementation.CommandExecution
{
public Guid Id { get; init; }
public int ClientId { get; set; }
public int CommandId { get; init; }
public required string Exception { get; set; }
public RemoteException GetException()
public class ExceptionCommandExecution : ICommandExecution
{
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;
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace mROA.Implementation.CommandExecution;
public class FinalCommandExecution : ICommandExecution
namespace mROA.Implementation.CommandExecution
{
public Guid Id { get; init; }
[JsonIgnore]
public int ClientId { get; set; }
[JsonIgnore]
public int CommandId { get; init; }
}
public class FinalCommandExecution : ICommandExecution
{
public Guid Id { get; set; }
}
public class FinalCommandExecution<T> : FinalCommandExecution
{
public T? Result { get; init; }
public class FinalCommandExecution<T> : FinalCommandExecution
{
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;
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
namespace mROA.Implementation
{
private Type _reprModuleType;
private IInjectableModule[] _creationModules;
private IConnectionHub? _hub;
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
{
_creationModules = creationModules;
_reprModuleType = reprModuleType;
}
private Type _reprModuleType;
private IInjectableModule[] _creationModules;
private IConnectionHub? _hub;
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
{
_creationModules = creationModules;
_reprModuleType = reprModuleType;
}
public void Inject<T>(T dependency)
{
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule;
}
public void Inject<T>(T dependency)
{
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule;
}
public IRepresentationModule Produce(int id)
{
if (_hub == null)
throw new NullReferenceException("Interaction module is null");
public IRepresentationModule Produce(int id)
{
if (_hub == null)
throw new NullReferenceException("Interaction module is null");
var produced =
Activator.CreateInstance(_reprModuleType) as IRepresentationModule ??
throw new Exception("Bad serialization module type");
var produced =
Activator.CreateInstance(_reprModuleType) as IRepresentationModule ??
throw new Exception("Bad serialization module type");
foreach (var creationModule in _creationModules)
produced.Inject(creationModule);
foreach (var creationModule in _creationModules)
produced.Inject(creationModule);
produced.Inject(_hub.GetInteracion(id));
var interaction = _hub.GetInteracion(id);
produced.Inject(interaction);
return produced;
return produced;
}
}
}
+20
View File
@@ -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; }
}
}
}
+15
View File
@@ -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);
}
}
}
+61
View File
@@ -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.Sockets;
using mROA.Abstract;
namespace mROA.Implementation.Frontend;
public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
namespace mROA.Implementation.Frontend
{
private readonly TcpClient _tcpClient = new();
private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
public void Inject<T>(T dependency)
public class NetworkFrontendBridge : IFrontendBridge
{
switch (dependency)
private readonly IPEndPoint _ipEndPoint;
private readonly TcpClient _tcpClient = new();
private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
public NetworkFrontendBridge(IPEndPoint ipEndPoint)
{
case NextGenerationInteractionModule interactionModule:
_interactionModule = interactionModule;
break;
case ISerializationToolkit toolkit:
_serialization = toolkit;
break;
_ipEndPoint = ipEndPoint;
}
}
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();
_interactionModule.StartInfiniteReceiving();
var handle = _interactionModule.CurrentReceivingHandle;
handle.WaitOne();
var welcomeMessage = _interactionModule.LastMessage;
if (welcomeMessage.MessageType != EMessageType.IdAssigning)
public void Inject<T>(T dependency)
{
throw new Exception($"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.MessageType.ToString()}");
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}";
}
}
+142 -72
View File
@@ -1,88 +1,158 @@
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using mROA.Abstract;
using mROA.Implementation.Backend;
using mROA.Implementation.CommandExecution;
// ReSharper disable MethodHasAsyncOverload
namespace mROA.Implementation.Frontend;
public class RequestExtractor : IRequestExtractor
namespace mROA.Implementation.Frontend
{
private IRepresentationModule? _representationModule;
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private IExecuteModule? _executeModule;
private ISerializationToolkit? _serializationToolkit;
public void Inject<T>(T dependency)
public class RequestExtractor : IRequestExtractor
{
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:
_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)
switch (dependency)
{
var request =
_representationModule!.GetMessage<DefaultCallRequest>(m => m.Id != lastCommandId && m.MessageType == EMessageType.CallRequest);
lastCommandId = request.Id;
if (request.Parameter is not null)
{
var parameterType = _methodRepository!.GetMethod(request.CommandId).GetParameters().First()
.ParameterType;
request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType);
}
var result = _executeModule.Execute(request, _contextRepository);
var resultType = result is FinalCommandExecution
? EMessageType.FinishedCommandExecution
: EMessageType.ExceptionCommandExecution;
_representationModule.PostCallMessage(request.Id, resultType, result, result.GetType());
case IExecuteModule executeModule:
_executeModule = executeModule;
break;
case MultiClientContextRepository:
case ContextRepository:
_realContextRepository = dependency as IContextRepository;
break;
case RemoteContextRepository remoteContextRepository:
_remoteContextRepository = remoteContextRepository;
break;
case IMethodRepository methodRepository:
_methodRepository = methodRepository;
break;
case IRepresentationModule representationModule:
_representationModule = representationModule;
break;
case ISerializationToolkit serializationToolkit:
_serializationToolkit = serializationToolkit;
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;
namespace mROA.Implementation.Frontend;
public class StaticOwnershipRepository(int id) : IOwnershipRepository
namespace mROA.Implementation.Frontend
{
public int GetOwnershipId()
public class StaticOwnershipRepository : IOwnershipRepository
{
return id;
}
private readonly int _id;
public int GetHostOwnershipId()
{
return id;
public StaticOwnershipRepository(int 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)
// {
// }
// }
+7
View File
@@ -0,0 +1,7 @@
namespace mROA.Implementation
{
public class IdAssignment
{
public int Id { get; set; }
}
}
-6
View File
@@ -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