diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj
index 62581cc..95845de 100644
--- a/Example.Backend/Example.Backend.csproj
+++ b/Example.Backend/Example.Backend.csproj
@@ -2,9 +2,20 @@
Exe
+
net9.0
- enable
+
enable
+
+ 9
+
+
+
+ TRACE
+
+
+
+ TRACE;
diff --git a/Example.Backend/LoadTestImp.cs b/Example.Backend/LoadTestImp.cs
index e0ea125..a1fec60 100644
--- a/Example.Backend/LoadTestImp.cs
+++ b/Example.Backend/LoadTestImp.cs
@@ -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");
+ }
}
}
\ No newline at end of file
diff --git a/Example.Backend/Page.cs b/Example.Backend/Page.cs
index a635f09..7e2fb4d 100644
--- a/Example.Backend/Page.cs
+++ b/Example.Backend/Page.cs
@@ -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);
+ }
}
}
\ No newline at end of file
diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs
new file mode 100644
index 0000000..1b195c9
--- /dev/null
+++ b/Example.Backend/PagesList.cs
@@ -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 Collection { get; }
+
+ public IPage this[int index]
+ {
+ get => GetResultAsync(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? OnAdd;
+ public event Action? OnRemove;
+
+ public void Dispose()
+ {
+ // TODO release managed resources here
+ }
+
+ public void OnAddExternal(IPage p0)
+ {
+ }
+
+ public void OnRemoveExternal(IPage p0)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs
index 85cf27b..87958c9 100644
--- a/Example.Backend/Printer.cs
+++ b/Example.Backend/Printer.cs
@@ -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> 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 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? OnPrint;
+
+ public void Dispose()
+ {
+ Console.WriteLine(
+ "Dispose printer with name {0}, Dispose works, Dispose works, Dispose works, Dispose works,", Name);
+ }
}
}
\ No newline at end of file
diff --git a/Example.Backend/PrinterFactory.cs b/Example.Backend/PrinterFactory.cs
index e71503f..efc3975 100644
--- a/Example.Backend/PrinterFactory.cs
+++ b/Example.Backend/PrinterFactory.cs
@@ -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 _printers = new();
-
- public SharedObject Create(string printerName)
+ [SharedObjectSingleton]
+ public class PrinterFactory : IPrinterFactory
{
- Console.WriteLine("Creating printer");
- return new Printer { Name = printerName };
- }
+ private List _printers = new List();
- public void Register(SharedObject 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 GetPrinterByName(string printerName)
- {
- Console.WriteLine("Getting printer");
- return new SharedObject(_printers.Find(i => i.GetName() == printerName)!);
- }
+ public void Register(IPrinter printer)
+ {
+ _printers.Add(printer);
+ Console.WriteLine("Registered printer");
+ }
- public SharedObject GetFirstPrinter()
- {
- return new SharedObject(_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();
+ }
}
}
\ No newline at end of file
diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs
index 65c6fbf..1e12d48 100644
--- a/Example.Backend/Program.cs
+++ b/Example.Backend/Program.cs
@@ -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()!);
-
-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()!],
- 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()!);
+ builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
+ builder.GetModule()!);
-builder.Build();
-new RemoteTypeBinder();
+ builder.Modules.Add(new ConnectionHub());
+ builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
-TransmissionConfig.RealContextRepository = builder.GetModule();
-TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
-TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
+ builder.UseBasicExecution();
+ builder.Modules.Add(new CreativeRepresentationModuleProducer(
+ new IInjectableModule[] { builder.GetModule()! },
+ 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().First());
+ return repo;
+ }));
+ builder.SetupMethodsRepository(new CoCodegenMethodRepository());
-var gateway = builder.GetModule();
+ builder.Modules.Add(new CancellationRepository());
-gateway.Run();
\ No newline at end of file
+ builder.Build();
+ new RemoteTypeBinder();
+
+ TransmissionConfig.RealContextRepository = builder.GetModule();
+ TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
+ TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
+
+ var gateway = builder.GetModule();
+
+ gateway.Run();
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Backend/Chat.cs b/Example.Events.Backend/Chat.cs
new file mode 100644
index 0000000..2239d59
--- /dev/null
+++ b/Example.Events.Backend/Chat.cs
@@ -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? OnCharPosted;
+
+ public void OnCharPostedExternal(string p0, RequestContext p1)
+ {
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Backend/ChatFactory.cs b/Example.Events.Backend/ChatFactory.cs
new file mode 100644
index 0000000..90a4c65
--- /dev/null
+++ b/Example.Events.Backend/ChatFactory.cs
@@ -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 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;
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Backend/Example.Events.Backend.csproj b/Example.Events.Backend/Example.Events.Backend.csproj
new file mode 100644
index 0000000..4e79fe1
--- /dev/null
+++ b/Example.Events.Backend/Example.Events.Backend.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example.Events.Backend/Program.cs b/Example.Events.Backend/Program.cs
new file mode 100644
index 0000000..d42eb89
--- /dev/null
+++ b/Example.Events.Backend/Program.cs
@@ -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()!);
+
+ builder.Modules.Add(new ConnectionHub());
+ builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
+
+ builder.UseBasicExecution();
+ builder.Modules.Add(new CreativeRepresentationModuleProducer(
+ new IInjectableModule[] { builder.GetModule()! },
+ 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().First());
+ return repo;
+ }));
+ builder.SetupMethodsRepository(new CoCodegenMethodRepository());
+
+ builder.Modules.Add(new CancellationRepository());
+
+ builder.Build();
+ new RemoteTypeBinder();
+
+ TransmissionConfig.RealContextRepository = builder.GetModule();
+ TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
+ TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
+
+ var gateway = builder.GetModule();
+
+ gateway.Run();
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Client/Example.Events.Client.csproj b/Example.Events.Client/Example.Events.Client.csproj
new file mode 100644
index 0000000..4e79fe1
--- /dev/null
+++ b/Example.Events.Client/Example.Events.Client.csproj
@@ -0,0 +1,18 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Example.Events.Client/Program.cs b/Example.Events.Client/Program.cs
new file mode 100644
index 0000000..155e969
--- /dev/null
+++ b/Example.Events.Client/Program.cs
@@ -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();
+ TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
+
+ builder.GetModule()!.Connect();
+ _ = builder.GetModule()!.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
+ }
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Shared/Example.Events.Shared.csproj b/Example.Events.Shared/Example.Events.Shared.csproj
new file mode 100644
index 0000000..98d21fd
--- /dev/null
+++ b/Example.Events.Shared/Example.Events.Shared.csproj
@@ -0,0 +1,16 @@
+
+
+
+ net9.0
+ enable
+ 9
+
+
+
+
+
+
+
+
+
+
diff --git a/Example.Events.Shared/IChat.cs b/Example.Events.Shared/IChat.cs
new file mode 100644
index 0000000..a37b06a
--- /dev/null
+++ b/Example.Events.Shared/IChat.cs
@@ -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 OnCharPosted;
+ }
+}
\ No newline at end of file
diff --git a/Example.Events.Shared/IChatFactory.cs b/Example.Events.Shared/IChatFactory.cs
new file mode 100644
index 0000000..b73949b
--- /dev/null
+++ b/Example.Events.Shared/IChatFactory.cs
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs
index 58a97c8..6afc7a3 100644
--- a/Example.Frontend/ClientBasedPrinter.cs
+++ b/Example.Frontend/ClientBasedPrinter.cs
@@ -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 Print(string text, bool some, RequestContext context,
+ CancellationToken cancellationToken)
+ {
+ Console.WriteLine($"Printed: {text}");
+ await Task.Yield();
+ return new ClientBasedPage();
+ }
+
+ public event Action? OnPrint;
+
+ public void Dispose()
+ {
+ }
}
- public async Task> 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 };
+ }
}
}
\ No newline at end of file
diff --git a/Example.Frontend/DemoCheck.cs b/Example.Frontend/DemoCheck.cs
new file mode 100644
index 0000000..efc95aa
--- /dev/null
+++ b/Example.Frontend/DemoCheck.cs
@@ -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();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj
index f59d7cc..fdac1b1 100644
--- a/Example.Frontend/Example.Frontend.csproj
+++ b/Example.Frontend/Example.Frontend.csproj
@@ -3,8 +3,18 @@
Exe
net9.0
- enable
+
enable
+
+ 9
+
+
+
+ TRACE;
+
+
+
+
diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs
index f4800df..156026d 100644
--- a/Example.Frontend/Program.cs
+++ b/Example.Frontend/Program.cs
@@ -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();
-TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
+ TransmissionConfig.RealContextRepository = builder.GetModule();
+ TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule();
-builder.GetModule()!.Connect();
-_ = builder.GetModule()!.StartExtraction();
-Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
-var context = builder.GetModule();
+ builder.GetModule()!.Connect();
+ _ = builder.GetModule()!.StartExtraction();
+ Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ var context = builder.GetModule();
-var factory = context.GetSingleObject();
+ 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(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}");
-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");
\ No newline at end of file
+ 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");
+ }
+}
\ No newline at end of file
diff --git a/Example.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj
index 40f085d..98d21fd 100644
--- a/Example.Shared/Example.Shared.csproj
+++ b/Example.Shared/Example.Shared.csproj
@@ -2,14 +2,15 @@
net9.0
- enable
enable
+ 9
+
-
+
diff --git a/Example.Shared/IDataList.cs b/Example.Shared/IDataList.cs
new file mode 100644
index 0000000..bdaae63
--- /dev/null
+++ b/Example.Shared/IDataList.cs
@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using mROA.Implementation;
+
+namespace Example.Shared
+{
+ public interface IDataList : IShared, IDisposable
+ {
+ IReadOnlyList Collection { get; }
+ T this[int index] { get; set; }
+ T Get(int index);
+ void Add(T item);
+ void Remove(int index, T item);
+ event Action OnAdd;
+ event Action OnRemove;
+ }
+}
\ No newline at end of file
diff --git a/Example.Shared/ILoadTest.cs b/Example.Shared/ILoadTest.cs
index dc4e787..227af99 100644
--- a/Example.Shared/ILoadTest.cs
+++ b/Example.Shared/ILoadTest.cs
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/Example.Shared/IPage.cs b/Example.Shared/IPage.cs
index 6f39f19..c7517ff 100644
--- a/Example.Shared/IPage.cs
+++ b/Example.Shared/IPage.cs
@@ -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();
+ }
}
\ No newline at end of file
diff --git a/Example.Shared/IPagesList.cs b/Example.Shared/IPagesList.cs
new file mode 100644
index 0000000..0b4d5d5
--- /dev/null
+++ b/Example.Shared/IPagesList.cs
@@ -0,0 +1,9 @@
+using mROA.Implementation.Attributes;
+
+namespace Example.Shared
+{
+ [SharedObjectInterface]
+ public partial interface IPagesList : IDataList
+ {
+ }
+}
\ No newline at end of file
diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs
index 2d8e6c8..f5b25f0 100644
--- a/Example.Shared/IPrinter.cs
+++ b/Example.Shared/IPrinter.cs
@@ -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> Print(string text, CancellationToken cancellationToken);
-
+ [SharedObjectInterface]
+ public partial interface IPrinter : IDisposable, IShared
+ {
+ double Resource { get; set; }
+ string GetName();
+ Task Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken);
+ event Action OnPrint;
+ }
}
\ No newline at end of file
diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs
index eb6ee8e..60d4d0e 100644
--- a/Example.Shared/IPrinterFactory.cs
+++ b/Example.Shared/IPrinterFactory.cs
@@ -1,15 +1,15 @@
using mROA.Implementation;
using mROA.Implementation.Attributes;
-namespace Example.Shared;
-
-[SharedObjectInterface]
-public interface IPrinterFactory
+namespace Example.Shared
{
- SharedObject Create(string printerName);
- void Register(SharedObject printer);
- SharedObject GetPrinterByName(string printerName);
- SharedObject GetFirstPrinter();
- string[] CollectAllNames();
-
+ [SharedObjectInterface]
+ public interface IPrinterFactory : IShared
+ {
+ IPrinter Create(string printerName);
+ void Register(IPrinter printer);
+ IPrinter GetPrinterByName(string printerName);
+ IPrinter GetFirstPrinter();
+ string[] CollectAllNames();
+ }
}
\ No newline at end of file
diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs
index 57ab0c3..217a6d7 100644
--- a/mROA.Benchmark/Program.cs
+++ b/mROA.Benchmark/Program.cs
@@ -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();
-
- }
-}
-
-public class CollectionsSpeed
-{
- private const int N = 1000;
-
- private readonly List _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++)
+ static void Main(string[] args)
{
- sum += _array[i];
+ // Console.WriteLine("Hello, World!");
+ // var summary = BenchmarkRunner.Run();
}
- return sum;
}
-
- [Benchmark]
- public int ImmutableArray()
+
+ public class CollectionsSpeed
{
- var sum = 0;
- for (int i = 0; i < N; i++)
+ private const int N = 1000;
+
+ private readonly List _immutable;
+ private readonly int[] _array;
+
+ public CollectionsSpeed()
{
- sum += _immutable[i];
+ _array = Enumerable.Range(0, N).ToArray();
+ // _immutable = [.._array];
+ }
+
+ [Benchmark]
+ public int DefaultArray()
+ {
+ var sum = 0;
+ for (int i = 0; i < N; i++)
+ {
+ sum += _array[i];
+ }
+ return sum;
+ }
+
+ [Benchmark]
+ public int ImmutableArray()
+ {
+ var sum = 0;
+ for (int i = 0; i < N; i++)
+ {
+ sum += _immutable[i];
+ }
+ return sum;
}
- return sum;
}
}
\ No newline at end of file
diff --git a/mROA.Benchmark/mROA.Benchmark.csproj b/mROA.Benchmark/mROA.Benchmark.csproj
index 78eb323..5697c66 100644
--- a/mROA.Benchmark/mROA.Benchmark.csproj
+++ b/mROA.Benchmark/mROA.Benchmark.csproj
@@ -2,8 +2,8 @@
Exe
- net9.0
- enable
+ netstandard2.1
+
enable
diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs
new file mode 100644
index 0000000..47d1fc0
--- /dev/null
+++ b/mROA.Cbor/CborSerializationToolkit.cs
@@ -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 destination, IEndPointContext context)
+ {
+ var writer = new CborWriter();
+ WriteData(objectToSerialize, writer, context);
+ writer.Encode(destination);
+ }
+
+ public T Deserialize(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(ReadOnlyMemory rawMemory, IEndPointContext? context)
+ {
+ return (T)Deserialize(rawMemory, typeof(T), context);
+ }
+
+ public object? Deserialize(ReadOnlyMemory rawMemory, Type type, IEndPointContext? context)
+ {
+ var reader = new CborReader(rawMemory);
+ return ReadData(reader, type, context);
+ }
+
+ public T Cast(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 dependency)
+ {
+ }
+
+ public byte[] Serialize(T objectToSerialize)
+ {
+ return Serialize(objectToSerialize, typeof(T));
+ }
+
+ public byte[] Serialize(object objectToSerialize, Type type)
+ {
+ return Serialize(objectToSerialize, context: null);
+ }
+
+ public T Deserialize(byte[] rawData)
+ {
+ return Deserialize(rawData: rawData, context: null);
+ }
+
+ public object? Deserialize(byte[] rawData, Type type)
+ {
+ return Deserialize(rawData: rawData, type, context: null);
+ }
+
+ public T Deserialize(Span rawData)
+ {
+ return Deserialize(rawData.ToArray().AsMemory(), context: null);
+ }
+
+ public object? Deserialize(Span rawData, Type type)
+ {
+ return Deserialize(rawData: rawData.ToArray(), type: type);
+ }
+
+ public T Cast(object nonCasted)
+ {
+ return Cast(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
+
+
+
+
+
diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs
index da1f1bb..25609fb 100644
--- a/mROA.Codegen/mROASourceGenerator.cs
+++ b/mROA.Codegen/mROASourceGenerator.cs
@@ -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;
-
-///
-/// 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.
-///
-[Generator]
-public class mROASourceGenerator : IIncrementalGenerator
+namespace mROA.Codegen
{
- private const string Namespace = "mROA.Implementation";
- private const string AttributeName = "SharedObjectInterafceAttribute";
-
- private const string AttributeSourceCode = $@"//
-
-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)));
- }
-
///
- /// 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.
///
- /// Syntax context, based on CreateSyntaxProvider predicate
- /// The specific cast and whether the attribute was found.
- private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen(
- GeneratorSyntaxContext context)
+ [Generator]
+ public class mROASourceGenerator : ISourceGenerator
{
- var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node;
+ private static Predicate 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 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);
- }
-
- ///
- /// Generate code action.
- /// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
- ///
- /// Source generation context used to add source files.
- /// Compilation used to provide access to the Semantic Model.
- /// Nodes annotated with the [Report] attribute that trigger the generate action.
- private void GenerateCode(SourceProductionContext context, Compilation compilation,
- ImmutableArray classes)
- {
- var methods = new List<(string, IMethodSymbol)>();
- var frontendContextRepo = new List();
- // 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().OrderBy(i => i.Name);
-
- var originalName = className;
- // Build up the source code
- className = className.TrimStart('I') + "RemoteEndpoint";
-
-
- var methodsText = new List();
-
- foreach (var method in methodBody)
+ var interfaces = new List();
+ 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")
- // {
- // 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(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 = $@"//
+ GenerateCode(context, context.Compilation, interfaces.ToImmutableArray());
+ }
+
+ private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
+ ImmutableArray 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();
+ var eventBinders = new List();
+ List totalMethods = new List();
+
+
+ List invokers = new List();
+ 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 innerMethods = new List();
+
+ 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().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();
+ 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 = $@"//
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 = @$"//
+ var coCodegenRepoCode = @$"//
using System.Collections.Generic;
using System.Reflection;
using mROA.Abstract;
-
-namespace mROA.Codegen;
-
-public class CoCodegenMethodRepository : IMethodRepository
-{{
- private readonly List _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 GetMethods()
- {{
- return _methods;
- }}
-
- public void Inject(T dependency)
- {{
- }}
-}}
-";
- context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
- }
-
- if (frontendContextRepo.Count != 0)
- {
- var fronendRepoCode = @$"//
-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 {{
- {string.Join(", \r\n\t\t", frontendContextRepo)}}}.ToFrozenDictionary();
+ public class CoCodegenMethodRepository : IMethodRepository
+ {{
+ private readonly List _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 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 = @$"//
+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 {{
+ {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 invokers,
+ List declaredMethods, GeneratorExecutionContext context, List binders)
+ {
+ var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers())
+ .OfType().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(events.Count);
+ var singleEventBinder = new List(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 declaredMethods, List invokers,
+ INamedTypeSymbol baseInterace)
+ {
+ var index = invokers.Count;
+ var sb = new StringBuilder();
+
+ bool isParametrized;
+
+ bool isAsync;
+ bool isVoid;
+
+ List? 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();
+ 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();
+
+ 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 invokers, INamedTypeSymbol baseType,
+ List 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 parts) => string.Join(", ", parts);
+
+ private void GenerateEventCode(IEventSymbol eventSymbol, List 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();
+
+ 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 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 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 CollectMembers(INamedTypeSymbol type)
+ {
+ var methods = type.GetMembers().OfType().ToList();
+ foreach (var inner in type.AllInterfaces)
+ {
+ methods.AddRange(inner.GetMembers().OfType());
+ }
+
+ methods.RemoveAll(m => m.Name == "Dispose");
+ return methods.OrderBy(i => i.Name).ToList();
+ }
}
}
\ No newline at end of file
diff --git a/mROA.Codegen/test.tpt b/mROA.Codegen/test.tpt
new file mode 100644
index 0000000..c53ad17
--- /dev/null
+++ b/mROA.Codegen/test.tpt
@@ -0,0 +1 @@
+test text
\ No newline at end of file
diff --git a/mROA.CodegenTools/mROA.CodegenTools.csproj b/mROA.CodegenTools/mROA.CodegenTools.csproj
new file mode 100644
index 0000000..d2a210c
--- /dev/null
+++ b/mROA.CodegenTools/mROA.CodegenTools.csproj
@@ -0,0 +1,7 @@
+
+
+
+ netstandard2.0
+
+
+
diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs
new file mode 100644
index 0000000..cfa7d20
--- /dev/null
+++ b/mROA.Test/CborTest.cs
@@ -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(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(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(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 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
+ }
+}
\ No newline at end of file
diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs
index 99025f3..8eaebb0 100644
--- a/mROA.Test/NextGenTest.cs
+++ b/mROA.Test/NextGenTest.cs
@@ -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() });
- }
- });
-
- var client = new TcpClient();
- client.Connect(IPAddress.Loopback, 4567);
- _interactionModuleA.BaseStream = client.GetStream();
+ _listener = new TcpListener(IPAddress.Loopback, 4567);
+ _interactionModuleA = new NextGenerationInteractionModule();
+ _interactionModuleA.Inject(new JsonSerializationToolkit());
+ _interactionModuleB = new NextGenerationInteractionModule();
+ _interactionModuleB.Inject(new JsonSerializationToolkit());
- var tasks = guids.Select(ReadStream);
-
- Task.WaitAll(tasks.ToArray());
- Assert.Pass();
-
- }
-
- private async Task ReadStream(Guid current)
- {
- var msg = await _interactionModuleA.GetNextMessageReceiving();
- Console.WriteLine(
- $"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
- while (msg.Id != current)
- {
- msg = await _interactionModuleA.GetNextMessageReceiving();
- Console.WriteLine(
- $"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
}
- Console.WriteLine($"{Environment.CurrentManagedThreadId} Good message received");
- }
+ [Test]
+ public void MultithreadedTest()
+ {
+
+ Task.Run(() =>
+ {
+ _listener.Start();
+ _interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream();
- [TearDown]
- public void TearDown()
- {
- _listener.Dispose();
+ 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();
+ }
}
}
\ No newline at end of file
diff --git a/mROA.Test/UnSOization.cs b/mROA.Test/UnSOization.cs
new file mode 100644
index 0000000..d30c025
--- /dev/null
+++ b/mROA.Test/UnSOization.cs
@@ -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));
+ }
+}
\ No newline at end of file
diff --git a/mROA.Test/mROA.Test.csproj b/mROA.Test/mROA.Test.csproj
index 4262b31..bff76ec 100644
--- a/mROA.Test/mROA.Test.csproj
+++ b/mROA.Test/mROA.Test.csproj
@@ -3,7 +3,7 @@
net9.0
latest
- enable
+
enable
false
@@ -27,6 +27,7 @@
+
diff --git a/mROA.sln b/mROA.sln
index 7586eb3..6ca35dc 100644
--- a/mROA.sln
+++ b/mROA.sln
@@ -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
diff --git a/mROA/Abstract/ICancellationRepository.cs b/mROA/Abstract/ICancellationRepository.cs
new file mode 100644
index 0000000..489a648
--- /dev/null
+++ b/mROA/Abstract/ICancellationRepository.cs
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/ICommandExecution.cs b/mROA/Abstract/ICommandExecution.cs
index 4566f1d..5037a4e 100644
--- a/mROA/Abstract/ICommandExecution.cs
+++ b/mROA/Abstract/ICommandExecution.cs
@@ -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; }
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IConnectionHub.cs b/mROA/Abstract/IConnectionHub.cs
index 1a595c8..34106f3 100644
--- a/mROA/Abstract/IConnectionHub.cs
+++ b/mROA/Abstract/IConnectionHub.cs
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs
index 6829405..920a317 100644
--- a/mROA/Abstract/IContextRepository.cs
+++ b/mROA/Abstract/IContextRepository.cs
@@ -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(int id);
- T GetSingleObject();
- object GetSingleObject(Type type);
- int GetObjectIndex(object o);
+ public interface IContextRepository : IInjectableModule
+ {
+ int HostId { get; set; }
+ int ResisterObject(object o, IEndPointContext context);
+ void ClearObject(ComplexObjectIdentifier id);
+ T GetObject(ComplexObjectIdentifier id);
+ object GetSingleObject(Type type, int ownerId);
+ int GetObjectIndex(object o, IEndPointContext context);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IContextRepositoryHub.cs b/mROA/Abstract/IContextRepositoryHub.cs
index 8a34bf2..f950b8f 100644
--- a/mROA/Abstract/IContextRepositoryHub.cs
+++ b/mROA/Abstract/IContextRepositoryHub.cs
@@ -1,6 +1,7 @@
-namespace mROA.Abstract;
-
-public interface IContextRepositoryHub
+namespace mROA.Abstract
{
- IContextRepository GetRepository(int clientId);
+ public interface IContextRepositoryHub
+ {
+ IContextRepository GetRepository(int clientId);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs
new file mode 100644
index 0000000..0267321
--- /dev/null
+++ b/mROA/Abstract/IEndPointContext.cs
@@ -0,0 +1,10 @@
+namespace mROA.Abstract
+{
+ public interface IEndPointContext
+ {
+ IContextRepository RealRepository { get; }
+ IContextRepository RemoteRepository { get; }
+ int HostId { get; }
+ int OwnerId { get; }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IEventBinder.cs b/mROA/Abstract/IEventBinder.cs
new file mode 100644
index 0000000..737bfd2
--- /dev/null
+++ b/mROA/Abstract/IEventBinder.cs
@@ -0,0 +1,8 @@
+namespace mROA.Abstract
+{
+ public interface IEventBinder
+ {
+ public void BindEvents(T source, IEndPointContext context,
+ IRepresentationModuleProducer representationModuleProducer, int index);
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs
index 7a9b0a1..3ae2d13 100644
--- a/mROA/Abstract/IExecuteModule.cs
+++ b/mROA/Abstract/IExecuteModule.cs
@@ -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);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IFrontendBridge.cs b/mROA/Abstract/IFrontendBridge.cs
index 103fec2..909f486 100644
--- a/mROA/Abstract/IFrontendBridge.cs
+++ b/mROA/Abstract/IFrontendBridge.cs
@@ -1,3 +1,6 @@
-namespace mROA.Abstract;
-
-public interface IFrontendBridge : IInjectableModule;
\ No newline at end of file
+namespace mROA.Abstract
+{
+ public interface IFrontendBridge : IInjectableModule
+ {
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IGatewayModule.cs b/mROA/Abstract/IGatewayModule.cs
index d51063a..77c869f 100644
--- a/mROA/Abstract/IGatewayModule.cs
+++ b/mROA/Abstract/IGatewayModule.cs
@@ -1,6 +1,9 @@
-namespace mROA.Abstract;
+using System;
-public interface IGatewayModule : IDisposable, IInjectableModule
-{
- void Run();
+namespace mROA.Abstract
+{
+ public interface IGatewayModule : IDisposable, IInjectableModule
+ {
+ void Run();
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IIdentityGenerator.cs b/mROA/Abstract/IIdentityGenerator.cs
index bede9f3..6123cdd 100644
--- a/mROA/Abstract/IIdentityGenerator.cs
+++ b/mROA/Abstract/IIdentityGenerator.cs
@@ -1,6 +1,7 @@
-namespace mROA.Abstract;
-
-public interface IIdentityGenerator : IInjectableModule
+namespace mROA.Abstract
{
- int GetNextIdentity();
+ public interface IIdentityGenerator : IInjectableModule
+ {
+ int GetNextIdentity();
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IInjectableModule.cs b/mROA/Abstract/IInjectableModule.cs
index d7da7cb..c516a6f 100644
--- a/mROA/Abstract/IInjectableModule.cs
+++ b/mROA/Abstract/IInjectableModule.cs
@@ -1,6 +1,7 @@
-namespace mROA.Abstract;
-
-public interface IInjectableModule
+namespace mROA.Abstract
{
- void Inject(T dependency);
+ public interface IInjectableModule
+ {
+ void Inject(T dependency);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs
index 9068ba1..dc45dbf 100644
--- a/mROA/Abstract/IInteractionModule.cs
+++ b/mROA/Abstract/IInteractionModule.cs
@@ -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 GetNextMessageReceiving();
- Task PostMessage(NetworkMessage message);
- void HandleMessage(NetworkMessage message);
- NetworkMessage? FirstByFilter(Predicate predicate);
+ public interface INextGenerationInteractionModule : IInjectableModule
+ {
+ int ConnectionId { get; }
+ public Stream? BaseStream { get; set; }
+ Task GetNextMessageReceiving();
+ Task PostMessage(NetworkMessage message);
+ void HandleMessage(NetworkMessage message);
+ NetworkMessage[] UnhandledMessages { get; }
+ NetworkMessage? FirstByFilter(Predicate predicate);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs
new file mode 100644
index 0000000..dcb04db
--- /dev/null
+++ b/mROA/Abstract/IMethodInvoker.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace mROA.Abstract
+{
+ public interface IMethodInvoker
+ {
+ bool IsVoid { get; }
+ Type[] ParameterTypes { get; }
+ Type? ReturnType { get; }
+ Type SuitableType { get; }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs
index d18405c..4c468f1 100644
--- a/mROA/Abstract/IMethodRepository.cs
+++ b/mROA/Abstract/IMethodRepository.cs
@@ -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 GetMethods();
+ public interface IMethodRepository : IInjectableModule
+ {
+ IMethodInvoker GetMethod(int id);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IOwnershipRepository.cs b/mROA/Abstract/IOwnershipRepository.cs
index deccfe9..55ec3f3 100644
--- a/mROA/Abstract/IOwnershipRepository.cs
+++ b/mROA/Abstract/IOwnershipRepository.cs
@@ -1,7 +1,8 @@
-namespace mROA.Abstract;
-
-public interface IOwnershipRepository
+namespace mROA.Abstract
{
- int GetOwnershipId();
- int GetHostOwnershipId();
+ public interface IOwnershipRepository
+ {
+ int GetOwnershipId();
+ int GetHostOwnershipId();
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IRemoteObjectFactory.cs b/mROA/Abstract/IRemoteObjectFactory.cs
new file mode 100644
index 0000000..e68fb0f
--- /dev/null
+++ b/mROA/Abstract/IRemoteObjectFactory.cs
@@ -0,0 +1,9 @@
+using mROA.Implementation;
+
+namespace mROA.Abstract
+{
+ public interface IRemoteObjectFactory : IInjectableModule
+ {
+ T Produce(ComplexObjectIdentifier id);
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IRepresentationModuleProducer.cs b/mROA/Abstract/IRepresentationModuleProducer.cs
index 9162a5c..6406c78 100644
--- a/mROA/Abstract/IRepresentationModuleProducer.cs
+++ b/mROA/Abstract/IRepresentationModuleProducer.cs
@@ -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);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IRequestExtractor.cs b/mROA/Abstract/IRequestExtractor.cs
index eaf59de..d49194b 100644
--- a/mROA/Abstract/IRequestExtractor.cs
+++ b/mROA/Abstract/IRequestExtractor.cs
@@ -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();
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/ISerialisationModule.cs
index f83f40b..17e7911 100644
--- a/mROA/Abstract/ISerialisationModule.cs
+++ b/mROA/Abstract/ISerialisationModule.cs
@@ -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 GetNextCommandExecution(Guid requestId) where T : ICommandExecution;
- Task> GetFinalCommandExecution(Guid requestId);
- void PostCallRequest(ICallRequest callRequest);
- }
-}
+ int Id { get; }
-public interface IRepresentationModule : IInjectableModule
-{
- int Id { get; }
- Task GetMessageAsync(Guid? requestId = null, EMessageType? messageType = null, CancellationToken token = default);
- T GetMessage(Guid? requestId = null, EMessageType? messageType = null);
- T GetMessage(Predicate filter);
- Task GetRawMessage(Predicate filter, CancellationToken token = default);
-
- Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull;
- Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType);
- void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull;
- void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType);
+ Task GetMessageAsync(Guid? requestId = null, MessageType? messageType = null,
+ CancellationToken token = default);
+
+ T GetMessage(Guid? requestId = null, MessageType? messageType = null);
+
+ Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null,
+ CancellationToken token = default);
+
+ Task PostCallMessageAsync(Guid id, MessageType messageType, T payload) where T : notnull;
+ Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType);
+ void PostCallMessage(Guid id, MessageType messageType, T payload) where T : notnull;
+ void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs
index 769180a..497c953 100644
--- a/mROA/Abstract/ISerializationToolkit.cs
+++ b/mROA/Abstract/ISerializationToolkit.cs
@@ -1,14 +1,16 @@
-namespace mROA.Abstract;
+using System;
-public interface ISerializationToolkit : IInjectableModule
+namespace mROA.Abstract
{
- byte[] Serialize(T objectToSerialize);
- byte[] Serialize(object objectToSerialize, Type type);
- T? Deserialize(byte[] rawData);
- object? Deserialize(byte[] rawData, Type type);
- T? Deserialize(Span rawData);
- object? Deserialize(Span rawData, Type type);
- T Cast(object nonCasted);
- object Cast(object nonCasted, Type type);
-
+ public interface ISerializationToolkit : IInjectableModule
+ {
+ byte[] Serialize(T objectToSerialize);
+ byte[] Serialize(object objectToSerialize, Type type);
+ T? Deserialize(byte[] rawData);
+ object? Deserialize(byte[] rawData, Type type);
+ T? Deserialize(Span rawData);
+ object? Deserialize(Span rawData, Type type);
+ T? Cast(object? nonCasted);
+ object? Cast(object? nonCasted, Type type);
+ }
}
\ No newline at end of file
diff --git a/mROA/Abstract/IShared.cs b/mROA/Abstract/IShared.cs
new file mode 100644
index 0000000..6758159
--- /dev/null
+++ b/mROA/Abstract/IShared.cs
@@ -0,0 +1,7 @@
+namespace mROA.Implementation
+{
+#pragma warning disable CS8618, CS9264
+ public interface IShared
+ {
+ }
+}
\ No newline at end of file
diff --git a/mROA/Abstract/IStorage.cs b/mROA/Abstract/IStorage.cs
new file mode 100644
index 0000000..88432a8
--- /dev/null
+++ b/mROA/Abstract/IStorage.cs
@@ -0,0 +1,10 @@
+namespace mROA.Abstract
+{
+ public interface IStorage where T : class
+ {
+ T? GetValue(int index);
+ int GetIndex(T value);
+ int Place(T value);
+ void Free(int index);
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs
new file mode 100644
index 0000000..cd32ca7
--- /dev/null
+++ b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs
@@ -0,0 +1,8 @@
+using System;
+
+namespace mROA.Implementation.Attributes
+{
+ public class SerializationIgnoreAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs b/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs
index 78bfa15..adcc66e 100644
--- a/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs
+++ b/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs
@@ -1,3 +1,8 @@
-namespace mROA.Implementation.Attributes;
+using System;
-public class SharedObjectInterfaceAttribute : Attribute;
\ No newline at end of file
+namespace mROA.Implementation.Attributes
+{
+ public class SharedObjectInterfaceAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs b/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs
index f0439f5..ec2f228 100644
--- a/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs
+++ b/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs
@@ -1,3 +1,8 @@
-namespace mROA.Implementation.Attributes;
+using System;
-public class SharedObjectSingletonAttribute : Attribute;
\ No newline at end of file
+namespace mROA.Implementation.Attributes
+{
+ public class SharedObjectSingletonAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/BackendIdentityGenerator.cs b/mROA/Implementation/Backend/BackendIdentityGenerator.cs
index 82dd4e2..dce88be 100644
--- a/mROA/Implementation/Backend/BackendIdentityGenerator.cs
+++ b/mROA/Implementation/Backend/BackendIdentityGenerator.cs
@@ -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()
- {
- return ++_currentId;
- }
-
- public void Inject(T dependency)
+ public class BackendIdentityGenerator : IIdentityGenerator
{
+ private int _currentId;
+
+ public int GetNextIdentity()
+ {
+ return ++_currentId;
+ }
+
+ public void Inject(T dependency)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs
index 1fbdbf3..b8e0f7c 100644
--- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs
+++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs
@@ -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);
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs
index ac64004..25b96c1 100644
--- a/mROA/Implementation/Backend/BasicExecutionModule.cs
+++ b/mROA/Implementation/Backend/BasicExecutionModule.cs
@@ -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 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 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(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
+ {
+ 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
+ {
+ 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()
+ };
+ }
}
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/ConnectionHub.cs b/mROA/Implementation/Backend/ConnectionHub.cs
index e2c0c18..f26a304 100644
--- a/mROA/Implementation/Backend/ConnectionHub.cs
+++ b/mROA/Implementation/Backend/ConnectionHub.cs
@@ -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 _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");
-
- _connections.Add(interaction.ConnectionId, interaction);
- var module = new RepresentationModule();
- module.Inject(_serializationToolkit);
- module.Inject(interaction);
- OnConnected?.Invoke(module);
- }
+ private readonly Dictionary _connections = new();
+ private ISerializationToolkit? _serializationToolkit;
- public INextGenerationInteractionModule GetInteracion(int id)
- {
- return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
- }
+ public void RegisterInteraction(INextGenerationInteractionModule interaction)
+ {
+ if (_serializationToolkit is null)
+ throw new NullReferenceException("Serialization toolkit is null");
- public event ConnectionHandler? OnConnected;
- public event DisconnectionHandler? OnDisconnected;
- public void Inject(T dependency)
- {
- if (dependency is ISerializationToolkit serializationToolkit)
- _serializationToolkit = serializationToolkit;
-
+ _connections.Add(interaction.ConnectionId, interaction);
+ var module = new RepresentationModule();
+ module.Inject(_serializationToolkit);
+ module.Inject(interaction);
+ OnConnected?.Invoke(module);
+ }
+
+ 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 dependency)
+ {
+ if (dependency is ISerializationToolkit serializationToolkit)
+ _serializationToolkit = serializationToolkit;
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs
index 6a3fe1e..71ee389 100644
--- a/mROA/Implementation/Backend/ContextRepository.cs
+++ b/mROA/Implementation/Backend/ContextRepository.cs
@@ -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? _singletons;
- private object?[] _storage = new object[StartupSize];
-
- private Task _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 _lastIndexFinder = Task.FromResult(0);
- var last = _lastIndexFinder.Result;
- _lastIndexFinder = Task.Run(FindLastIndex);
+ private IRepresentationModuleProducer? _representationModuleProducer;
- return last;
- }
+ // [CanBeNull]
+ private Dictionary _singletons;
+ private IStorage _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(int id)
- {
- return id == -1 || _storage.Length <= id
- ? throw new NullReferenceException("Cannot find that object. It is null")
- : (T)_storage[id]!;
- }
-
- public T GetSingleObject()
- {
- 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();
}
- 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 dependency)
- {
+ public int ResisterObject(object o, IEndPointContext context)
+ {
+ var last = _storage.Place(o);
+
+ EventBinders.OfType>().FirstOrDefault()
+ ?.BindEvents((T)o, context, _representationModuleProducer!, last);
+
+ return last;
+ }
+
+ public void ClearObject(ComplexObjectIdentifier id)
+ {
+ _storage.Free(id.ContextId);
+ }
+
+ public T GetObject(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(object o, IEndPointContext context)
+ {
+ var index = _storage.GetIndex(o);
+ return index == -1 ? ResisterObject(o, context) : index;
+ }
+
+ public void Inject(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);
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs
index ae29e29..6529c6c 100644
--- a/mROA/Implementation/Backend/HubRequestExtractor.cs
+++ b/mROA/Implementation/Backend/HubRequestExtractor.cs
@@ -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 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 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();
- }
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/JsonSerialisationModule.cs b/mROA/Implementation/Backend/JsonSerialisationModule.cs
deleted file mode 100644
index 557331a..0000000
--- a/mROA/Implementation/Backend/JsonSerialisationModule.cs
+++ /dev/null
@@ -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(message)!;
-// Console.WriteLine(Encoding.Default.GetString(input.Data));
-// if (input.SchemaId == MessageType.CallRequest)
-// {
-// var command = JsonSerializer.Deserialize(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 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;
-// }
-// }
-// }
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs
index ff9da0e..065c746 100644
--- a/mROA/Implementation/Backend/MultiClientContextRepository.cs
+++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs
@@ -1,62 +1,69 @@
+using System;
+using System.Collections.Generic;
using mROA.Abstract;
-namespace mROA.Implementation.Backend;
-
-public class MultiClientContextRepository(Func produceRepository) : IContextRepository, IContextRepositoryHub
+namespace mROA.Implementation.Backend
{
- private Dictionary _repositories = new();
-
- private IContextRepository GetRepositoryByClientId(int clientId)
+ public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub
{
- if (_repositories.TryGetValue(clientId, out var repository))
+ private readonly Func _produceRepository;
+ private readonly Dictionary _repositories = new();
+
+ public MultiClientContextRepository(Func produceRepository)
+ {
+ _produceRepository = produceRepository;
+ }
+
+ public void Inject(T dependency)
+ {
+ }
+
+ public int HostId { get; set; }
+
+ public int ResisterObject(object o, IEndPointContext context)
+ {
+ var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ return repository.ResisterObject(o, context);
+ }
+
+ public void ClearObject(ComplexObjectIdentifier id)
+ {
+ var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ repository.ClearObject(id);
+ }
+
+ public T GetObject(ComplexObjectIdentifier id)
+ {
+ var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ return repository.GetObject(id);
+ }
+
+ public object GetSingleObject(Type type, int ownerId)
+ {
+ var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ return repository.GetSingleObject(type, ownerId);
+ }
+
+ public int GetObjectIndex(object o, IEndPointContext context)
+ {
+ var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ return repository.GetObjectIndex(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 dependency)
- {
- }
+ }
- public int ResisterObject(object o)
- {
- return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o);
- }
+ private IContextRepository GetRepositoryByClientId(int clientId)
+ {
+ if (_repositories.TryGetValue(clientId, out var repository))
+ return repository;
- 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(int id)
- {
- return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id);
- }
-
- public T GetSingleObject()
- {
- 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;
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs
index 93f8aa8..56cd389 100644
--- a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs
+++ b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs
@@ -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 _ownerships = new();
-
- public int GetOwnershipId()
+ public class MultiClientOwnershipRepository : IOwnershipRepository
{
- return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
- }
+ private Dictionary _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);
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs
index 45ac183..d7bf45d 100644
--- a/mROA/Implementation/Backend/NetworkGatewayModule.cs
+++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs
@@ -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 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 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");
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Backend/StreamBasedInteractionModule.cs b/mROA/Implementation/Backend/StreamBasedInteractionModule.cs
deleted file mode 100644
index 0427209..0000000
--- a/mROA/Implementation/Backend/StreamBasedInteractionModule.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-// using mROA.Abstract;
-//
-// namespace mROA.Implementation.Backend;
-//
-// public class StreamBasedInteractionModule : IInteractionModule
-// {
-// internal ISerialisationModule _serialisationModule;
-// private readonly Dictionary _streams = new();
-// internal Action? _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 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 dependency)
-// {
-// if (dependency is ISerialisationModule serialisationModule)
-// {
-// _handler = serialisationModule.HandleIncomingRequest;
-// _serialisationModule = serialisationModule;
-// }
-// }
-//
-// }
\ No newline at end of file
diff --git a/mROA/Implementation/Bootstrap/FullMixBuilder.cs b/mROA/Implementation/Bootstrap/FullMixBuilder.cs
index 848480d..3b7a9ae 100644
--- a/mROA/Implementation/Bootstrap/FullMixBuilder.cs
+++ b/mROA/Implementation/Bootstrap/FullMixBuilder.cs
@@ -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 Modules { get; } = [];
-
- public void Build()
+ public class FullMixBuilder
{
- foreach (var module in Modules)
- foreach (var injection in Modules)
- module.Inject(injection);
- }
+ public List Modules { get; } = new() { };
- public T? GetModule()
- {
- return Modules.OfType().FirstOrDefault();
+ public void Build()
+ {
+ foreach (var module in Modules)
+ foreach (var injection in Modules)
+ module.Inject(injection);
+ }
+
+ public T? GetModule()
+ {
+ return Modules.OfType().FirstOrDefault();
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs
index 1709ba7..6a909b0 100644
--- a/mROA/Implementation/CallRequest.cs
+++ b/mROA/Implementation/CallRequest.cs
@@ -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;
-
- [JsonIgnore]
- public Type? ParameterType { get; init; }
- public object? Parameter { get; set; }
+ public class DefaultCallRequest : ICallRequest
+ {
+ public Guid Id { get; set; } = Guid.NewGuid();
+ public int CommandId { get; set; }
+ public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null;
+
+ 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} }}";
+ }
+ }
}
\ No newline at end of file
diff --git a/mROA/Implementation/CancellationRepository.cs b/mROA/Implementation/CancellationRepository.cs
new file mode 100644
index 0000000..d6543aa
--- /dev/null
+++ b/mROA/Implementation/CancellationRepository.cs
@@ -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 _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 dependency)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs
new file mode 100644
index 0000000..7dea41d
--- /dev/null
+++ b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs
@@ -0,0 +1,10 @@
+using System;
+using mROA.Abstract;
+
+namespace mROA.Implementation.CommandExecution
+{
+ public class AsyncCommandExecution : ICommandExecution
+ {
+ public Guid Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs
index 772fa05..82a63de 100644
--- a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs
+++ b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs
@@ -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 };
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs
index 5069911..fba0dca 100644
--- a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs
+++ b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs
@@ -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 : FinalCommandExecution
-{
- public T? Result { get; init; }
+ public class FinalCommandExecution : FinalCommandExecution
+ {
+ public T? Result { get; set; }
+ }
}
\ No newline at end of file
diff --git a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs b/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs
deleted file mode 100644
index 813accc..0000000
--- a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Text.Json.Serialization;
-
-namespace mROA.Implementation.CommandExecution;
-
-public class TypedFinalCommandExecution : FinalCommandExecution
-{
- [JsonIgnore]
- // ReSharper disable once UnusedAutoPropertyAccessor.Global
- public Type? Type { get; set; }
-}
\ No newline at end of file
diff --git a/mROA/Implementation/ComplexContextRepository.cs b/mROA/Implementation/ComplexContextRepository.cs
new file mode 100644
index 0000000..8f44c78
--- /dev/null
+++ b/mROA/Implementation/ComplexContextRepository.cs
@@ -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>> _storages = new();
+ public static object[] EventBinders = { };
+
+ private IRemoteObjectFactory? _remoteObjectFactory;
+ private IRepresentationModuleProducer? _representationModuleProducer;
+
+ public void Inject(T dependency)
+ {
+ if (dependency is IRemoteObjectFactory remoteObjectFactory)
+ {
+ _remoteObjectFactory = remoteObjectFactory;
+ }
+
+ if (dependency is IRepresentationModuleProducer moduleProducer)
+ {
+ _representationModuleProducer = moduleProducer;
+ }
+ }
+
+ public int HostId { get; set; }
+
+ public int ResisterObject(object o, IEndPointContext context)
+ {
+ var storageIndex = _storages.FindIndex(i => i.Key == context.OwnerId);
+ if (storageIndex == -1)
+ {
+ _storages.Add(
+ new KeyValuePair>(context.OwnerId, new ExtensibleStorage()));
+ storageIndex = _storages.Count - 1;
+ }
+
+ var storage = _storages[storageIndex].Value;
+
+ var placedIndex = storage.Place(o);
+ EventBinders.OfType>().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(ComplexObjectIdentifier id)
+ {
+ throw new NotImplementedException();
+ }
+
+ public object GetSingleObject(Type type, int ownerId)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetObjectIndex(object o, IEndPointContext context)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs
new file mode 100644
index 0000000..d95d378
--- /dev/null
+++ b/mROA/Implementation/ComplexObjectIdentifier.cs
@@ -0,0 +1,58 @@
+using System;
+
+namespace mROA.Implementation
+{
+#pragma warning disable CS8618, CS9264
+ public struct ComplexObjectIdentifier : IEquatable
+ {
+ 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);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs
index 0b79371..0e21899 100644
--- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs
+++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs
@@ -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 dependency)
- {
- if (dependency is IConnectionHub interactionModule)
- _hub = interactionModule;
- }
+ public void Inject(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);
-
- produced.Inject(_hub.GetInteracion(id));
-
- return produced;
+ foreach (var creationModule in _creationModules)
+ produced.Inject(creationModule);
+
+ var interaction = _hub.GetInteracion(id);
+ produced.Inject(interaction);
+
+ return produced;
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs
new file mode 100644
index 0000000..e6351e9
--- /dev/null
+++ b/mROA/Implementation/EndPointContext.cs
@@ -0,0 +1,20 @@
+using System;
+using mROA.Abstract;
+
+namespace mROA.Implementation
+{
+ public class EndPointContext : IEndPointContext
+ {
+ public Func 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; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/EventBinder.cs b/mROA/Implementation/EventBinder.cs
new file mode 100644
index 0000000..8354c4f
--- /dev/null
+++ b/mROA/Implementation/EventBinder.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace mROA.Abstract
+{
+ public class EventBinder : IEventBinder
+ {
+ public Action BindAction { get; set; }
+
+ public void BindEvents(T source, IEndPointContext context,
+ IRepresentationModuleProducer representationModuleProducer, int index)
+ {
+ BindAction(source, context, representationModuleProducer, index);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/ExtensibleStorage.cs b/mROA/Implementation/ExtensibleStorage.cs
new file mode 100644
index 0000000..6543519
--- /dev/null
+++ b/mROA/Implementation/ExtensibleStorage.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using mROA.Abstract;
+
+namespace mROA.Implementation
+{
+ public class ExtensibleStorage : IStorage where T : class
+ {
+ private const int StartupSize = 1024;
+ private const int GrowSize = 128;
+ private T?[] _array = new T?[StartupSize];
+ private readonly LinkedList _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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs
deleted file mode 100644
index dce21a4..0000000
--- a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs
+++ /dev/null
@@ -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 GetNextCommandExecution(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(receiveMessage)!;
-//
-// while (message.Id != requestId)
-// {
-// receiveMessage = await _interactionModule.ReceiveMessage();
-// message = JsonSerializer.Deserialize(receiveMessage)!;
-// }
-//
-// var parsed = JsonSerializer.Deserialize(message.Data)!;
-//
-// if (message.SchemaId == MessageType.ErrorCommandExecution)
-// {
-// throw new RemoteException(JsonSerializer.Deserialize(message.Data)!.Exception)
-// { CallRequestId = requestId };
-// }
-//
-// return parsed;
-// }
-//
-// public async Task> GetFinalCommandExecution(Guid requestId)
-// {
-// if (_interactionModule is null)
-// throw new Exception("Interaction module not initialized");
-//
-// var receiveMessage = await _interactionModule.ReceiveMessage();
-//
-// var message = JsonSerializer.Deserialize(receiveMessage)!;
-// while (message.Id != requestId)
-// {
-// receiveMessage = await _interactionModule.ReceiveMessage();
-//
-// message = JsonSerializer.Deserialize(receiveMessage)!;
-// }
-//
-// if (message.SchemaId == MessageType.ErrorCommandExecution)
-// {
-// throw new RemoteException(JsonSerializer.Deserialize(message.Data)!.Exception)
-// { CallRequestId = requestId };
-// }
-//
-// return JsonSerializer.Deserialize>(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 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}";
-}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs
index 9aa3b0c..8bd0aba 100644
--- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs
+++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs
@@ -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 dependency)
+ public class NetworkFrontendBridge : IFrontendBridge
{
- switch (dependency)
- {
- case NextGenerationInteractionModule interactionModule:
- _interactionModule = interactionModule;
- break;
- case ISerializationToolkit toolkit:
- _serialization = toolkit;
- break;
- }
- }
+ private readonly IPEndPoint _ipEndPoint;
+ private readonly TcpClient _tcpClient = new();
+ private NextGenerationInteractionModule? _interactionModule;
+ private ISerializationToolkit? _serialization;
- 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 NetworkFrontendBridge(IPEndPoint ipEndPoint)
{
- throw new Exception($"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.MessageType.ToString()}");
+ _ipEndPoint = ipEndPoint;
+ }
+
+ public void Inject(T dependency)
+ {
+ switch (dependency)
+ {
+ case NextGenerationInteractionModule interactionModule:
+ _interactionModule = interactionModule;
+ break;
+ case ISerializationToolkit toolkit:
+ _serialization = toolkit;
+ break;
+ }
+ }
+
+ public void Connect()
+ {
+ if (_interactionModule is null)
+ throw new Exception("Interaction module was not injected");
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is not initialized");
+
+ _tcpClient.Connect(_ipEndPoint);
+ _interactionModule.BaseStream = _tcpClient.GetStream();
+ var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
+ if (welcomeMessage.SchemaId != MessageType.IdAssigning)
+ {
+ throw new Exception(
+ $"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.SchemaId.ToString()}");
+ }
+
+
+ var assignment = _serialization.Deserialize(welcomeMessage.Data)!;
+ _interactionModule.ConnectionId = -assignment.Id;
+ TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id);
}
- _interactionModule.HandleMessage(welcomeMessage);
- TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize(welcomeMessage.Data)!.Id);
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/RemoteException.cs b/mROA/Implementation/Frontend/RemoteException.cs
new file mode 100644
index 0000000..e63e8b3
--- /dev/null
+++ b/mROA/Implementation/Frontend/RemoteException.cs
@@ -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}";
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs
index 6a6e52f..0cc961a 100644
--- a/mROA/Implementation/Frontend/RequestExtractor.cs
+++ b/mROA/Implementation/Frontend/RequestExtractor.cs
@@ -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 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 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(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(
+ messageType: MessageType.CallRequest, token: token);
+ var cancelRequest =
+ _representationModule!.GetMessageAsync(
+ messageType: MessageType.CancelRequest, token: token);
+ var eventRequest =
+ _representationModule!.GetMessageAsync(
+ 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!);
}
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/StaticOwnershipRepository.cs b/mROA/Implementation/Frontend/StaticOwnershipRepository.cs
index bbc0d9b..1739824 100644
--- a/mROA/Implementation/Frontend/StaticOwnershipRepository.cs
+++ b/mROA/Implementation/Frontend/StaticOwnershipRepository.cs
@@ -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;
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs b/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs
deleted file mode 100644
index a94a374..0000000
--- a/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs
+++ /dev/null
@@ -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();
-// }
-//
-// public NetworkMessage LastMessage()
-// {
-// return null;
-// }
-//
-//
-//
-// public async Task 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 dependency)
-// {
-// }
-// }
\ No newline at end of file
diff --git a/mROA/Implementation/IdAssignment.cs b/mROA/Implementation/IdAssignment.cs
new file mode 100644
index 0000000..427124b
--- /dev/null
+++ b/mROA/Implementation/IdAssignment.cs
@@ -0,0 +1,7 @@
+namespace mROA.Implementation
+{
+ public class IdAssignment
+ {
+ public int Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/IdAssingnment.cs b/mROA/Implementation/IdAssingnment.cs
deleted file mode 100644
index 5cdb944..0000000
--- a/mROA/Implementation/IdAssingnment.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace mROA.Implementation;
-
-public class IdAssingnment
-{
- public int Id { get; set; }
-}
\ No newline at end of file
diff --git a/mROA/Implementation/JsonSerializationToolkit.cs b/mROA/Implementation/JsonSerializationToolkit.cs
index 4cc0f75..61a3c7e 100644
--- a/mROA/Implementation/JsonSerializationToolkit.cs
+++ b/mROA/Implementation/JsonSerializationToolkit.cs
@@ -1,59 +1,61 @@
-using System.Text.Json;
+using System;
+using System.Text.Json;
using mROA.Abstract;
-namespace mROA.Implementation;
-
-public class JsonSerializationToolkit : ISerializationToolkit
+namespace mROA.Implementation
{
- public byte[] Serialize(T objectToSerialize)
+ public class JsonSerializationToolkit : ISerializationToolkit
{
- return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize);
- }
-
- public byte[] Serialize(object objectToSerialize, Type type)
- {
- return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type);
- }
-
- public T? Deserialize(byte[] rawData)
- {
- return JsonSerializer.Deserialize(rawData);
- }
-
- public object? Deserialize(byte[] rawData, Type type)
- {
- return JsonSerializer.Deserialize(rawData, type);
- }
-
- public T? Deserialize(Span rawData)
- {
- return JsonSerializer.Deserialize(rawData);
- }
-
- public object? Deserialize(Span rawData, Type type)
- {
- return JsonSerializer.Deserialize(rawData, type);
- }
-
- public T Cast(object nonCasted)
- {
- return nonCasted switch
+ public byte[] Serialize(T objectToSerialize)
{
- JsonElement jsonElement => jsonElement.Deserialize()!,
- T casted => casted,
- _ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName)
- };
- }
+ return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize);
+ }
- public object Cast(object nonCasted, Type type)
- {
- if (nonCasted is JsonElement jsonElement)
- return jsonElement.Deserialize(type)!;
+ public byte[] Serialize(object objectToSerialize, Type type)
+ {
+ return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type);
+ }
- throw new JsonException("Cannot cast object to type " + type.FullName);
- }
+ public T? Deserialize(byte[] rawData)
+ {
+ return JsonSerializer.Deserialize(rawData);
+ }
- public void Inject(T dependency)
- {
+ public object? Deserialize(byte[] rawData, Type type)
+ {
+ return JsonSerializer.Deserialize(rawData, type);
+ }
+
+ public T? Deserialize(Span rawData)
+ {
+ return JsonSerializer.Deserialize(rawData);
+ }
+
+ public object? Deserialize(Span rawData, Type type)
+ {
+ return JsonSerializer.Deserialize(rawData, type);
+ }
+
+ public T Cast(object nonCasted)
+ {
+ return nonCasted switch
+ {
+ JsonElement jsonElement => jsonElement.Deserialize()!,
+ T casted => casted,
+ _ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName)
+ };
+ }
+
+ public object Cast(object nonCasted, Type type)
+ {
+ if (nonCasted is JsonElement jsonElement)
+ return jsonElement.Deserialize(type)!;
+
+ throw new JsonException("Cannot cast object to type " + type.FullName);
+ }
+
+ public void Inject(T dependency)
+ {
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs
new file mode 100644
index 0000000..59efb7d
--- /dev/null
+++ b/mROA/Implementation/MethodInvoker.cs
@@ -0,0 +1,47 @@
+using System;
+using mROA.Abstract;
+
+namespace mROA.Implementation
+{
+ public class MethodInvoker : IMethodInvoker
+ {
+ public bool IsVoid { get; set; }
+ public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
+ public Type? ReturnType { get; set; }
+ public Func Invoking { get; set; } = (_, _, _) => null;
+
+ public object? Invoke(object instance, object?[]? parameters, object[] special)
+ {
+ return Invoking(instance, parameters, special);
+ }
+
+ public Type SuitableType { get; set; } = null!;
+
+ public static readonly IMethodInvoker Dispose = new MethodInvoker
+ {
+ IsVoid = true,
+ Invoking = (instance, _, _) =>
+ {
+ (instance as IDisposable)?.Dispose();
+ return null;
+ },
+ SuitableType = typeof(IDisposable)
+ };
+ }
+
+ public class AsyncMethodInvoker : IMethodInvoker
+ {
+ public bool IsVoid { get; set; }
+ public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
+ public Type? ReturnType { get; set; }
+ public Type SuitableType { get; set; }
+
+ public Action> Invoking { get; set; } =
+ (_, _, _, post) => { post.Invoke(null); };
+
+ public void Invoke(object instance, object?[]? parameters, object[] special, Action postInvokeAction)
+ {
+ Invoking(instance, parameters, special, postInvokeAction);
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/MethodRepository.cs b/mROA/Implementation/MethodRepository.cs
deleted file mode 100644
index d429229..0000000
--- a/mROA/Implementation/MethodRepository.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System.Reflection;
-using mROA.Abstract;
-using mROA.Implementation.Attributes;
-
-namespace mROA.Implementation;
-
-public class MethodRepository : IMethodRepository
-{
- private readonly List _methods = [];
-
- public MethodInfo GetMethod(int id)
- {
- if (_methods.Count <= id)
- throw new Exception("Method such registered method");
-
- return _methods[id];
- }
-
- public int RegisterMethod(MethodInfo method)
- {
- _methods.Add(method);
- return _methods.Count - 1;
- }
-
- public IEnumerable GetMethods()
- {
- return _methods;
- }
-
- public void CollectForAssembly(Assembly assembly)
- {
- var types = assembly.GetTypes().Where(i => i.IsInterface && i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0);
- foreach (var type in types)
- {
- foreach (var method in type.GetMethods())
- RegisterMethod(method);
- }
- }
- public void Inject(T dependency)
- {
-
- }
-}
\ No newline at end of file
diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs
index b6bb898..e610586 100644
--- a/mROA/Implementation/NetworkMessage.cs
+++ b/mROA/Implementation/NetworkMessage.cs
@@ -1,28 +1,28 @@
-using System.Text.Json.Serialization;
+using System;
+using System.Text.Json.Serialization;
// ReSharper disable UnusedMember.Global
-namespace mROA.Implementation;
-
-public sealed class NetworkMessage
+namespace mROA.Implementation
{
- public static readonly NetworkMessage Null = new() { MessageType = EMessageType.Unknown, Id = Guid.Empty, Data = [] };
- public Guid Id { get; init; }
- public EMessageType MessageType { get; init; }
- public required byte[] Data { get; init; }
- public bool IsValidMessage(Guid? requestId = null, EMessageType? messageType = null)
+ public class NetworkMessage
{
- return (requestId is null || Id == requestId) &&
- (messageType is null || MessageType == messageType);
- }
-}
+ public Guid Id { get; set; }
-public enum EMessageType
-{
- Unknown,
- FinishedCommandExecution,
- ExceptionCommandExecution,
- AsyncCancelCommandExecution,
- CallRequest,
- IdAssigning
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public MessageType SchemaId { get; set; }
+
+ public byte[] Data { get; set; }
+ }
+
+ public enum MessageType
+ {
+ Unknown,
+ FinishedCommandExecution,
+ ExceptionCommandExecution,
+ CallRequest,
+ IdAssigning,
+ CancelRequest,
+ EventRequest
+ }
}
\ No newline at end of file
diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs
index a02183c..2aa7163 100644
--- a/mROA/Implementation/NextGenerationInteractionModule.cs
+++ b/mROA/Implementation/NextGenerationInteractionModule.cs
@@ -1,115 +1,103 @@
-using mROA.Abstract;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using mROA.Abstract;
-namespace mROA.Implementation;
-
-public class NextGenerationInteractionModule : INextGenerationInteractionModule
+namespace mROA.Implementation
{
- private ISerializationToolkit? _serialization;
- public int ConnectionId { get; private set; }
- public Stream BaseStream { get; set; } = Stream.Null;
- private Task? _currentReceiving;
- private const int BufferSize = ushort.MaxValue;
- private readonly Memory _buffer = new byte[BufferSize];
- private readonly List _messageBuffer = new (128);
- public NetworkMessage[] UnhandledMessages => _messageBuffer.ToArray();
- public NetworkMessage LastMessage { get; private set; } = NetworkMessage.Null;
- public EventWaitHandle CurrentReceivingHandle { get; private set; } = new(true, EventResetMode.ManualReset);
-
- public void Inject(T dependency)
+ public class NextGenerationInteractionModule : INextGenerationInteractionModule
{
- switch (dependency)
+ private const int BufferSize = ushort.MaxValue;
+ private readonly Memory _buffer = new byte[BufferSize];
+ private readonly List _messageBuffer = new(128);
+ private Task? _currentReceiving;
+ private ISerializationToolkit? _serialization;
+ public int ConnectionId { get; set; }
+ public Stream? BaseStream { get; set; }
+
+
+ public void Inject(T dependency)
{
- case ISerializationToolkit toolkit:
- _serialization = toolkit;
- break;
- case IIdentityGenerator identityGenerator:
- ConnectionId = identityGenerator.GetNextIdentity();
- break;
- }
- }
-
-
- public async void StartInfiniteReceiving()
- {
- try
- {
- CurrentReceivingHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
-
- await Task.Yield();
- while (true)
+ switch (dependency)
{
- var message = ReceiveMessage();
- LastMessage = message;
- _messageBuffer.Add(message);
- CurrentReceivingHandle.Set();
- CurrentReceivingHandle = new EventWaitHandle(false, EventResetMode.ManualReset);
+ case ISerializationToolkit toolkit:
+ _serialization = toolkit;
+ break;
+ case IIdentityGenerator identityGenerator:
+ ConnectionId = identityGenerator.GetNextIdentity();
+ break;
}
}
- catch (Exception)
+
+ public Task GetNextMessageReceiving()
{
- // ignored
+ if (_currentReceiving != null) return _currentReceiving;
+ _currentReceiving = Task.Run(async () => await GetNextMessage());
+ return _currentReceiving;
+ }
+
+ public async Task PostMessage(NetworkMessage message)
+ {
+ if (BaseStream == null)
+ throw new NullReferenceException("BaseStream is null");
+
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is not initialized");
+
+ // Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message));
+
+
+ var rawMessage = _serialization.Serialize(message);
+ var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort));
+
+ await BaseStream.WriteAsync(header);
+ await BaseStream.WriteAsync(rawMessage);
+ }
+
+ public void HandleMessage(NetworkMessage message)
+ {
+ _messageBuffer.Remove(message);
+ }
+
+ public NetworkMessage[] UnhandledMessages => _messageBuffer.ToArray();
+
+ public NetworkMessage? FirstByFilter(Predicate predicate)
+ {
+ return _messageBuffer.FirstOrDefault(m => predicate(m));
+ }
+
+ private async Task GetNextMessage()
+ {
+ if (BaseStream == null)
+ throw new NullReferenceException("BaseStream is null");
+
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is null");
+
+
+ // Console.WriteLine("Receiving message");
+ var firstBit = (byte)BaseStream.ReadByte();
+ var secondBit = (byte)BaseStream.ReadByte();
+
+ var len = BitConverter.ToUInt16(new[] { firstBit, secondBit });
+ var localSpan = _buffer[..len];
+
+ await BaseStream.ReadExactlyAsync(localSpan);
+
+ // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len]));
+
+ var message = _serialization.Deserialize(localSpan.Span);
+#if TRACE
+ Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.SchemaId}");
+ TransmissionConfig.TotalTransmittedBytes += len;
+ Console.WriteLine($"Total recieced bytes are {TransmissionConfig.TotalTransmittedBytes}");
+#endif
+ _messageBuffer.Add(message);
+ _currentReceiving = Task.Run(async () => await GetNextMessage());
+
+ return message;
}
}
-
-
-
- public Task GetNextMessageReceiving()
- {
- if (_currentReceiving != null) return _currentReceiving;
- _currentReceiving = Task.Run(GetNextMessage);
- return _currentReceiving;
-
- }
-
- public async Task PostMessage(NetworkMessage message)
- {
- if (BaseStream == null)
- throw new NullReferenceException("BaseStream is null");
-
- if (_serialization == null)
- throw new NullReferenceException("Serialization toolkit is not initialized");
-
- // Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message));
-
-
- var rawMessage = _serialization.Serialize(message);
- await BaseStream.WriteAsync(BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)));
- await BaseStream.WriteAsync(rawMessage);
- }
-
- public void HandleMessage(NetworkMessage message)
- {
- _messageBuffer.Remove(message);
- }
-
- public NetworkMessage FirstByFilter(Predicate predicate)
- {
- return _messageBuffer.FirstOrDefault(m => predicate(m)) ?? NetworkMessage.Null;
- }
-
- private NetworkMessage GetNextMessage()
- {
- if (BaseStream == null)
- throw new NullReferenceException("BaseStream is null");
-
- if (_serialization == null)
- throw new NullReferenceException("Serialization toolkit is null");
-
- var message = ReceiveMessage();
-
- _messageBuffer.Add(message);
- _currentReceiving = Task.Run(GetNextMessage);
-
- return message;
- }
-
- private NetworkMessage ReceiveMessage()
- {
- var len = BitConverter.ToUInt16([(byte)BaseStream.ReadByte(), (byte)BaseStream.ReadByte()]);
- var localSpan = _buffer.Span.Slice(0, len);
- BaseStream.ReadExactly(localSpan);
-
- var message = _serialization!.Deserialize(localSpan);
- return message!;
- }
}
\ No newline at end of file
diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs
index c470092..8c8ded5 100644
--- a/mROA/Implementation/RemoteContextRepository.cs
+++ b/mROA/Implementation/RemoteContextRepository.cs
@@ -1,62 +1,75 @@
-using System.Collections.Frozen;
+using System;
+using System.Collections.Generic;
+using System.Linq;
using mROA.Abstract;
-namespace mROA.Implementation;
-
-public class RemoteContextRepository : IContextRepository
+namespace mROA.Implementation
{
- private IRepresentationModuleProducer? _representationProducer;
- public static FrozenDictionary RemoteTypes = FrozenDictionary.Empty;
- public int ResisterObject(object o)
+ public class RemoteContextRepository : IContextRepository
{
- throw new NotSupportedException();
- }
+ private List _producedRemoteEndpoints = new();
+ public static Dictionary RemoteTypes = new();
+ private IRepresentationModuleProducer? _representationProducer;
- public void ClearObject(int id)
- {
- throw new NotSupportedException();
- }
+ public int HostId { get; set; }
- public object GetObject(int id)
- {
- throw new NotSupportedException();
- }
-
- public T GetObject(int id)
- {
- if (_representationProducer == null)
- throw new NullReferenceException("representation producer is not initialized");
-
- if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
- var remote = (T)Activator.CreateInstance(remoteType, id, _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!;
- return remote;
- }
- public T GetSingleObject()
- {
- var obj = GetSingleObject(typeof(T));
- return (T)obj;
- }
-
- public object GetSingleObject(Type type)
- {
- if (_representationProducer == null)
- throw new NullReferenceException("representation producer is not initialized");
-
- return Activator.CreateInstance(RemoteTypes[type], -1, _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!;
- }
-
- public int GetObjectIndex(object o)
- {
- if (o is RemoteObjectBase remote)
+ public int ResisterObject(object o, IEndPointContext context)
{
- return remote.Id;
+ throw new NotSupportedException();
}
- throw new NotSupportedException();
- }
- public void Inject(T dependency)
- {
- if (dependency is IRepresentationModuleProducer serialisationModule)
- _representationProducer = serialisationModule;
+ public void ClearObject(ComplexObjectIdentifier id)
+ {
+ throw new NotSupportedException();
+ }
+
+ public T GetObject(ComplexObjectIdentifier id)
+ {
+ var index = _producedRemoteEndpoints.Find(i => i.Identifier.Equals(id));
+ if (index is not null)
+ return (T)(index as object);
+ if (_representationProducer == null)
+ throw new NullReferenceException("representation producer is not initialized");
+
+ if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
+ var representationModule =
+ _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
+ representationModule)!;
+
+ _producedRemoteEndpoints.Add((remote as RemoteObjectBase)!);
+
+ return remote;
+ }
+
+ public object GetSingleObject(Type type, int ownerId)
+ {
+ if (_representationProducer == null)
+ throw new NullReferenceException("representation producer is not initialized");
+
+ var representationModule =
+ _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+
+ _producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1,
+ representationModule) as RemoteObjectBase)!);
+
+ return _producedRemoteEndpoints.Last();
+ }
+
+ public int GetObjectIndex(object o, IEndPointContext context)
+ {
+ if (o is RemoteObjectBase remote)
+ {
+ return remote.Id;
+ }
+
+ throw new NotSupportedException();
+ }
+
+ public void Inject(T dependency)
+ {
+ if (dependency is IRepresentationModuleProducer serialisationModule)
+ _representationProducer = serialisationModule;
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs
index af66e18..a35e734 100644
--- a/mROA/Implementation/RemoteObjectBase.cs
+++ b/mROA/Implementation/RemoteObjectBase.cs
@@ -1,61 +1,151 @@
-using mROA.Abstract;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using mROA.Abstract;
using mROA.Implementation.CommandExecution;
// ReSharper disable UnusedMember.Global
-namespace mROA.Implementation;
-
-public abstract class RemoteObjectBase(int id, IRepresentationModule representationModule)
+namespace mROA.Implementation
{
- public int Id => id;
- public int OwnerId => representationModule.Id;
-
- protected async Task GetResultAsync(int methodId, object? parameter = default)
+ public abstract class RemoteObjectBase : IDisposable
{
- var request = new DefaultCallRequest
- { CommandId = methodId, ObjectId = id, Parameter = parameter, ParameterType = parameter?.GetType() };
- await representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request);
-
- var localTokenSource = new CancellationTokenSource();
-
- var successResponse =
- representationModule.GetMessageAsync>(request.Id,
- EMessageType.FinishedCommandExecution, localTokenSource.Token);
-
- var errorResponse =
- representationModule.GetMessageAsync(request.Id,
- EMessageType.ExceptionCommandExecution, localTokenSource.Token);
-
- Task.WaitAny(successResponse, errorResponse);
-
- if (successResponse.IsCompletedSuccessfully)
+ protected bool Equals(RemoteObjectBase other)
{
- await localTokenSource.CancelAsync();
- return successResponse.Result.Result!;
+ return _identifier.Equals(other._identifier);
}
- await localTokenSource.CancelAsync();
- throw errorResponse.Result.GetException();
- }
+ 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((RemoteObjectBase)obj);
+ }
- protected async Task CallAsync(int methodId, object? parameter = default)
- {
- var request = new DefaultCallRequest
- { CommandId = methodId, ObjectId = id, Parameter = parameter, ParameterType = parameter?.GetType() };
- await representationModule.PostCallMessageAsync(request.Id, EMessageType.CallRequest, request);
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_identifier.GetHashCode(), _identifier.ContextId);
+ }
- var successResponse =
- representationModule.GetMessageAsync(
- messageType: EMessageType.FinishedCommandExecution, requestId: request.Id);
- var errorResponse =
- representationModule.GetMessageAsync(
- messageType: EMessageType.ExceptionCommandExecution, requestId: request.Id);
+ private readonly ComplexObjectIdentifier _identifier;
+ private readonly IRepresentationModule _representationModule;
- Task.WaitAny(successResponse, errorResponse);
+ protected RemoteObjectBase(int id, IRepresentationModule representationModule)
+ {
+ _identifier = new ComplexObjectIdentifier { ContextId = id, OwnerId = representationModule.Id };
+ _representationModule = representationModule;
+ }
- if (successResponse.IsCompletedSuccessfully)
- return;
+ public int Id => _identifier.ContextId;
+ public int OwnerId => _identifier.OwnerId;
+ public ComplexObjectIdentifier Identifier => _identifier;
- throw errorResponse.Result.GetException();
+ public void Dispose()
+ {
+ if (_identifier.IsStatic)
+ return;
+ CallAsync(-1).Wait();
+ }
+
+ protected async Task GetResultAsync(int methodId, object?[]? parameters = null,
+ CancellationToken cancellationToken = default)
+ {
+ var request = new DefaultCallRequest
+ {
+ CommandId = methodId, ObjectId = _identifier, Parameters = parameters
+ };
+
+ await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
+
+ var localTokenSource = new CancellationTokenSource();
+
+ var successResponse =
+ _representationModule.GetMessageAsync>(request.Id,
+ MessageType.FinishedCommandExecution,
+ localTokenSource.Token);
+ var errorResponse =
+ _representationModule.GetMessageAsync(requestId: request.Id,
+ MessageType.ExceptionCommandExecution, localTokenSource.Token);
+
+ cancellationToken.Register(async () =>
+ {
+#if TRACE
+ Console.WriteLine("Cancelling task");
+#endif
+ await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest,
+ new CancelRequest
+ {
+ Id = request.Id
+ });
+ localTokenSource.Cancel();
+ });
+
+ Task.WaitAny(new Task[]
+ {
+ successResponse, errorResponse
+ }, cancellationToken);
+
+ if (successResponse.IsCompletedSuccessfully)
+ {
+ localTokenSource.Cancel();
+ return successResponse.Result.Result!;
+ }
+
+ localTokenSource.Cancel();
+ throw errorResponse.Result.GetException();
+ }
+
+ protected async Task CallAsync(int methodId, object?[]? parameters = null,
+ CancellationToken cancellationToken = default)
+ {
+ var request = new DefaultCallRequest
+ {
+ CommandId = methodId, ObjectId = _identifier, Parameters = parameters
+ };
+ await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
+
+ var localTokenSource = new CancellationTokenSource();
+
+ var successResponse =
+ _representationModule.GetMessageAsync(request.Id,
+ MessageType.FinishedCommandExecution,
+ localTokenSource.Token);
+ var errorResponse =
+ _representationModule.GetMessageAsync(requestId: request.Id,
+ MessageType.ExceptionCommandExecution, localTokenSource.Token);
+
+ cancellationToken.Register(async () =>
+ {
+#if TRACE
+ Console.WriteLine("Cancelling task");
+#endif
+ await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest,
+ new CancelRequest
+ {
+ Id = request.Id
+ });
+ localTokenSource.Cancel();
+ });
+
+ Task.WaitAny(new Task[]
+ {
+ errorResponse, successResponse
+ }, cancellationToken);
+
+#if TRACE
+ Console.WriteLine($"Handling message");
+#endif
+ if (successResponse.IsCompletedSuccessfully)
+ return;
+
+ if (errorResponse.IsCompletedSuccessfully)
+ throw errorResponse.Result.GetException();
+ }
+
+ public override string ToString()
+ {
+ return _identifier.ToString();
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/RemoteObjectFactory.cs b/mROA/Implementation/RemoteObjectFactory.cs
new file mode 100644
index 0000000..fad21e3
--- /dev/null
+++ b/mROA/Implementation/RemoteObjectFactory.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using mROA.Abstract;
+
+namespace mROA.Implementation
+{
+ public class RemoteObjectFactory : IRemoteObjectFactory
+ {
+ public static Dictionary RemoteTypes = new();
+ private IRepresentationModuleProducer? _representationProducer;
+
+ public T Produce(ComplexObjectIdentifier id)
+ {
+ if (_representationProducer == null)
+ throw new NullReferenceException("representation producer is not initialized");
+
+ if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException();
+ var representationModule =
+ _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId());
+ var remote = (T)Activator.CreateInstance(remoteType, id.ContextId,
+ representationModule)!;
+ return remote;
+ }
+
+ public void Inject(T dependency)
+ {
+ if (dependency is IRepresentationModuleProducer serialisationModule)
+ _representationProducer = serialisationModule;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs
index 6c3e08f..ffd1b87 100644
--- a/mROA/Implementation/RepresentationModule.cs
+++ b/mROA/Implementation/RepresentationModule.cs
@@ -1,115 +1,112 @@
-using mROA.Abstract;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using mROA.Abstract;
-namespace mROA.Implementation;
-
-public class RepresentationModule : IRepresentationModule
+namespace mROA.Implementation
{
- private ISerializationToolkit? _serialization;
- private INextGenerationInteractionModule? _interaction;
-
- public void Inject(T dependency)
+ public class RepresentationModule : IRepresentationModule
{
- switch (dependency)
+ private INextGenerationInteractionModule? _interaction;
+ private ISerializationToolkit? _serialization;
+
+ public void Inject(T dependency)
{
- case ISerializationToolkit toolkit:
- _serialization = toolkit;
- break;
- case INextGenerationInteractionModule interactionModule:
- _interaction = interactionModule;
- break;
- }
- }
-
- public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId;
-
- public async Task GetMessageAsync(Guid? requestId, EMessageType? messageType,
- CancellationToken token = default)
- {
- if (_serialization == null)
- throw new NullReferenceException("Serialization toolkit is not initialized");
-
- var raw = await GetRawMessage(m => m.IsValidMessage(requestId, messageType), token);
- return _serialization.Deserialize(raw)!;
- }
-
- public T GetMessage(Guid? requestId = null, EMessageType? messageType = null)
- {
- return GetMessage(m => m.IsValidMessage(requestId, messageType));
- }
-
- public T GetMessage(Predicate filter)
- {
- if (_serialization == null)
- throw new NullReferenceException("Serialization toolkit is not initialized");
- var raw = GetRawMessage(filter).GetAwaiter().GetResult();
- return _serialization.Deserialize(raw)!;
- }
-
- public async Task GetRawMessage(Predicate filter, CancellationToken token = default)
- {
- await Task.Yield();
-
- if (_interaction == null)
- throw new NullReferenceException("Interaction toolkit is not initialized");
-
- if (filter(_interaction.LastMessage))
- {
- _interaction.HandleMessage(_interaction.LastMessage);
- return _interaction.LastMessage.Data;
+ switch (dependency)
+ {
+ case ISerializationToolkit toolkit:
+ _serialization = toolkit;
+ break;
+ case INextGenerationInteractionModule interactionModule:
+ _interaction = interactionModule;
+ break;
+ }
}
- var message = _interaction.FirstByFilter(filter);
+ public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized"))
+ .ConnectionId;
- if (message != NetworkMessage.Null)
+ public async Task GetMessageAsync(Guid? requestId, MessageType? messageType,
+ CancellationToken token = default)
{
- _interaction.HandleMessage(message);
- return message.Data;
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is not initialized");
+
+ var rawMessage = await GetRawMessage(requestId, messageType, token);
+ return _serialization.Deserialize(rawMessage)!;
}
-
- while (!token.IsCancellationRequested)
+ public T GetMessage(Guid? requestId = null, MessageType? messageType = null)
{
- var handle = _interaction.CurrentReceivingHandle;
- handle.WaitOne();
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is not initialized");
- message = _interaction.LastMessage;
-
- if (!filter(message))
- continue;
-
- message = _interaction.LastMessage;
-
- _interaction.HandleMessage(message);
- return message.Data;
+ var rawMessage = GetRawMessage(requestId, messageType).GetAwaiter().GetResult();
+ return _serialization.Deserialize(rawMessage)!;
}
- return [];
- }
+ public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null,
+ CancellationToken token = default)
+ {
+ if (_interaction == null)
+ throw new NullReferenceException("Interaction toolkit is not initialized");
- public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, T payload) where T : notnull
- {
- await PostCallMessageAsync(id, eMessageType, payload, typeof(T));
- }
+ var fromBuffer =
+ _interaction.FirstByFilter(message =>
+ (requestId is null || message.Id == requestId) &&
+ (messageType is null || message.SchemaId == messageType));
- public async Task PostCallMessageAsync(Guid id, EMessageType eMessageType, object payload, Type payloadType)
- {
- if (_interaction == null)
- throw new NullReferenceException("Interaction toolkit is not initialized");
- if (_serialization == null)
- throw new NullReferenceException("Serialization toolkit is not initialized");
+ if (fromBuffer == null)
+ {
+ while (token.IsCancellationRequested == false)
+ {
+ var message = await _interaction.GetNextMessageReceiving();
+ if ((requestId is not null && message.Id != requestId) ||
+ (messageType is not null && message.SchemaId != messageType))
+ continue;
- var message = new NetworkMessage
- { Id = id, MessageType = eMessageType, Data = _serialization.Serialize(payload, payloadType) };
- await _interaction.PostMessage(message);
- }
+ _interaction.HandleMessage(message);
+ return message.Data;
+ }
+ }
- public void PostCallMessage(Guid id, EMessageType eMessageType, T payload) where T : notnull
- {
- PostCallMessageAsync(id, eMessageType, payload).GetAwaiter().GetResult();
- }
+ if (fromBuffer == null)
+ {
+ return Array.Empty();
+ }
- public void PostCallMessage(Guid id, EMessageType eMessageType, object payload, Type payloadType)
- {
- PostCallMessageAsync(id, eMessageType, payload, payloadType).GetAwaiter().GetResult();
+ _interaction.HandleMessage(fromBuffer);
+ return fromBuffer.Data;
+ }
+
+ public async Task PostCallMessageAsync(Guid id, MessageType messageType, T payload) where T : notnull
+ {
+ await PostCallMessageAsync(id, messageType, payload, typeof(T));
+ }
+
+ public async Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType)
+ {
+ if (_interaction == null)
+ throw new NullReferenceException("Interaction toolkit is not initialized");
+ if (_serialization == null)
+ throw new NullReferenceException("Serialization toolkit is not initialized");
+#if TRACE
+ Console.WriteLine($"{DateTime.Now.TimeOfDay} Posting message: {id} - {messageType} to {Id}");
+#endif
+
+ var serialized = _serialization.Serialize(payload, payloadType);
+ await _interaction.PostMessage(new NetworkMessage
+ { Id = id, SchemaId = messageType, Data = serialized });
+ }
+
+ public void PostCallMessage(Guid id, MessageType messageType, T payload) where T : notnull
+ {
+ PostCallMessageAsync(id, messageType, payload).GetAwaiter().GetResult();
+ }
+
+ public void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType)
+ {
+ PostCallMessageAsync(id, messageType, payload, payloadType).GetAwaiter().GetResult();
+ }
}
}
\ No newline at end of file
diff --git a/mROA/Implementation/RequestContext.cs b/mROA/Implementation/RequestContext.cs
new file mode 100644
index 0000000..9daf956
--- /dev/null
+++ b/mROA/Implementation/RequestContext.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace mROA.Implementation
+{
+ public sealed class RequestContext
+ {
+ public int OwnerId { get; }
+ public Guid RequestId { get; }
+
+ public RequestContext(Guid requestId, int ownerId)
+ {
+ RequestId = requestId;
+ OwnerId = ownerId;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs
deleted file mode 100644
index 644b8f4..0000000
--- a/mROA/Implementation/SharedObject.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-using System.Text.Json.Serialization;
-using mROA.Abstract;
-// ReSharper disable UnusedMember.Global
-#pragma warning disable CS8618, CS9264
-
-namespace mROA.Implementation;
-
-public static class TransmissionConfig
-{
- private static IContextRepository? _realContextRepository;
- private static IContextRepository? _remoteEndpointContextRepository;
- private static IOwnershipRepository? _ownershipRepository;
-
- public static IContextRepository RealContextRepository
- {
- get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null");
- set => _realContextRepository = value;
- }
-
- public static IContextRepository RemoteEndpointContextRepository
- {
- get => _remoteEndpointContextRepository ?? throw new NullReferenceException("RemoteEndpointContextRepository is null");
- set => _remoteEndpointContextRepository = value;
- }
-
- public static IOwnershipRepository OwnershipRepository
- {
- get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null");
- set => _ownershipRepository = value;
- }
-
-}
-
-public class SharedObject where T : notnull
-{
- private IContextRepository GetDefaultContextRepository() =>
- (OwnerId == TransmissionConfig.OwnershipRepository.GetHostOwnershipId()
- ? TransmissionConfig.RealContextRepository
- : TransmissionConfig.RemoteEndpointContextRepository) ??
- throw new NullReferenceException(
- "DefaultContextRepository was not defined");
-
- private int _contextId = -2;
- private int _ownerId = -1;
-
- public int OwnerId
- {
- get
- {
- _ownerId = _ownerId == -1 ? TransmissionConfig.OwnershipRepository.GetOwnershipId() : _ownerId;
- return _ownerId;
- }
- init => _ownerId = value;
- }
-
- // ReSharper disable once MemberCanBePrivate.Global
- public int ContextId
- {
- // ReSharper disable once UnusedMember.Global
- get
- {
- if (_contextId != -2)
- return _contextId;
-
- _contextId = TransmissionConfig.RealContextRepository.GetObjectIndex(Value);
- return _contextId;
- }
- init
- {
- _contextId = value;
- Value = GetDefaultContextRepository().GetObject(_contextId)!;
- }
- }
-
- [JsonIgnore] public T Value { get; private init; }
-
- // ReSharper disable once MemberCanBePrivate.Global
- // ReSharper disable once UnusedMember.Global
- public SharedObject()
- {
- }
-
- // ReSharper disable once UnusedMember.Global
- public SharedObject(T value)
- {
- Value = value;
-
- if (value is RemoteObjectBase ro)
- {
- _ownerId = ro.OwnerId;
- _contextId = ro.Id;
- }
- else
- _ownerId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId();
- }
-
- public static implicit operator T(SharedObject value) => value.Value;
-
- public static implicit operator SharedObject(T value) =>
- new(value);
-}
\ No newline at end of file
diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs
new file mode 100644
index 0000000..0fe0450
--- /dev/null
+++ b/mROA/Implementation/SharedObjectShell.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Text.Json.Serialization;
+using mROA.Abstract;
+using mROA.Implementation.Attributes;
+
+// ReSharper disable UnusedMember.Global
+#pragma warning disable CS8618, CS9264
+
+namespace mROA.Implementation
+{
+ public interface ISharedObjectShell
+ {
+ // ReSharper disable once UnusedMemberInSuper.Global
+ IEndPointContext EndPointContext { get; set; }
+ ComplexObjectIdentifier Identifier { get; set; }
+ object UniversalValue { get; set; }
+ }
+
+ public class SharedObjectShellShell : ISharedObjectShell where T : notnull
+ {
+ private ComplexObjectIdentifier _identifier = ComplexObjectIdentifier.Null;
+
+ private T _value;
+
+ // ReSharper disable once MemberCanBePrivate.Global
+ // ReSharper disable once UnusedMember.Global
+ public SharedObjectShellShell()
+ {
+ }
+
+ // ReSharper disable once UnusedMember.Global
+ // ReSharper disable once MemberCanBePrivate.Global
+ public SharedObjectShellShell(T value)
+ {
+ Value = value;
+ }
+
+ [JsonIgnore]
+ [SerializationIgnore]
+ // ReSharper disable once MemberCanBePrivate.Global
+ public T Value
+ {
+ get => _value;
+ set
+ {
+ _value = value;
+
+ if (value is RemoteObjectBase ro)
+ {
+ _identifier = ro.Identifier;
+ }
+ else
+ {
+ _identifier.OwnerId = EndPointContext.OwnerId;
+ _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value, EndPointContext);
+ }
+ }
+ }
+
+ [SerializationIgnore]
+ [JsonIgnore]
+ public IEndPointContext EndPointContext { get; set; } = new EndPointContext
+ {
+ RealRepository = TransmissionConfig.RealContextRepository,
+ RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository,
+ HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(),
+ OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId
+ };
+
+ public ComplexObjectIdentifier Identifier
+ {
+ get
+ {
+ _identifier.OwnerId = _identifier.OwnerId == 0 ? EndPointContext.OwnerId : _identifier.OwnerId;
+ return _identifier;
+ }
+ set
+ {
+ _identifier = value;
+ Value = GetDefaultContextRepository().GetObject(Identifier);
+ }
+ }
+
+ public object UniversalValue
+ {
+ get => _value;
+ set => _value = (T)value;
+ }
+
+ private IContextRepository GetDefaultContextRepository() =>
+ (_identifier.OwnerId == EndPointContext.HostId
+ ? EndPointContext.RealRepository
+ : EndPointContext.RemoteRepository) ??
+ throw new NullReferenceException(
+ "DefaultContextRepository was not defined");
+
+ public static implicit operator T(SharedObjectShellShell value) => value.Value;
+
+ public static implicit operator SharedObjectShellShell