From 50fd3e7b7382d5c071a9520030581777c79766e8 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 20 Feb 2025 16:10:09 +0300 Subject: [PATCH 01/66] =?UTF-8?q?=D0=B1=D0=B8=D0=BB=D0=B4=D0=B8=D1=82?= =?UTF-8?q?=D1=81=D1=8F=20=D0=BD=D0=B0=20=D1=81=D1=82=D0=B0=D1=80=D0=BE?= =?UTF-8?q?=D0=BC=20=D0=B4=D0=BE=D1=82=D0=BD=D0=B5=D1=82=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 6 +- Example.Backend/LoadTestImp.cs | 40 +- Example.Backend/Page.cs | 13 +- Example.Backend/Printer.cs | 26 +- Example.Backend/PrinterFactory.cs | 60 ++- Example.Backend/Program.cs | 64 +-- Example.Frontend/ClientBasedPrinter.cs | 42 +- Example.Frontend/Example.Frontend.csproj | 6 +- Example.Frontend/Program.cs | 114 ++-- Example.Shared/Example.Shared.csproj | 6 +- Example.Shared/ILoadTest.cs | 17 +- Example.Shared/IPage.cs | 11 +- Example.Shared/IPrinter.cs | 15 +- Example.Shared/IPrinterFactory.cs | 19 +- mROA.Benchmark/Program.cs | 80 +-- mROA.Benchmark/mROA.Benchmark.csproj | 4 +- mROA.Codegen/mROA.Codegen.csproj | 3 +- mROA.Codegen/mROASourceGenerator.cs | 488 ++++++++++-------- mROA.Test/NextGenTest.cs | 120 ++--- mROA.Test/mROA.Test.csproj | 4 +- mROA/Abstract/ICommandExecution.cs | 13 +- mROA/Abstract/IConnectionHub.cs | 21 +- mROA/Abstract/IContextRepository.cs | 19 +- mROA/Abstract/IContextRepositoryHub.cs | 9 +- mROA/Abstract/IExecuteModule.cs | 9 +- mROA/Abstract/IFrontendBridge.cs | 10 +- mROA/Abstract/IGatewayModule.cs | 11 +- mROA/Abstract/IIdentityGenerator.cs | 9 +- mROA/Abstract/IInjectableModule.cs | 9 +- mROA/Abstract/IInteractionModule.cs | 24 +- mROA/Abstract/IMethodRepository.cs | 16 +- mROA/Abstract/IOwnershipRepository.cs | 11 +- .../Abstract/IRepresentationModuleProducer.cs | 9 +- mROA/Abstract/IRequestExtractor.cs | 9 +- mROA/Abstract/ISerialisationModule.cs | 47 +- mROA/Abstract/ISerializationToolkit.cs | 23 +- .../SharedObjectInterfaceAttribute.cs | 7 +- .../SharedObjectSingletonAttribute.cs | 7 +- .../Backend/BackendIdentityGenerator.cs | 23 +- .../Backend/BasicConfigurationExtensions.cs | 50 +- .../Backend/BasicExecutionModule.cs | 197 +++---- mROA/Implementation/Backend/ConnectionHub.cs | 55 +- .../Backend/ContextRepository.cs | 150 +++--- .../Backend/HubRequestExtractor.cs | 92 ++-- .../Backend/MultiClientContextRepository.cs | 93 ++-- .../Backend/MultiClientOwnershipRepository.cs | 43 +- .../Backend/NetworkGatewayModule.cs | 148 +++--- .../Bootstrap/FullMixBuilder.cs | 29 +- mROA/Implementation/CallRequest.cs | 36 +- .../ExceptionCommandExecution.cs | 24 +- .../CommandExecution/FinalCommandExecution.cs | 28 +- .../TypedFinalCommandExecution.cs | 16 +- .../CreativeRepresentationModuleProducer.cs | 58 ++- .../JsonFrontendSerialisationModule.cs | 22 +- .../Frontend/NetworkFrontendBridge.cs | 68 +-- .../Frontend/RequestExtractor.cs | 146 +++--- .../Frontend/StaticOwnershipRepository.cs | 26 +- mROA/Implementation/IdAssingnment.cs | 9 +- .../JsonSerializationToolkit.cs | 100 ++-- mROA/Implementation/MethodRepository.cs | 70 +-- mROA/Implementation/NetworkMessage.cs | 26 +- .../NextGenerationInteractionModule.cs | 168 +++--- .../Implementation/RemoteContextRepository.cs | 98 ++-- mROA/Implementation/RemoteObjectBase.cs | 85 +-- mROA/Implementation/RepresentationModule.cs | 161 +++--- mROA/Implementation/SharedObject.cs | 160 +++--- .../StaticRepresentationModuleProducer.cs | 32 +- mROA/LegacyExtentions.cs | 43 ++ mROA/mROA.csproj | 8 +- 69 files changed, 1990 insertions(+), 1675 deletions(-) create mode 100644 mROA/LegacyExtentions.cs diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index 62581cc..fc4e81b 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -2,9 +2,11 @@ Exe - net9.0 - enable + netstandard2.1 + enable + + 9 diff --git a/Example.Backend/LoadTestImp.cs b/Example.Backend/LoadTestImp.cs index e0ea125..bc22304 100644 --- a/Example.Backend/LoadTestImp.cs +++ b/Example.Backend/LoadTestImp.cs @@ -1,28 +1,30 @@ -using Example.Shared; +using System; +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(); + } } } \ 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/Printer.cs b/Example.Backend/Printer.cs index b456160..59ef144 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -1,20 +1,22 @@ +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 string GetName() + { + return Name; + } - public async Task> Print(string text, CancellationToken cancellationToken = default) - { - // throw new Exception("The method or operation is not implemented."); - return new Page {Text = text}; + public async Task> Print(string text, CancellationToken cancellationToken = default) + { + // throw new Exception("The method or operation is not implemented."); + return new Page {Text = text}; + } } } \ No newline at end of file diff --git a/Example.Backend/PrinterFactory.cs b/Example.Backend/PrinterFactory.cs index e71503f..697b2e4 100644 --- a/Example.Backend/PrinterFactory.cs +++ b/Example.Backend/PrinterFactory.cs @@ -1,40 +1,44 @@ +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 SharedObject 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(SharedObject printer) + { + _printers.Add(printer.Value); + Console.WriteLine("Registered printer"); + } - public SharedObject GetFirstPrinter() - { - return new SharedObject(_printers.First()); - } + public SharedObject GetPrinterByName(string printerName) + { + Console.WriteLine("Getting printer"); + return new SharedObject(_printers.Find(i => i.GetName() == printerName)!); + } - public string[] CollectAllNames() - { - Console.WriteLine("Collecting all printers"); - return _printers.Select(i => i.GetName()).ToArray(); + public SharedObject GetFirstPrinter() + { + return new SharedObject(_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..0a8315a 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -7,37 +7,43 @@ 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 BackendIdentityGenerator()); + 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(); -var gateway = builder.GetModule(); + 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); + return repo; + })); + builder.SetupMethodsRepository(new CoCodegenMethodRepository()); + builder.Modules.Add(new CreativeRepresentationModuleProducer( + new IInjectableModule[] { builder.GetModule()! }, + typeof(RepresentationModule))); -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.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 58a97c8..32c3de0 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -1,28 +1,32 @@ -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 string GetName() + { + Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); + return "ClientBasedPrinter from mroa"; + } + + public async Task> Print(string text, CancellationToken cancellationToken) + { + Console.WriteLine($"Printed: {text}"); + await Task.Yield(); + return new ClientBasedPage(); + } } - 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/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index f59d7cc..e4d8f0d 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -2,9 +2,11 @@ Exe - net9.0 - enable + netstandard2.1 + enable + + 9 diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index fdbd77d..ca2ac99 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -1,6 +1,8 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; using System.Net; using System.Text; +using System.Threading; using Example.Frontend; using Example.Shared; using mROA.Codegen; @@ -9,71 +11,77 @@ 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 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(); -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(typeof(IPrinterFactory)) as IPrinterFactory; + var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory; //правильный порядок команд 8-5-10-7 -var printer = factory.Create("Test"); -Console.WriteLine("Printer created"); -Thread.Sleep(100); + var printer = factory.Create("Test"); + Console.WriteLine("Printer created"); + Thread.Sleep(100); -var name = printer.Value.GetName(); -Console.WriteLine("Printer name : {0}", name); -Thread.Sleep(100); + var name = printer.Value.GetName(); + Console.WriteLine("Printer name : {0}", name); + Thread.Sleep(100); -factory.Register(new SharedObject(new ClientBasedPrinter())); -Console.WriteLine("Registered printer"); -Thread.Sleep(100); + factory.Register(new SharedObject(new ClientBasedPrinter())); + Console.WriteLine("Registered printer"); + Thread.Sleep(100); -var registred = factory.GetFirstPrinter(); -Console.WriteLine("First printer"); -Thread.Sleep(100); + var registred = 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(registred.Value); + 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 = printer.Value.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); + var data = page.Value.GetData(); + Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); -var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; + var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; -const int iterations = 10000; -var timer = Stopwatch.StartNew(); -var x = 0; -for (int i = 0; i < iterations; i++) -{ - x = loadSingleton.Next(x); -} + 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 + 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..37ad63a 100644 --- a/Example.Shared/Example.Shared.csproj +++ b/Example.Shared/Example.Shared.csproj @@ -1,9 +1,11 @@  - net9.0 - enable + netstandard2.1 + enable + + 9 diff --git a/Example.Shared/ILoadTest.cs b/Example.Shared/ILoadTest.cs index dc4e787..326822f 100644 --- a/Example.Shared/ILoadTest.cs +++ b/Example.Shared/ILoadTest.cs @@ -1,13 +1,14 @@ 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 + { + int Next(int last); + int Last(int next); + void C(); + void A(); + } } diff --git a/Example.Shared/IPage.cs b/Example.Shared/IPage.cs index 6f39f19..a8d21f9 100644 --- a/Example.Shared/IPage.cs +++ b/Example.Shared/IPage.cs @@ -1,9 +1,10 @@ using mROA.Implementation.Attributes; -namespace Example.Shared; - -[SharedObjectInterface] -public interface IPage +namespace Example.Shared { - byte[] GetData(); + [SharedObjectInterface] + public interface IPage + { + byte[] GetData(); + } } \ No newline at end of file diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 2d8e6c8..a2c789f 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -1,12 +1,15 @@ +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 interface IPrinter + { + string GetName(); + Task> Print(string text, CancellationToken cancellationToken); + } } \ No newline at end of file diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs index eb6ee8e..bc18270 100644 --- a/Example.Shared/IPrinterFactory.cs +++ b/Example.Shared/IPrinterFactory.cs @@ -1,15 +1,16 @@ 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 + { + SharedObject Create(string printerName); + void Register(SharedObject printer); + SharedObject GetPrinterByName(string printerName); + SharedObject GetFirstPrinter(); + string[] CollectAllNames(); + } } \ No newline at end of file diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs index 57ab0c3..c4ebb5e 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -1,50 +1,54 @@ -using BenchmarkDotNet.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Running; -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.Codegen/mROA.Codegen.csproj b/mROA.Codegen/mROA.Codegen.csproj index 0b8cdea..2a23fd6 100644 --- a/mROA.Codegen/mROA.Codegen.csproj +++ b/mROA.Codegen/mROA.Codegen.csproj @@ -25,8 +25,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index da1f1bb..db252ae 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -7,19 +7,19 @@ 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"; + /// + /// 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 : ISourceGenerator + { + private const string Namespace = "mROA.Implementation"; + private const string AttributeName = "SharedObjectInterafceAttribute"; - private const string AttributeSourceCode = $@"// + private const string AttributeSourceCode = $@"// namespace {Namespace} {{ @@ -29,151 +29,151 @@ namespace {Namespace} }} }}"; - 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); + // 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))); + // } - // 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). + /// + /// Syntax context, based on CreateSyntaxProvider predicate + /// The specific cast and whether the attribute was found. + // private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen( + // GeneratorSyntaxContext context) + // { + // var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node; + // + // // Go through all attributes of the class. + // foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists) + // foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + // { + // 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); + // } - /// - /// Checks whether the Node is annotated with the [Report] attribute and maps syntax context to the specific node type (ClassDeclarationSyntax). - /// - /// Syntax context, based on CreateSyntaxProvider predicate - /// The specific cast and whether the attribute was found. - private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen( - GeneratorSyntaxContext context) - { - var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node; - - // Go through all attributes of the class. - foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists) - foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + /// + /// 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(GeneratorExecutionContext context, Compilation compilation, + ImmutableArray classes) { - 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) - { - // We need to get semantic model of the class to retrieve metadata. - var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree); - - - // 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 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) { - var index = methods.Count; - methods.Add((namespaceName + "." + originalName, method)); - var sb = new StringBuilder(); + // We need to get semantic model of the class to retrieve metadata. + var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree); - 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; + // Symbols allow us to get the compile-time information. + if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol) + continue; - //Creating signature - sb.AppendLine("public" + (isAsync - ? " async " - : " ") + - $"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{"); + 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 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})"; + var methodsText = new List(); - 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}"); + foreach (var method in methodBody) + { + var index = methods.Count; + methods.Add((namespaceName + "." + originalName, method)); + var sb = new StringBuilder(); - sb.AppendLine("\t\t" + prefix + caller + postfix+ ";"); - - sb.AppendLine("\t}"); - methodsText.Add(sb.ToString()); - } + 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; - var code = $@"// + + //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\t" + prefix + caller + postfix + ";"); + + sb.AppendLine("\t\t}"); + + methodsText.Add(sb.ToString()); + } + + var code = $@"// using mROA; using System; @@ -181,106 +181,168 @@ 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", methodsText)} + }} }} "; - // Add the source code to the compilation. - context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); - frontendContextRepo.Add( - $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); - } + // Add the source code to the compilation. + context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); - 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(); + frontendContextRepo.Add( + $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); + } - var coCodegenRepoCode = @$"// + if (methods.Count != 0) + { + var methodsStringed = methods.Select(i => + $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})") + .ToList(); + + var coCodegenRepoCode = @$"// using System.Collections.Generic; using System.Reflection; using mROA.Abstract; +using System; -namespace mROA.Codegen; - -public class CoCodegenMethodRepository : IMethodRepository +namespace mROA.Codegen {{ - private readonly List _methods = [ - {string.Join(", // test comment\r\n\t\t", methodsStringed)} - ]; - public MethodInfo GetMethod(int id) + public class CoCodegenMethodRepository : IMethodRepository {{ - if (_methods.Count <= id) - return null; - - return _methods[id]; - }} + private readonly List _methods = new () {{ + {string.Join(",\r\n\t\t\t", methodsStringed)} + }}; - public int RegisterMethod(MethodInfo method) - {{ - _methods.Add(method); - return _methods.Count - 1; - }} + public MethodInfo GetMethod(int id) + {{ + if (_methods.Count <= id) + return null; + + return _methods[id]; + }} - public IEnumerable GetMethods() - {{ - return _methods; - }} + public int RegisterMethod(MethodInfo method) + {{ + _methods.Add(method); + return _methods.Count - 1; + }} - public void Inject(T dependency) - {{ + 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; + context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); + } + + if (frontendContextRepo.Count != 0) + { + var fronendRepoCode = @$"// using mROA.Implementation; using mROA.Abstract; +using System.Collections.Generic; +using System; +using System.Reflection; -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 sealed class RemoteTypeBinder + {{ + static RemoteTypeBinder(){{ + RemoteContextRepository.RemoteTypes = new Dictionary {{ + {string.Join(", \r\n\t\t\t", frontendContextRepo)}}}; + }} }} }} "; - context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); + context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); + } + } + + 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) + { + var type = taskType.ToString(); + type = type.Substring(type.IndexOf('<') + 1); + return type.Substring(0, type.Length - 1); + } + + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + var trees = context.Compilation.SyntaxTrees; + + var interfaces = new List(); + foreach (var tree in trees) + { + 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) + + if (inside is InterfaceDeclarationSyntax ids2) + if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2)) + interfaces.Add(ids2); + } + } + } + + GenerateCode(context, context.Compilation, interfaces.ToImmutableArray()); + } + + private bool ContainsSOIAttribute(SyntaxList attributes, GeneratorExecutionContext context, + InterfaceDeclarationSyntax interfaceDeclarationSyntax) + { + foreach (AttributeListSyntax attributeListSyntax in attributes) + foreach (AttributeSyntax attributeSyntax in 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 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) - { - var type = taskType.ToString(); - type = type.Substring(type.IndexOf('<') + 1); - return type.Substring(0, type.Length - 1); - } } \ No newline at end of file diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs index 7293877..76a53c5 100644 --- a/mROA.Test/NextGenTest.cs +++ b/mROA.Test/NextGenTest.cs @@ -1,72 +1,76 @@ -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(); + _listener = new TcpListener(IPAddress.Loopback, 4567); + _interactionModuleA = new NextGenerationInteractionModule(); + _interactionModuleA.Inject(new JsonSerializationToolkit()); + _interactionModuleB = new NextGenerationInteractionModule(); + _interactionModuleB.Inject(new JsonSerializationToolkit()); - 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"); - } + [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.Dispose(); + } } } \ No newline at end of file diff --git a/mROA.Test/mROA.Test.csproj b/mROA.Test/mROA.Test.csproj index 4262b31..4d1d9e4 100644 --- a/mROA.Test/mROA.Test.csproj +++ b/mROA.Test/mROA.Test.csproj @@ -1,9 +1,9 @@  - net9.0 + netstandard2.1 latest - enable + enable false diff --git a/mROA/Abstract/ICommandExecution.cs b/mROA/Abstract/ICommandExecution.cs index 4566f1d..210b976 100644 --- a/mROA/Abstract/ICommandExecution.cs +++ b/mROA/Abstract/ICommandExecution.cs @@ -1,8 +1,11 @@ -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; } + int ClientId { get; set; } + int CommandId { get; } + } } \ No newline at end of file diff --git a/mROA/Abstract/IConnectionHub.cs b/mROA/Abstract/IConnectionHub.cs index 1a595c8..43dc945 100644 --- a/mROA/Abstract/IConnectionHub.cs +++ b/mROA/Abstract/IConnectionHub.cs @@ -1,12 +1,13 @@ -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 754c39f..a54d5d6 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -1,11 +1,14 @@ -namespace mROA.Abstract; +using System; -public interface IContextRepository : IInjectableModule +namespace mROA.Abstract { - int ResisterObject(object o); - void ClearObject(int id); - object GetObject(int id); - T? GetObject(int id); - object GetSingleObject(Type type); - int GetObjectIndex(object o); + public interface IContextRepository : IInjectableModule + { + int ResisterObject(object o); + void ClearObject(int id); + object GetObject(int id); + T? GetObject(int id); + object GetSingleObject(Type type); + int GetObjectIndex(object o); + } } \ 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/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs index 7a9b0a1..2ebdd24 100644 --- a/mROA/Abstract/IExecuteModule.cs +++ b/mROA/Abstract/IExecuteModule.cs @@ -1,8 +1,9 @@ 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); + } } \ No newline at end of file diff --git a/mROA/Abstract/IFrontendBridge.cs b/mROA/Abstract/IFrontendBridge.cs index 103fec2..7d4eb3f 100644 --- a/mROA/Abstract/IFrontendBridge.cs +++ b/mROA/Abstract/IFrontendBridge.cs @@ -1,3 +1,7 @@ -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..46d96bd 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 cb1072e..dc45dbf 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -1,14 +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; } - Task GetNextMessageReceiving(); - Task PostMessage(NetworkMessage message); - void HandleMessage(NetworkMessage message); - NetworkMessage[] UnhandledMessages { get; } - 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/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs index d18405c..9e448f9 100644 --- a/mROA/Abstract/IMethodRepository.cs +++ b/mROA/Abstract/IMethodRepository.cs @@ -1,11 +1,13 @@ -using System.Reflection; +using System.Collections.Generic; +using System.Reflection; -namespace mROA.Abstract; - -public interface IMethodRepository : IInjectableModule +namespace mROA.Abstract { - MethodInfo GetMethod(int id); - int RegisterMethod(MethodInfo method); + public interface IMethodRepository : IInjectableModule + { + MethodInfo GetMethod(int id); + int RegisterMethod(MethodInfo method); - IEnumerable GetMethods(); + IEnumerable GetMethods(); + } } \ 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/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 14ea0ef..02292c2 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/ISerialisationModule.cs @@ -1,31 +1,34 @@ +using System; +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 ISerialisationModule : IInjectableModule { - int ClientId { get; } - Task GetNextCommandExecution(Guid requestId) where T : ICommandExecution; - Task> GetFinalCommandExecution(Guid requestId); - void PostCallRequest(ICallRequest callRequest); + void HandleIncomingRequest(int clientId, byte[] message); + void PostResponse(NetworkMessage message, int clientId); + void SendWelcomeMessage(int clientId); + public interface IFrontendSerialisationModule : IInjectableModule + { + int ClientId { get; } + Task GetNextCommandExecution(Guid requestId) where T : ICommandExecution; + Task> GetFinalCommandExecution(Guid requestId); + void PostCallRequest(ICallRequest callRequest); + } } -} -public interface IRepresentationModule : IInjectableModule -{ - int Id { get; } - Task GetMessageAsync(Guid? requestId = null, MessageType? messageType = null); - T GetMessage(Guid? requestId = null, MessageType? messageType = null); - Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null); + public interface IRepresentationModule : IInjectableModule + { + int Id { get; } + Task GetMessageAsync(Guid? requestId = null, MessageType? messageType = null); + T GetMessage(Guid? requestId = null, MessageType? messageType = null); + Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null); - 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); + 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..fbb48d2 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -1,14 +1,17 @@ -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/Implementation/Attributes/SharedObjectInterfaceAttribute.cs b/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs index 78bfa15..c187036 100644 --- a/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs +++ b/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs @@ -1,3 +1,6 @@ -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..84002ac 100644 --- a/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs +++ b/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs @@ -1,3 +1,6 @@ -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..ae49490 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..16b1851 100644 --- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs +++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs @@ -1,37 +1,39 @@ +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 UseJsonSerialisation(this FullMixBuilder builder) + { + 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 e3d9903..8f5ac39 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -1,121 +1,128 @@ -using System.Reflection; +using System; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; 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 IMethodRepository? _methodRepo; - public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository) - { - if (_methodRepo is null) - throw new NullReferenceException("Method repository was not defined"); + public void Inject(T dependency) + { + if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo; + } + + 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"); + 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 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; + 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.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); + if (currentCommand.ReturnType == typeof(Task)) + return ExecuteAsync(currentCommand, context, parameter, command); - return Execute(currentCommand, context, parameter, command); - } - - private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command) - { - try - { - var finalResult = currentCommand.Invoke(context, parameter is null ? [] : [parameter]); - return new TypedFinalCommandExecution - { - CommandId = command.CommandId, Result = finalResult, - Id = command.Id, - Type = currentCommand.ReturnType - }; + return Execute(currentCommand, context, parameter, command); } - catch (Exception e) + + private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, + ICallRequest command) { - return new ExceptionCommandExecution + try { - Id = command.Id, CommandId = command.CommandId, - Exception = e.ToString() - }; - } - } - - 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])!; - - - result.Wait(token); - - - return new FinalCommandExecution { CommandId = command.CommandId, Id = command.Id }; - } - catch (Exception e) - { - return new ExceptionCommandExecution + var finalResult = currentCommand.Invoke(context, parameter is null ? new object[0] : new[] + { parameter }); + return new TypedFinalCommandExecution + { + CommandId = command.CommandId, Result = finalResult, + Id = command.Id, + Type = currentCommand.ReturnType + }; + } + catch (Exception e) { - Id = command.Id, CommandId = command.CommandId, - Exception = e.ToString() - }; + return new ExceptionCommandExecution + { + Id = command.Id, CommandId = command.CommandId, + 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 static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + ICallRequest command) { - 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(); + var token = tokenSource.Token; + try { - Id = command.Id, - Result = finalResult, - CommandId = command.CommandId, - Type = finalResult?.GetType() - }; + var result = (Task)currentCommand.Invoke(context, parameter is null ? new object[] { token } : new[] + { parameter, token })!; + + + result.Wait(token); + + + return new FinalCommandExecution { CommandId = command.CommandId, Id = command.Id }; + } + catch (Exception e) + { + return new ExceptionCommandExecution + { + Id = command.Id, CommandId = command.CommandId, + Exception = e.ToString() + }; + } } - catch (Exception e) + + private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + ICallRequest command) { - return new ExceptionCommandExecution + var tokenSource = new CancellationTokenSource(); + var token = tokenSource.Token; + try { - Id = command.Id, CommandId = command.CommandId, - Exception = e.ToString() - }; + var result = + (Task)currentCommand.Invoke(context, parameter is null ? new object[] { token } : new[] + { parameter, token })!; + + result.Wait(token); + + var finalResult = result.GetType().GetProperty("Result")?.GetValue(result); + return new TypedFinalCommandExecution + { + Id = command.Id, + Result = finalResult, + CommandId = command.CommandId, + Type = finalResult?.GetType() + }; + } + catch (Exception e) + { + return new ExceptionCommandExecution + { + Id = command.Id, CommandId = command.CommandId, + 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..61fa56c 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 class ConnectionHub : IConnectionHub + { + private readonly Dictionary _connections = new(); + private ISerializationToolkit? _serializationToolkit; - public void RegisterInteraction(INextGenerationInteractionModule interaction) - { - if (_serializationToolkit is null) - throw new NullReferenceException("Serialization toolkit is null"); + public void RegisterInteraction(INextGenerationInteractionModule interaction) + { + 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); - } + _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 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; + 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 8ee451d..2831a38 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -1,88 +1,92 @@ -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 Dictionary? _singletons; + private object?[] _storage = new object[StartupSize]; - public int ResisterObject(object o) - { - if (!_lastIndexFinder.IsCompleted) - _lastIndexFinder.Wait(); + private Task _lastIndexFinder = Task.FromResult(0); - _storage[_lastIndexFinder.Result] = o; + private const int StartupSize = 1024; + private const int GrowSize = 128; - var last = _lastIndexFinder.Result; - _lastIndexFinder = Task.Run(FindLastIndex); - return last; - } - - 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 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 void FillSingletons(params Assembly[] assembly) { - if (_storage[i] is null) - return i; + 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); } - var nextStorage = new object[_storage.Length + GrowSize]; - Array.Copy(_storage, nextStorage, _storage.Length); - _storage = nextStorage; - return _storage.Length; - } - public void Inject(T dependency) - { - } + public int ResisterObject(object o) + { + if (!_lastIndexFinder.IsCompleted) + _lastIndexFinder.Wait(); + _storage[_lastIndexFinder.Result] = o; + + var last = _lastIndexFinder.Result; + _lastIndexFinder = Task.Run(FindLastIndex); + + return last; + } + + 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 object GetSingleObject(Type type) + { + return _singletons!.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); + } + + public int GetObjectIndex(object o) + { + var index = Array.IndexOf(_storage, o); + return index == -1 ? ResisterObject(o) : index; + } + + private int FindLastIndex() + { + for (var i = 0; i < _storage.Length; i++) + { + if (_storage[i] is null) + return i; + } + + var nextStorage = new object[_storage.Length + GrowSize]; + Array.Copy(_storage, nextStorage, _storage.Length); + _storage = nextStorage; + return _storage.Length; + } + public void Inject(T dependency) + { + } + + } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index ae29e29..3bad121 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -1,50 +1,58 @@ +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 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 IContextRepository contextRepository: + _contextRepository = contextRepository; + 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 = (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.StartExtraction(); } } - - 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/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 5bcce54..5aa906a 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -1,56 +1,65 @@ +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)) - return repository; + private Dictionary _repositories = new(); + private readonly Func _produceRepository; + + public MultiClientContextRepository(Func produceRepository) + { + _produceRepository = produceRepository; + } + + private IContextRepository GetRepositoryByClientId(int clientId) + { + if (_repositories.TryGetValue(clientId, out var repository)) + return repository; - var created = produceRepository(clientId); - _repositories.Add(clientId, created); - return created; - } - public void Inject(T dependency) - { - } + 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); - } + public int ResisterObject(object o) + { + return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o); + } - public void ClearObject(int id) - { - GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id); - } + public void ClearObject(int id) + { + GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id); + } - public object GetObject(int id) - { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(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? GetObject(int id) + { + return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); + } - public object GetSingleObject(Type type) - { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetSingleObject(type); - } + 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 int GetObjectIndex(object o) + { + return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObjectIndex(o); + } - public IContextRepository GetRepository(int clientId) - { - return GetRepositoryByClientId(clientId); + public IContextRepository GetRepository(int clientId) + { + return GetRepositoryByClientId(clientId); + } } } \ 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 c62cfc1..aeba65c 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -1,89 +1,91 @@ -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 Type? _interactionModuleType; + private readonly IInjectableModule[]? _injectableModules; + 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.PostMessage(new NetworkMessage + while (true) { - Id = Guid.NewGuid(), SchemaId = MessageType.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(); + } + + private void HandleIncomingConnections() + { + if (_hub is null) + throw new NullReferenceException("Hub module is null"); + if (_tcpListener == null) + throw new NullReferenceException("TcpListener is null"); + if (_injectableModules is null) + throw new NullReferenceException("InjectableModules is null"); + if (_interactionModuleType is null) + throw new NullReferenceException("InteractionModuleType is null"); + if (_serialization is null) + throw new NullReferenceException("Serialization is null"); + + while (true) + { + var client = _tcpListener.AcceptTcpClient(); + 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 IdAssingnment { Id = interaction.ConnectionId }) + }); + _hub.RegisterInteraction(interaction); + Console.WriteLine("Client registered"); + } + } + + public void Inject(T dependency) + { + if (dependency is IConnectionHub interactionModule) + _hub = interactionModule; + if (dependency is ISerializationToolkit serializationToolkit) + _serialization = serializationToolkit; + } } } \ 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..8a24b42 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -1,24 +1,26 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; // 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; } + int ObjectId { get; } + object? Parameter { get; } + } -public class DefaultCallRequest : ICallRequest -{ - public Guid Id { get; set; } = Guid.NewGuid(); - public int CommandId { get; init; } - public int ObjectId { get; init; } = -1; + public class DefaultCallRequest : ICallRequest + { + public Guid Id { get; set; } = Guid.NewGuid(); + public int CommandId { get; set; } + public int ObjectId { get; set; } = -1; - [JsonIgnore] - public Type? ParameterType { get; init; } - public object? Parameter { get; set; } + [JsonIgnore] + public Type? ParameterType { get; set; } + public object? Parameter { get; set; } + } } \ No newline at end of file diff --git a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs index 772fa05..c9d32ab 100644 --- a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs @@ -1,17 +1,19 @@ -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 int ClientId { get; set; } + public int CommandId { 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..5fa3f31 100644 --- a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs @@ -1,20 +1,22 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; 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; } + [JsonIgnore] + public int ClientId { get; set; } + [JsonIgnore] + public int CommandId { 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 index 813accc..b998737 100644 --- a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs @@ -1,10 +1,12 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; -namespace mROA.Implementation.CommandExecution; - -public class TypedFinalCommandExecution : FinalCommandExecution +namespace mROA.Implementation.CommandExecution { - [JsonIgnore] - // ReSharper disable once UnusedAutoPropertyAccessor.Global - public Type? Type { get; set; } + 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/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs index 0b79371..667c2f4 100644 --- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs +++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs @@ -1,40 +1,42 @@ -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); + foreach (var creationModule in _creationModules) + produced.Inject(creationModule); - produced.Inject(_hub.GetInteracion(id)); + produced.Inject(_hub.GetInteracion(id)); - return produced; + return produced; + } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs index dce21a4..98bae9a 100644 --- a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs +++ b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs @@ -1,6 +1,8 @@ -namespace mROA.Implementation.Frontend; +using System; -// public class JsonFrontendSerialisationModule +namespace mROA.Implementation.Frontend +{ + // public class JsonFrontendSerialisationModule // : ISerialisationModule.IFrontendSerialisationModule // { // private IInteractionModule.IFrontendInteractionModule? _interactionModule; @@ -77,8 +79,16 @@ namespace mROA.Implementation.Frontend; // } // } -public class RemoteException(string error) : Exception -{ - public Guid CallRequestId; - public override string Message => $"Error in request {CallRequestId} : {error}"; + 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/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index a5f4a16..53da9fc 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -1,43 +1,51 @@ +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) + private readonly TcpClient _tcpClient = new(); + private NextGenerationInteractionModule? _interactionModule; + private ISerializationToolkit? _serialization; + private readonly IPEndPoint _ipEndPoint; + + public NetworkFrontendBridge(IPEndPoint ipEndPoint) { - case NextGenerationInteractionModule interactionModule: - _interactionModule = interactionModule; - break; - case ISerializationToolkit toolkit: - _serialization = toolkit; - break; + _ipEndPoint = ipEndPoint; } - } - public void Connect() - { - if (_interactionModule is null) - throw new Exception("Interaction module was not injected"); - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is not initialized"); + 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()}"); - } + _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()}"); + } - TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize(welcomeMessage.Data)!.Id); + TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize(welcomeMessage.Data)!.Id); + } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 486a61b..5cfb0b6 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,88 +1,92 @@ +using System; +using System.Linq; +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 IRepresentationModule? _representationModule; + private IContextRepository? _contextRepository; + private IMethodRepository? _methodRepository; + private IExecuteModule? _executeModule; + 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 - { - while (true) + switch (dependency) { - var request = - _representationModule!.GetMessage(messageType: MessageType.CallRequest); - - // Console.WriteLine("Executing {0}", 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 - ? MessageType.FinishedCommandExecution - : MessageType.ExceptionCommandExecution; - - _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + 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; } } - catch + + 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 + { + while (true) + { + var request = + _representationModule!.GetMessage(messageType: MessageType.CallRequest); + + // Console.WriteLine("Executing {0}", 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 + ? MessageType.FinishedCommandExecution + : MessageType.ExceptionCommandExecution; + + _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + } + } + catch + { + multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); + } } } } \ 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/IdAssingnment.cs b/mROA/Implementation/IdAssingnment.cs index 5cdb944..dfb634b 100644 --- a/mROA/Implementation/IdAssingnment.cs +++ b/mROA/Implementation/IdAssingnment.cs @@ -1,6 +1,7 @@ -namespace mROA.Implementation; - -public class IdAssingnment +namespace mROA.Implementation { - public int Id { get; set; } + 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/MethodRepository.cs b/mROA/Implementation/MethodRepository.cs index d429229..020f7fc 100644 --- a/mROA/Implementation/MethodRepository.cs +++ b/mROA/Implementation/MethodRepository.cs @@ -1,43 +1,47 @@ -using System.Reflection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; using mROA.Abstract; using mROA.Implementation.Attributes; -namespace mROA.Implementation; - -public class MethodRepository : IMethodRepository +namespace mROA.Implementation { - private readonly List _methods = []; - - public MethodInfo GetMethod(int id) + public class MethodRepository : IMethodRepository { - if (_methods.Count <= id) - throw new Exception("Method such registered method"); + private readonly List _methods = new() { }; - 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) + public MethodInfo GetMethod(int id) { - foreach (var method in type.GetMethods()) - RegisterMethod(method); + 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) + { + } } - public void Inject(T dependency) - { - - } } \ No newline at end of file diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 9b524f8..2ccda17 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -1,18 +1,20 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; // ReSharper disable UnusedMember.Global -namespace mROA.Implementation; - -public class NetworkMessage +namespace mROA.Implementation { - public Guid Id { get; init; } - [JsonConverter(typeof(JsonStringEnumConverter))] - public MessageType SchemaId { get; init; } + public class NetworkMessage + { + public Guid Id { get; set; } + [JsonConverter(typeof(JsonStringEnumConverter))] + public MessageType SchemaId { get; set; } - public required byte[] Data { get; init; } -} + public byte[] Data { get; set; } + } -public enum MessageType -{ - Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning + public enum MessageType + { + Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning + } } \ No newline at end of file diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 0036eda..0f3f253 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -1,87 +1,95 @@ -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; } - private Task? _currentReceiving; - private const int BufferSize = ushort.MaxValue; - private readonly Memory _buffer = new byte[BufferSize]; - private readonly List _messageBuffer = new (128); - - - public void Inject(T dependency) + public class NextGenerationInteractionModule : INextGenerationInteractionModule { - switch (dependency) + private ISerializationToolkit? _serialization; + public int ConnectionId { get; private set; } + public Stream? BaseStream { get; set; } + private Task? _currentReceiving; + private const int BufferSize = ushort.MaxValue; + private readonly Memory _buffer = new byte[BufferSize]; + private readonly List _messageBuffer = new (128); + + + public void Inject(T dependency) { - case ISerializationToolkit toolkit: - _serialization = toolkit; - break; - case IIdentityGenerator identityGenerator: - ConnectionId = identityGenerator.GetNextIdentity(); - break; + switch (dependency) + { + case ISerializationToolkit toolkit: + _serialization = toolkit; + break; + case IIdentityGenerator identityGenerator: + ConnectionId = identityGenerator.GetNextIdentity(); + break; + } + } + + 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[] 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.Slice(0, len); + await BaseStream.ReadExactlyAsync(localSpan); + + // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); + + var message = _serialization.Deserialize(localSpan.Span); + _messageBuffer.Add(message!); + _currentReceiving = 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[] UnhandledMessages => _messageBuffer.ToArray(); - public NetworkMessage? FirstByFilter(Predicate predicate) - { - return _messageBuffer.FirstOrDefault(m => predicate(m)); - } - - private NetworkMessage 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 len = BitConverter.ToUInt16([(byte)BaseStream.ReadByte(), (byte)BaseStream.ReadByte()]); - var localSpan = _buffer.Span.Slice(0, len); - BaseStream.ReadExactly(localSpan); - - // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); - - var message = _serialization.Deserialize(localSpan); - _messageBuffer.Add(message!); - _currentReceiving = Task.Run(GetNextMessage); - - return message!; - } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 37eac71..0b7611d 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -1,57 +1,59 @@ -using System.Collections.Frozen; +using System; +using System.Collections.Generic; 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(); - } - - public void ClearObject(int id) - { - throw new NotSupportedException(); - } - - 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 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) + private IRepresentationModuleProducer? _representationProducer; + public static Dictionary RemoteTypes = new(); + public int ResisterObject(object o) { - return remote.Id; + throw new NotSupportedException(); } - throw new NotSupportedException(); - } - public void Inject(T dependency) - { - if (dependency is IRepresentationModuleProducer serialisationModule) - _representationProducer = serialisationModule; + public void ClearObject(int id) + { + throw new NotSupportedException(); + } + + 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 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) + { + 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 6a813f2..69e2657 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -1,53 +1,64 @@ -using mROA.Abstract; +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 { - var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = id, Parameter = parameter, ParameterType = parameter?.GetType() }; - await representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); + private readonly int _id; + private readonly IRepresentationModule _representationModule; - var successResponse = - representationModule.GetMessageAsync>( - messageType: MessageType.FinishedCommandExecution, requestId: request.Id); - var errorResponse = - representationModule.GetMessageAsync( - messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); - Task.WaitAny(successResponse, errorResponse); + protected RemoteObjectBase(int id, IRepresentationModule representationModule) + { + _id = id; + _representationModule = representationModule; + } - if (successResponse.IsCompletedSuccessfully) - return successResponse.Result.Result!; + public int Id => _id; + public int OwnerId => _representationModule.Id; - throw errorResponse.Result.GetException(); - } + protected async Task GetResultAsync(int methodId, object? parameter = default) + { + var request = new DefaultCallRequest + { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); - 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, MessageType.CallRequest, request); + var successResponse = + _representationModule.GetMessageAsync>( + messageType: MessageType.FinishedCommandExecution, requestId: request.Id); + var errorResponse = + _representationModule.GetMessageAsync( + messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); + Task.WaitAny(successResponse, errorResponse); - var successResponse = - representationModule.GetMessageAsync( - messageType: MessageType.FinishedCommandExecution, requestId: request.Id); - var errorResponse = - representationModule.GetMessageAsync( - messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); + if (successResponse.IsCompletedSuccessfully) + return successResponse.Result.Result!; - Task.WaitAny(successResponse, errorResponse); + throw errorResponse.Result.GetException(); + } - if (successResponse.IsCompletedSuccessfully) - return; + 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, MessageType.CallRequest, request); - throw errorResponse.Result.GetException(); + var successResponse = + _representationModule.GetMessageAsync( + messageType: MessageType.FinishedCommandExecution, requestId: request.Id); + var errorResponse = + _representationModule.GetMessageAsync( + messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); + + Task.WaitAny(successResponse, errorResponse); + + if (successResponse.IsCompletedSuccessfully) + return; + + throw errorResponse.Result.GetException(); + } } } \ No newline at end of file diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 4a119b9..b6e0ce7 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -1,93 +1,96 @@ -using mROA.Abstract; +using System; +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 ISerializationToolkit? _serialization; + private INextGenerationInteractionModule? _interaction; + + 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, MessageType? messageType) - { - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is not initialized"); - - return _serialization.Deserialize(await GetRawMessage(requestId, messageType))!; - } - - public T GetMessage(Guid? requestId = null, MessageType? messageType = null) - { - if (_serialization == null) - throw new NullReferenceException("Serialization toolkit is not initialized"); - - return _serialization.Deserialize(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!; - } - - public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null) - { - if (_interaction == null) - throw new NullReferenceException("Interaction toolkit is not initialized"); - - var fromBuffer = - _interaction.FirstByFilter(message => - (requestId is null || message.Id == requestId) && - (messageType is null || message.SchemaId == messageType)); - - if (fromBuffer == null) - { - while (true) + switch (dependency) { - var message = await _interaction.GetNextMessageReceiving(); - if ((requestId is not null && message.Id != requestId) || - (messageType is not null && message.SchemaId != messageType)) continue; - - _interaction.HandleMessage(message); - return message.Data; + case ISerializationToolkit toolkit: + _serialization = toolkit; + break; + case INextGenerationInteractionModule interactionModule: + _interaction = interactionModule; + break; } } - _interaction.HandleMessage(fromBuffer); - return fromBuffer.Data; - } + public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId; - 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"); + public async Task GetMessageAsync(Guid? requestId, MessageType? messageType) + { + if (_serialization == null) + throw new NullReferenceException("Serialization toolkit is not initialized"); - await _interaction.PostMessage(new NetworkMessage - { Id = id, SchemaId = messageType, Data = _serialization.Serialize(payload, payloadType) }); - } + return _serialization.Deserialize(await GetRawMessage(requestId, messageType))!; + } - public void PostCallMessage(Guid id, MessageType messageType, T payload) where T : notnull - { - PostCallMessageAsync(id, messageType, payload).GetAwaiter().GetResult(); - } + public T GetMessage(Guid? requestId = null, MessageType? messageType = null) + { + if (_serialization == null) + throw new NullReferenceException("Serialization toolkit is not initialized"); + + return _serialization.Deserialize(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!; + } - public void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType) - { - PostCallMessageAsync(id, messageType, payload, payloadType).GetAwaiter().GetResult(); + public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null) + { + if (_interaction == null) + throw new NullReferenceException("Interaction toolkit is not initialized"); + + var fromBuffer = + _interaction.FirstByFilter(message => + (requestId is null || message.Id == requestId) && + (messageType is null || message.SchemaId == messageType)); + + if (fromBuffer == null) + { + while (true) + { + var message = await _interaction.GetNextMessageReceiving(); + if ((requestId is not null && message.Id != requestId) || + (messageType is not null && message.SchemaId != messageType)) continue; + + _interaction.HandleMessage(message); + return message.Data; + } + } + + _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"); + + await _interaction.PostMessage(new NetworkMessage + { Id = id, SchemaId = messageType, Data = _serialization.Serialize(payload, payloadType) }); + } + + 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/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 644b8f4..cf44c46 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -1,101 +1,103 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; using mROA.Abstract; // ReSharper disable UnusedMember.Global #pragma warning disable CS8618, CS9264 -namespace mROA.Implementation; - -public static class TransmissionConfig +namespace mROA.Implementation { - private static IContextRepository? _realContextRepository; - private static IContextRepository? _remoteEndpointContextRepository; - private static IOwnershipRepository? _ownershipRepository; - - public static IContextRepository RealContextRepository + public static class TransmissionConfig { - get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); - set => _realContextRepository = value; - } + private static IContextRepository? _realContextRepository; + private static IContextRepository? _remoteEndpointContextRepository; + private static IOwnershipRepository? _ownershipRepository; - 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 + public static IContextRepository RealContextRepository { - _ownerId = _ownerId == -1 ? TransmissionConfig.OwnershipRepository.GetOwnershipId() : _ownerId; - return _ownerId; + get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); + set => _realContextRepository = value; } - init => _ownerId = 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; + } + } - // ReSharper disable once MemberCanBePrivate.Global - public int ContextId + public class SharedObject where T : notnull { - // ReSharper disable once UnusedMember.Global - get + 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 { - if (_contextId != -2) + get + { + _ownerId = _ownerId == -1 ? TransmissionConfig.OwnershipRepository.GetOwnershipId() : _ownerId; + return _ownerId; + } + set => _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; - - _contextId = TransmissionConfig.RealContextRepository.GetObjectIndex(Value); - return _contextId; + } + set + { + _contextId = value; + Value = GetDefaultContextRepository().GetObject(_contextId)!; + } } - init + + [JsonIgnore] public T Value { get; private set; } + + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedMember.Global + public SharedObject() { - _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) + // ReSharper disable once UnusedMember.Global + public SharedObject(T value) { - _ownerId = ro.OwnerId; - _contextId = ro.Id; + Value = value; + + if (value is RemoteObjectBase ro) + { + _ownerId = ro.OwnerId; + _contextId = ro.Id; + } + else + _ownerId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(); } - else - _ownerId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(); + + public static implicit operator T(SharedObject value) => value.Value; + + public static implicit operator SharedObject(T value) => + new(value); } - - 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/StaticRepresentationModuleProducer.cs b/mROA/Implementation/StaticRepresentationModuleProducer.cs index 8b0632a..188bfec 100644 --- a/mROA/Implementation/StaticRepresentationModuleProducer.cs +++ b/mROA/Implementation/StaticRepresentationModuleProducer.cs @@ -1,21 +1,23 @@ -using mROA.Abstract; +using System; +using mROA.Abstract; -namespace mROA.Implementation; - -public class StaticRepresentationModuleProducer : IRepresentationModuleProducer +namespace mROA.Implementation { - private IRepresentationModule? _representationModule; + public class StaticRepresentationModuleProducer : IRepresentationModuleProducer + { + private IRepresentationModule? _representationModule; - public IRepresentationModule Produce(int ownership) - { - if (_representationModule == null) - throw new NullReferenceException("The representation module is not initialized."); - return _representationModule; - } + public IRepresentationModule Produce(int ownership) + { + if (_representationModule == null) + throw new NullReferenceException("The representation module is not initialized."); + return _representationModule; + } - public void Inject(T dependency) - { - if (dependency is IRepresentationModule serialisationModule) - _representationModule = serialisationModule; + public void Inject(T dependency) + { + if (dependency is IRepresentationModule serialisationModule) + _representationModule = serialisationModule; + } } } \ No newline at end of file diff --git a/mROA/LegacyExtentions.cs b/mROA/LegacyExtentions.cs new file mode 100644 index 0000000..d35c5a9 --- /dev/null +++ b/mROA/LegacyExtentions.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using global::System; +using global::System.IO; +using global::System.Threading; +using global::System.Threading.Tasks; + +namespace mROA +{ + public static class LegacyExtentions + { + public static async ValueTask ReadExactlyAsync(this Stream stream, byte[] buffer, int offset, int count) + { + return await stream.ReadAtLeastAsyncCore(buffer.AsMemory(offset, count), count, true, default); + } + + public static ValueTask ReadExactlyAsync(this Stream stream, Memory buffer, + CancellationToken cancellationToken = default(CancellationToken)) + { + return stream.ReadAtLeastAsyncCore(buffer, buffer.Length, true, cancellationToken); + } + + private static async ValueTask ReadAtLeastAsyncCore(this Stream stream, + Memory buffer, + int minimumBytes, + bool throwOnEndOfStream, + CancellationToken cancellationToken) + { + int totalRead; + int num; + for (totalRead = 0; totalRead < minimumBytes; totalRead += num) + { + num = await stream.ReadAsync(buffer.Slice(totalRead), cancellationToken).ConfigureAwait(false); + if (num == 0) + { + if (throwOnEndOfStream) + throw new EndOfStreamException(); + return totalRead; + } + } + return totalRead; + } + } +} \ No newline at end of file diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 2ab4205..a436d48 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -1,8 +1,7 @@  - net9.0 - enable + netstandard2.1 enable mROA 2.0.0 @@ -12,6 +11,11 @@ https://github.com/YaslePoy/mROA git RPC + 9 + + + + From ca2a04b88e2516dbe9e6c57fcb73557705e1f6a4 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 20 Feb 2025 22:23:52 +0300 Subject: [PATCH 02/66] =?UTF-8?q?=D0=BE=D0=BF=D1=8F=D1=82=D1=8C=20=D0=B4?= =?UTF-8?q?=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D1=82=D0=BE?= =?UTF-8?q?=D0=BA=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BE=D0=B1=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=BA=D1=83=20=D1=81=D0=BE=D0=BE=D0=B1=D1=89?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Example.Frontend.csproj | 2 +- Example.Shared/Example.Shared.csproj | 2 +- mROA/Abstract/ISerialisationModule.cs | 6 ++++-- .../Implementation/Frontend/RequestExtractor.cs | 2 +- .../NextGenerationInteractionModule.cs | 4 ++-- mROA/Implementation/RemoteObjectBase.cs | 17 ++++++++++++----- mROA/Implementation/RepresentationModule.cs | 9 +++++---- 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index e4d8f0d..35760b9 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -2,7 +2,7 @@ Exe - netstandard2.1 + net9.0 enable diff --git a/Example.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj index 37ad63a..3d97856 100644 --- a/Example.Shared/Example.Shared.csproj +++ b/Example.Shared/Example.Shared.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net9.0 enable diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/ISerialisationModule.cs index 02292c2..a25e00e 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/ISerialisationModule.cs @@ -1,5 +1,7 @@ using System; +using System.Threading; using System.Threading.Tasks; +using System.Windows.Input; using mROA.Implementation; using mROA.Implementation.CommandExecution; @@ -22,9 +24,9 @@ namespace mROA.Abstract public interface IRepresentationModule : IInjectableModule { int Id { get; } - Task GetMessageAsync(Guid? requestId = null, MessageType? messageType = null); + 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); + 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); diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 5cfb0b6..7716314 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -85,7 +85,7 @@ namespace mROA.Implementation.Frontend } catch { - multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); + multiClientOwnershipRepository?.FreeOwnership(); } } } diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 0f3f253..72402b9 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -34,7 +34,7 @@ namespace mROA.Implementation public Task GetNextMessageReceiving() { if (_currentReceiving != null) return _currentReceiving; - _currentReceiving = Task.Run(GetNextMessage); + _currentReceiving = Task.Run(async () => await GetNextMessage()); return _currentReceiving; } @@ -87,7 +87,7 @@ namespace mROA.Implementation var message = _serialization.Deserialize(localSpan.Span); _messageBuffer.Add(message!); - _currentReceiving = GetNextMessage(); + _currentReceiving = Task.Run(async () => await GetNextMessage()); return message!; } diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 69e2657..2da6cbe 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.CommandExecution; @@ -26,16 +27,22 @@ namespace mROA.Implementation { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); + var localTokenSource = new CancellationTokenSource(); + var successResponse = - _representationModule.GetMessageAsync>( - messageType: MessageType.FinishedCommandExecution, requestId: request.Id); + _representationModule.GetMessageAsync>(request.Id, + MessageType.FinishedCommandExecution, + localTokenSource.Token); var errorResponse = - _representationModule.GetMessageAsync( - messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); + _representationModule.GetMessageAsync(requestId: request.Id, + MessageType.ExceptionCommandExecution, localTokenSource.Token); + Task.WaitAny(successResponse, errorResponse); if (successResponse.IsCompletedSuccessfully) + { return successResponse.Result.Result!; + } throw errorResponse.Result.GetException(); } diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index b6e0ce7..dcba18f 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -24,12 +25,12 @@ namespace mROA.Implementation public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId; - public async Task GetMessageAsync(Guid? requestId, MessageType? messageType) + public async Task GetMessageAsync(Guid? requestId, MessageType? messageType, CancellationToken token = default) { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - return _serialization.Deserialize(await GetRawMessage(requestId, messageType))!; + return _serialization.Deserialize(await GetRawMessage(requestId, messageType, token))!; } public T GetMessage(Guid? requestId = null, MessageType? messageType = null) @@ -40,7 +41,7 @@ namespace mROA.Implementation return _serialization.Deserialize(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!; } - public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null) + public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null, CancellationToken token = default) { if (_interaction == null) throw new NullReferenceException("Interaction toolkit is not initialized"); @@ -52,7 +53,7 @@ namespace mROA.Implementation if (fromBuffer == null) { - while (true) + while (token.IsCancellationRequested == false) { var message = await _interaction.GetNextMessageReceiving(); if ((requestId is not null && message.Id != requestId) || From a887b614c76f9bfeff4d3eef4a6e993be147dc7c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 21 Feb 2025 18:59:02 +0300 Subject: [PATCH 03/66] =?UTF-8?q?=D1=84=D1=80=D0=BE=D0=BD=D1=82=D0=B5?= =?UTF-8?q?=D0=BD=D0=B4=20=D0=B4=D0=BB=D1=8F=20=D0=BE=D1=82=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 28 +++++++-------- mROA/Implementation/NetworkMessage.cs | 2 +- mROA/Implementation/RemoteObjectBase.cs | 47 +++++++++++++++++++------ 3 files changed, 51 insertions(+), 26 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index ca2ac99..b9bf3a7 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -69,19 +69,19 @@ class Program var data = page.Value.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); - var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; - - 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"); + // var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; + // + // 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/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 2ccda17..6cb302b 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -15,6 +15,6 @@ namespace mROA.Implementation public enum MessageType { - Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning + Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning, CancelRequest } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 2da6cbe..62bcf76 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -20,8 +20,9 @@ namespace mROA.Implementation public int Id => _id; public int OwnerId => _representationModule.Id; - - protected async Task GetResultAsync(int methodId, object? parameter = default) + + protected async Task GetResultAsync(int methodId, object? parameter = default, + CancellationToken cancellationToken = default) { var request = new DefaultCallRequest { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; @@ -37,30 +38,54 @@ namespace mROA.Implementation _representationModule.GetMessageAsync(requestId: request.Id, MessageType.ExceptionCommandExecution, localTokenSource.Token); - Task.WaitAny(successResponse, errorResponse); + Task.WaitAny(new Task[] + { + successResponse, errorResponse + }, cancellationToken); + + if (cancellationToken.IsCancellationRequested) + { + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); + cancellationToken.ThrowIfCancellationRequested(); + } if (successResponse.IsCompletedSuccessfully) { + localTokenSource.Cancel(); return successResponse.Result.Result!; } + localTokenSource.Cancel(); throw errorResponse.Result.GetException(); } - protected async Task CallAsync(int methodId, object? parameter = default) + protected async Task CallAsync(int methodId, object? parameter = default, + CancellationToken cancellationToken = default) { var request = new DefaultCallRequest { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); - var successResponse = - _representationModule.GetMessageAsync( - messageType: MessageType.FinishedCommandExecution, requestId: request.Id); - var errorResponse = - _representationModule.GetMessageAsync( - messageType: MessageType.ExceptionCommandExecution, requestId: request.Id); + var localTokenSource = new CancellationTokenSource(); - Task.WaitAny(successResponse, errorResponse); + var successResponse = + _representationModule.GetMessageAsync(request.Id, + MessageType.FinishedCommandExecution, + localTokenSource.Token); + var errorResponse = + _representationModule.GetMessageAsync(requestId: request.Id, + MessageType.ExceptionCommandExecution, localTokenSource.Token); + + Task.WaitAny(new Task[] + { + successResponse, errorResponse + }, cancellationToken); + + if (cancellationToken.IsCancellationRequested) + { + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); + cancellationToken.ThrowIfCancellationRequested(); + } if (successResponse.IsCompletedSuccessfully) return; From c71585b100e58de82935fd4bceb53b099cff55e4 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 22 Feb 2025 09:28:59 +0300 Subject: [PATCH 04/66] =?UTF-8?q?=D0=91=D1=8D=D0=BA=D0=B5=D0=BD=D0=B4=20?= =?UTF-8?q?=D0=BE=D1=82=D0=BC=D0=B5=D0=BD=D1=8B=20=D0=B7=D0=B0=D0=B4=D0=B0?= =?UTF-8?q?=D1=87=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 3 +- Example.Backend/LoadTestImp.cs | 7 ++ Example.Backend/Program.cs | 3 +- Example.Frontend/Program.cs | 1 + Example.Shared/ILoadTest.cs | 6 +- mROA.Codegen/mROASourceGenerator.cs | 22 +++-- mROA/Abstract/ICancellationRepository.cs | 12 +++ mROA/Abstract/IExecuteModule.cs | 2 +- .../Backend/BasicExecutionModule.cs | 81 +++++++++++++------ mROA/Implementation/CancellationRepository.cs | 31 +++++++ .../ExceptionCommandExecution.cs | 7 ++ .../Frontend/RequestExtractor.cs | 2 +- 12 files changed, 141 insertions(+), 36 deletions(-) create mode 100644 mROA/Abstract/ICancellationRepository.cs create mode 100644 mROA/Implementation/CancellationRepository.cs diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index fc4e81b..3eac518 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -2,7 +2,8 @@ Exe - netstandard2.1 + + net9.0 enable diff --git a/Example.Backend/LoadTestImp.cs b/Example.Backend/LoadTestImp.cs index bc22304..e980aae 100644 --- a/Example.Backend/LoadTestImp.cs +++ b/Example.Backend/LoadTestImp.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Example.Shared; using mROA.Implementation.Attributes; @@ -26,5 +28,10 @@ namespace Example.Backend { throw new NotImplementedException(); } + + public async Task AsyncTest(CancellationToken token) + { + await Task.Delay(TimeSpan.FromSeconds(5), token); + } } } \ No newline at end of file diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 0a8315a..06bec62 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -34,7 +34,8 @@ class Program builder.Modules.Add(new CreativeRepresentationModuleProducer( new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); - + builder.Modules.Add(new CancellationRepository()); + builder.Build(); new RemoteTypeBinder(); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index b9bf3a7..63a25b2 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -47,6 +47,7 @@ class Program var name = printer.Value.GetName(); Console.WriteLine("Printer name : {0}", name); + Thread.Sleep(100); factory.Register(new SharedObject(new ClientBasedPrinter())); diff --git a/Example.Shared/ILoadTest.cs b/Example.Shared/ILoadTest.cs index 326822f..e9f958f 100644 --- a/Example.Shared/ILoadTest.cs +++ b/Example.Shared/ILoadTest.cs @@ -1,4 +1,6 @@ -using mROA.Implementation.Attributes; +using System.Threading; +using System.Threading.Tasks; +using mROA.Implementation.Attributes; namespace Example.Shared { @@ -9,6 +11,8 @@ namespace Example.Shared int Last(int next); void C(); void A(); + + Task AsyncTest(CancellationToken token = default); } } diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index db252ae..84fef04 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -120,7 +121,8 @@ namespace {Namespace} bool isAsync = method.ReturnType.Name == "Task"; - bool isVoid = method.ReturnType.Name == "Void" || method.ReturnType.ToString() == "Task"; + bool isVoid = method.ReturnType.Name == "Void" || + method.ReturnType.ToString() == "System.Threading.Tasks.Task"; bool isParametrized = method.Parameters.Length == 1 && !isAsync || method.Parameters.Length == 2 && isAsync; @@ -135,9 +137,16 @@ namespace {Namespace} 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})"; + var tokenInsert = isAsync + ? isParametrized + ? ", cancellationToken : " + method.Parameters[1].Name + : ", cancellationToken : " + method.Parameters[0].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; @@ -195,7 +204,6 @@ namespace {namespaceName} "; - // Add the source code to the compilation. context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); @@ -250,7 +258,7 @@ namespace mROA.Codegen "; context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); } - + if (frontendContextRepo.Count != 0) { var fronendRepoCode = @$"// @@ -324,7 +332,7 @@ namespace mROA.Codegen GenerateCode(context, context.Compilation, interfaces.ToImmutableArray()); } - + private bool ContainsSOIAttribute(SyntaxList attributes, GeneratorExecutionContext context, InterfaceDeclarationSyntax interfaceDeclarationSyntax) { 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/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs index 2ebdd24..29f5211 100644 --- a/mROA/Abstract/IExecuteModule.cs +++ b/mROA/Abstract/IExecuteModule.cs @@ -4,6 +4,6 @@ namespace mROA.Abstract { public interface IExecuteModule : IInjectableModule { - ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository); + ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, IRepresentationModule representationModule); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 8f5ac39..ec57413 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -10,20 +10,26 @@ namespace mROA.Implementation.Backend public class BasicExecutionModule : IExecuteModule { private IMethodRepository? _methodRepo; + private ICancellationRepository? _cancellationRepo; public void Inject(T dependency) { if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo; + if (dependency is ICancellationRepository cancellationRepo) _cancellationRepo = cancellationRepo; } - public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository) + public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, + IRepresentationModule representationModule) { + 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"); - + var currentCommand = _methodRepo.GetMethod(command.CommandId); if (currentCommand == null) throw new Exception($"Command {command.CommandId} not found"); @@ -35,10 +41,10 @@ namespace mROA.Implementation.Backend if (currentCommand.ReturnType.BaseType == typeof(Task) && currentCommand.ReturnType.GenericTypeArguments.Length == 1) - return TypedExecuteAsync(currentCommand, context, parameter, command); + return TypedExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); if (currentCommand.ReturnType == typeof(Task)) - return ExecuteAsync(currentCommand, context, parameter, command); + return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); return Execute(currentCommand, context, parameter, command); } @@ -48,8 +54,10 @@ namespace mROA.Implementation.Backend { try { - var finalResult = currentCommand.Invoke(context, parameter is null ? new object[0] : new[] - { parameter }); + var finalResult = currentCommand.Invoke(context, parameter is null + ? new object[0] + : new[] + { parameter }); return new TypedFinalCommandExecution { CommandId = command.CommandId, Result = finalResult, @@ -68,20 +76,34 @@ namespace mROA.Implementation.Backend } private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command) + ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) { var tokenSource = new CancellationTokenSource(); + cancellationRepository.RegisterCancellation(command.Id, tokenSource); var token = tokenSource.Token; try { - var result = (Task)currentCommand.Invoke(context, parameter is null ? new object[] { token } : new[] - { parameter, token })!; + var result = (Task)currentCommand.Invoke(context, parameter is null + ? new object[] { token } + : new[] + { parameter, token })!; - result.Wait(token); + result.ContinueWith(_ => + { + var payload = new FinalCommandExecution + { + Id = command.Id, + CommandId = command.CommandId + }; + representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); + }, token); - - return new FinalCommandExecution { CommandId = command.CommandId, Id = command.Id }; + return new AsyncCommandExecution + { + Id = command.Id, CommandId = command.CommandId + }; + } catch (Exception e) { @@ -94,25 +116,36 @@ namespace mROA.Implementation.Backend } private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command) + ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) { var tokenSource = new CancellationTokenSource(); + cancellationRepository.RegisterCancellation(command.Id, tokenSource); + var token = tokenSource.Token; try { var result = - (Task)currentCommand.Invoke(context, parameter is null ? new object[] { token } : new[] - { parameter, token })!; + (Task)currentCommand.Invoke(context, parameter is null + ? new object[] { token } + : new[] + { parameter, token })!; - result.Wait(token); - - var finalResult = result.GetType().GetProperty("Result")?.GetValue(result); - return new TypedFinalCommandExecution + result.ContinueWith(t => { - Id = command.Id, - Result = finalResult, - CommandId = command.CommandId, - Type = finalResult?.GetType() + var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); + var payload = new TypedFinalCommandExecution + { + Id = command.Id, + Result = finalResult, + CommandId = command.CommandId, + Type = finalResult?.GetType() + }; + representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); + }, token); + + return new AsyncCommandExecution + { + Id = command.Id, CommandId = command.CommandId }; } catch (Exception e) diff --git a/mROA/Implementation/CancellationRepository.cs b/mROA/Implementation/CancellationRepository.cs new file mode 100644 index 0000000..3c5659e --- /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/ExceptionCommandExecution.cs b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs index c9d32ab..6d18129 100644 --- a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs @@ -16,4 +16,11 @@ namespace mROA.Implementation.CommandExecution return new RemoteException(Exception) { CallRequestId = Id }; } } + + public class AsyncCommandExecution : ICommandExecution + { + public Guid Id { get; set; } + public int ClientId { get; set; } + public int CommandId { get; set; } + } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 7716314..25232bb 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -74,7 +74,7 @@ namespace mROA.Implementation.Frontend request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType); } - var result = _executeModule.Execute(request, _contextRepository); + var result = _executeModule.Execute(request, _contextRepository, _representationModule); var resultType = result is FinalCommandExecution ? MessageType.FinishedCommandExecution From 348947fb4c2a408ee1ff175f0f030b0a47ad7d87 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 22 Feb 2025 09:44:48 +0300 Subject: [PATCH 05/66] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B5=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D1=81=D0=BE=D0=BE=D0=B1=D1=89=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 2 ++ .../Implementation/Frontend/RequestExtractor.cs | 17 ++++++++++++++--- mROA/Implementation/NetworkMessage.cs | 2 +- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 63a25b2..842c0dd 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -27,6 +27,8 @@ class Program builder.Modules.Add(new BasicExecutionModule()); builder.Modules.Add(new CoCodegenMethodRepository()); builder.UseCollectableContextRepository(); + builder.Modules.Add(new CancellationRepository()); + builder.Build(); diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 25232bb..6d58ce6 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -76,9 +76,20 @@ namespace mROA.Implementation.Frontend var result = _executeModule.Execute(request, _contextRepository, _representationModule); - var resultType = result is FinalCommandExecution - ? MessageType.FinishedCommandExecution - : MessageType.ExceptionCommandExecution; + var resultType = MessageType.Unknown; + + switch (result) + { + case FinalCommandExecution: + resultType = MessageType.FinishedCommandExecution; + break; + case AsyncCommandExecution: + resultType = MessageType.AsyncCommandExecution; + break; + case ExceptionCommandExecution: + resultType = MessageType.ExceptionCommandExecution; + break; + } _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); } diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 6cb302b..7b04c12 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -15,6 +15,6 @@ namespace mROA.Implementation public enum MessageType { - Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning, CancelRequest + Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCommandExecution, CallRequest, IdAssigning, CancelRequest } } \ No newline at end of file From b6226b68c942fd93c41d5acd3fcb201f15be0e34 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 22 Feb 2025 10:06:41 +0300 Subject: [PATCH 06/66] =?UTF-8?q?=D0=92=D0=BE=D0=B7=D0=B2=D1=80=D0=B0?= =?UTF-8?q?=D1=89=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=BB=D0=BD=D0=BE?= =?UTF-8?q?=D0=B9=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BE=D1=81=D0=BF=D0=BE?= =?UTF-8?q?=D1=81=D0=BE=D0=B1=D0=BD=D0=BE=D1=81=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 1 + mROA/Abstract/IRequestExtractor.cs | 2 +- .../Backend/BasicExecutionModule.cs | 21 ++++++++++++++----- .../Frontend/RequestExtractor.cs | 1 + 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 842c0dd..f5323d2 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -69,6 +69,7 @@ class Program Console.WriteLine(string.Join(", ", names)); var page = printer.Value.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); + Console.WriteLine("Page printed"); var data = page.Value.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); diff --git a/mROA/Abstract/IRequestExtractor.cs b/mROA/Abstract/IRequestExtractor.cs index d49194b..30711fc 100644 --- a/mROA/Abstract/IRequestExtractor.cs +++ b/mROA/Abstract/IRequestExtractor.cs @@ -4,6 +4,6 @@ namespace mROA.Abstract { public interface IRequestExtractor : IInjectableModule { - Task StartExtraction(); + Task StartExtraction(); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index ec57413..3207c34 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -41,10 +41,12 @@ namespace mROA.Implementation.Backend if (currentCommand.ReturnType.BaseType == typeof(Task) && currentCommand.ReturnType.GenericTypeArguments.Length == 1) - return TypedExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); + return TypedExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, + representationModule); if (currentCommand.ReturnType == typeof(Task)) - return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); + return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, + representationModule); return Execute(currentCommand, context, parameter, command); } @@ -76,7 +78,8 @@ namespace mROA.Implementation.Backend } private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) + ICallRequest command, ICancellationRepository cancellationRepository, + IRepresentationModule representationModule) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -96,14 +99,17 @@ namespace mROA.Implementation.Backend Id = command.Id, CommandId = command.CommandId }; + var multiClientOwnershipRepository = + TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); + multiClientOwnershipRepository?.FreeOwnership(); }, token); return new AsyncCommandExecution { Id = command.Id, CommandId = command.CommandId }; - } catch (Exception e) { @@ -116,7 +122,8 @@ namespace mROA.Implementation.Backend } private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) + ICallRequest command, ICancellationRepository cancellationRepository, + IRepresentationModule representationModule) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -140,7 +147,11 @@ namespace mROA.Implementation.Backend CommandId = command.CommandId, Type = finalResult?.GetType() }; + var multiClientOwnershipRepository = + TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); + multiClientOwnershipRepository?.FreeOwnership(); }, token); return new AsyncCommandExecution diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 6d58ce6..fe89331 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -99,5 +99,6 @@ namespace mROA.Implementation.Frontend multiClientOwnershipRepository?.FreeOwnership(); } } + } } \ No newline at end of file From ae4979c9f9c80fe844caed28ad2dd3b2e1a94a85 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 23 Feb 2025 10:18:38 +0300 Subject: [PATCH 07/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20IDisposable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/LoadTestImp.cs | 16 +++- Example.Backend/Printer.cs | 6 ++ Example.Frontend/ClientBasedPrinter.cs | 5 ++ Example.Frontend/Program.cs | 59 +++++++++----- Example.Shared/IPrinter.cs | 3 +- mROA.Codegen/mROASourceGenerator.cs | 3 + .../Backend/BasicExecutionModule.cs | 39 ++++++++- mROA/Implementation/CallRequest.cs | 12 ++- .../Frontend/RequestExtractor.cs | 81 ++++++++++++------- .../NextGenerationInteractionModule.cs | 5 +- mROA/Implementation/RemoteObjectBase.cs | 43 +++++++--- mROA/Implementation/RepresentationModule.cs | 7 +- 12 files changed, 207 insertions(+), 72 deletions(-) diff --git a/Example.Backend/LoadTestImp.cs b/Example.Backend/LoadTestImp.cs index e980aae..a1fec60 100644 --- a/Example.Backend/LoadTestImp.cs +++ b/Example.Backend/LoadTestImp.cs @@ -31,7 +31,21 @@ namespace Example.Backend public async Task AsyncTest(CancellationToken token) { - await Task.Delay(TimeSpan.FromSeconds(5), 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/Printer.cs b/Example.Backend/Printer.cs index 59ef144..ba8c624 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; using Example.Shared; @@ -18,5 +19,10 @@ namespace Example.Backend // throw new Exception("The method or operation is not implemented."); return new Page {Text = text}; } + + public void Dispose() + { + Console.WriteLine("Dispose printer with name {0}", Name); + } } } \ No newline at end of file diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 32c3de0..00b1984 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -20,6 +20,11 @@ namespace Example.Frontend await Task.Yield(); return new ClientBasedPage(); } + + public void Dispose() + { + + } } public class ClientBasedPage : IPage diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index f5323d2..44860ad 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Net; using System.Text; using System.Threading; +using System.Threading.Tasks; using Example.Frontend; using Example.Shared; using mROA.Codegen; @@ -44,36 +45,50 @@ class Program //правильный порядок команд 8-5-10-7 var printer = factory.Create("Test"); - Console.WriteLine("Printer created"); - Thread.Sleep(100); + using (var disposingPrinter = printer.Value) + { + 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(); + 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 SharedObject(new ClientBasedPrinter())); + Console.WriteLine("Registered printer"); + Thread.Sleep(100); - var registred = factory.GetFirstPrinter(); - Console.WriteLine("First printer"); - Thread.Sleep(100); + var registred = 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(registred.Value); + 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(); - Console.WriteLine("Page printed"); - var data = page.Value.GetData(); - Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); + var page = disposingPrinter.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); + Console.WriteLine("Page printed"); + var data = page.Value.GetData(); + Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); + } - // var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; + + var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) 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}"); + Console.ReadKey(); // // const int iterations = 10000; // var timer = Stopwatch.StartNew(); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index a2c789f..6c4fe9a 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; using mROA.Implementation; @@ -6,7 +7,7 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPrinter + public interface IPrinter : IDisposable { string GetName(); Task> Print(string text, CancellationToken cancellationToken); diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 84fef04..70eefa9 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -233,6 +233,9 @@ namespace mROA.Codegen public MethodInfo GetMethod(int id) {{ + if (id == -1) + return typeof(IDisposable).GetMethod(""Dispose""); + if (_methods.Count <= id) return null; diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 3207c34..01343ca 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -21,6 +21,8 @@ namespace mROA.Implementation.Backend public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, IRepresentationModule representationModule) { + Console.WriteLine(command.GetType().Name); + if (_cancellationRepo is null) throw new NullReferenceException("Method repository was not defined"); @@ -30,6 +32,19 @@ namespace mROA.Implementation.Backend if (contextRepository is null) throw new NullReferenceException("Context repository was not defined"); + if (command is CancelRequest) + { + Console.WriteLine("Final cancelling request"); + var cts = _cancellationRepo.GetCancellation(command.Id); + cts.Cancel(); + _cancellationRepo.FreeCancelation(command.Id); + return new FinalCommandExecution + { + Id = command.Id, + CommandId = command.CommandId + }; + } + var currentCommand = _methodRepo.GetMethod(command.CommandId); if (currentCommand == null) throw new Exception($"Command {command.CommandId} not found"); @@ -48,7 +63,14 @@ namespace mROA.Implementation.Backend return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); - return Execute(currentCommand, context, parameter, command); + var result = Execute(currentCommand, context, parameter, command); + + if (command.CommandId == -1) + { + contextRepository.ClearObject(command.ObjectId); + } + + return result; } private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, @@ -57,9 +79,10 @@ namespace mROA.Implementation.Backend try { var finalResult = currentCommand.Invoke(context, parameter is null - ? new object[0] + ? Array.Empty() : new[] { parameter }); + return new TypedFinalCommandExecution { CommandId = command.CommandId, Result = finalResult, @@ -77,13 +100,14 @@ namespace mROA.Implementation.Backend } } - private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + private ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); var token = tokenSource.Token; + token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}")); try { var result = (Task)currentCommand.Invoke(context, parameter is null @@ -94,11 +118,16 @@ namespace mROA.Implementation.Backend result.ContinueWith(_ => { + if (token.IsCancellationRequested) + return; + var payload = new FinalCommandExecution { Id = command.Id, CommandId = command.CommandId }; + _cancellationRepo.FreeCancelation(command.Id); + var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); @@ -121,7 +150,7 @@ namespace mROA.Implementation.Backend } } - private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + private ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule) { @@ -147,6 +176,8 @@ namespace mROA.Implementation.Backend CommandId = command.CommandId, Type = finalResult?.GetType() }; + _cancellationRepo.FreeCancelation(command.Id); + var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 8a24b42..783cce2 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json.Serialization; + // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global @@ -18,9 +19,18 @@ namespace mROA.Implementation public Guid Id { get; set; } = Guid.NewGuid(); public int CommandId { get; set; } public int ObjectId { get; set; } = -1; - + [JsonIgnore] public Type? ParameterType { get; set; } + public object? Parameter { get; set; } } + + public class CancelRequest : ICallRequest + { + public Guid Id { get; set; } + public int CommandId { get; set; } = -2; + public int ObjectId { get; set; } = -2; + public object? Parameter { get; set; } = null; + } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index fe89331..83bc460 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.Backend; @@ -53,45 +54,68 @@ namespace mROA.Implementation.Frontend throw new NullReferenceException("Method repository is null."); await Task.Yield(); - - var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + + var multiClientOwnershipRepository = + TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); try { while (true) { - var request = - _representationModule!.GetMessage(messageType: MessageType.CallRequest); + Console.WriteLine("Waiting for request..."); + 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); - // Console.WriteLine("Executing {0}", request.Id); - - if (request.Parameter is not null) + Task.WaitAny(defaultRequest, cancelRequest); + + Console.WriteLine("Request received"); + + if (cancelRequest.IsCompleted) { - var parameterType = _methodRepository!.GetMethod(request.CommandId).GetParameters().First() - .ParameterType; - - request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType); + Console.WriteLine("Cancelling request"); + var req = cancelRequest.Result; + tokenSource.Cancel(); + _executeModule.Execute(req, _contextRepository, _representationModule); } - - var result = _executeModule.Execute(request, _contextRepository, _representationModule); - - var resultType = MessageType.Unknown; - - switch (result) + else { - case FinalCommandExecution: - resultType = MessageType.FinishedCommandExecution; - break; - case AsyncCommandExecution: - resultType = MessageType.AsyncCommandExecution; - break; - case ExceptionCommandExecution: - resultType = MessageType.ExceptionCommandExecution; - break; - } + tokenSource.Cancel(); + var request = defaultRequest.Result; - _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + 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, _representationModule); + + var resultType = MessageType.Unknown; + + switch (result) + { + case FinalCommandExecution: + resultType = MessageType.FinishedCommandExecution; + break; + case AsyncCommandExecution: + resultType = MessageType.AsyncCommandExecution; + break; + case ExceptionCommandExecution: + resultType = MessageType.ExceptionCommandExecution; + break; + } + + _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + } } } catch @@ -99,6 +123,5 @@ namespace mROA.Implementation.Frontend multiClientOwnershipRepository?.FreeOwnership(); } } - } } \ No newline at end of file diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 72402b9..cbe6731 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -86,10 +86,11 @@ namespace mROA.Implementation // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); var message = _serialization.Deserialize(localSpan.Span); - _messageBuffer.Add(message!); + Console.WriteLine($"Received Message {message.SchemaId} - {message.Id}"); + _messageBuffer.Add(message); _currentReceiving = Task.Run(async () => await GetNextMessage()); - return message!; + return message; } } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 62bcf76..5afc4c9 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -1,4 +1,5 @@ -using System.Threading; +using System; +using System.Threading; using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.CommandExecution; @@ -7,7 +8,7 @@ using mROA.Implementation.CommandExecution; namespace mROA.Implementation { - public abstract class RemoteObjectBase + public abstract class RemoteObjectBase : IDisposable { private readonly int _id; private readonly IRepresentationModule _representationModule; @@ -20,7 +21,7 @@ namespace mROA.Implementation public int Id => _id; public int OwnerId => _representationModule.Id; - + protected async Task GetResultAsync(int methodId, object? parameter = default, CancellationToken cancellationToken = default) { @@ -46,6 +47,7 @@ namespace mROA.Implementation if (cancellationToken.IsCancellationRequested) { await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); + localTokenSource.Cancel(); cancellationToken.ThrowIfCancellationRequested(); } @@ -76,21 +78,42 @@ namespace mROA.Implementation _representationModule.GetMessageAsync(requestId: request.Id, MessageType.ExceptionCommandExecution, localTokenSource.Token); + cancellationToken.Register(async () => + { + Console.WriteLine("Cancelling task"); + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, + new CancelRequest + { + Id = request.Id + }); + localTokenSource.Cancel(); + }); + Task.WaitAny(new Task[] { - successResponse, errorResponse + errorResponse, successResponse }, cancellationToken); - if (cancellationToken.IsCancellationRequested) - { - await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); - cancellationToken.ThrowIfCancellationRequested(); - } + Console.WriteLine($"Handling message"); + + // if (cancellationToken.IsCancellationRequested) + // { + // localTokenSource.Cancel(); + // return; + // } if (successResponse.IsCompletedSuccessfully) return; - throw errorResponse.Result.GetException(); + if (errorResponse.IsCompletedSuccessfully) + throw errorResponse.Result.GetException(); + } + + public void Dispose() + { + if (_id == -1) + return; + CallAsync(-1).Wait(); } } } \ No newline at end of file diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index dcba18f..54c9c76 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -57,7 +57,8 @@ namespace mROA.Implementation { var message = await _interaction.GetNextMessageReceiving(); if ((requestId is not null && message.Id != requestId) || - (messageType is not null && message.SchemaId != messageType)) continue; + (messageType is not null && message.SchemaId != messageType)) + continue; _interaction.HandleMessage(message); return message.Data; @@ -79,7 +80,9 @@ namespace mROA.Implementation throw new NullReferenceException("Interaction toolkit is not initialized"); if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - + + Console.WriteLine($"Posting message: {id} - {messageType}"); + await _interaction.PostMessage(new NetworkMessage { Id = id, SchemaId = messageType, Data = _serialization.Serialize(payload, payloadType) }); } From b8d816247603eaea5f18ee85437f599bbff46550 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 23 Feb 2025 10:32:31 +0300 Subject: [PATCH 08/66] =?UTF-8?q?=D0=94=D0=B8=D1=81=D0=BF=D0=BE=D0=B7=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 4 +++- Example.Frontend/Program.cs | 2 ++ .../Backend/BasicExecutionModule.cs | 22 ++++++++++++++----- mROA/Implementation/CallRequest.cs | 8 +++++++ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index ba8c624..92960e4 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -1,4 +1,6 @@ using System; +using System.Security.Cryptography; +using System.Text; using System.Threading; using System.Threading.Tasks; using Example.Shared; @@ -22,7 +24,7 @@ namespace Example.Backend public void Dispose() { - Console.WriteLine("Dispose printer with name {0}", Name); + 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.Frontend/Program.cs b/Example.Frontend/Program.cs index 44860ad..6ac3cb7 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -75,6 +75,8 @@ class Program Console.WriteLine("Page printed"); var data = page.Value.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); + + Console.WriteLine("Dispose printer"); } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 01343ca..8e8114e 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -63,14 +63,24 @@ namespace mROA.Implementation.Backend return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, representationModule); - var result = Execute(currentCommand, context, parameter, command); - - if (command.CommandId == -1) + try { - contextRepository.ClearObject(command.ObjectId); - } + var result = Execute(currentCommand, context, parameter, command); + if (command.CommandId == -1) + { + Console.WriteLine("Disposing object"); + contextRepository.ClearObject(command.ObjectId); + } - return result; + return result; + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + + } private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 783cce2..1d51e7e 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -24,6 +24,10 @@ namespace mROA.Implementation public Type? ParameterType { get; set; } public object? Parameter { get; set; } + public override string ToString() + { + return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; + } } public class CancelRequest : ICallRequest @@ -32,5 +36,9 @@ namespace mROA.Implementation public int CommandId { get; set; } = -2; public int ObjectId { get; set; } = -2; public object? Parameter { get; set; } = null; + public override string ToString() + { + return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; + } } } \ No newline at end of file From 79aaad9226a6c0b3f8717ef9e46791df2eccfe6e Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 24 Feb 2025 09:57:35 +0300 Subject: [PATCH 09/66] =?UTF-8?q?=D0=A1=D0=B8=D0=BD=D1=85=D1=80=D0=BE?= =?UTF-8?q?=D0=BD=D0=B8=D0=B7=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=81=20=D1=8E=D0=BD=D0=B8=D1=82=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 1 + mROA/Abstract/IContextRepository.cs | 3 +- .../Backend/BasicExecutionModule.cs | 2 +- .../Backend/ContextRepository.cs | 18 ++++++++-- .../Backend/MultiClientContextRepository.cs | 7 +++- .../CommandExecution/AsyncCommandExecution.cs | 12 +++++++ .../ExceptionCommandExecution.cs | 7 ---- .../Implementation/RemoteContextRepository.cs | 23 ++++++++++--- mROA/Implementation/RemoteObjectBase.cs | 34 ++++++++++++------- mROA/Implementation/SharedObject.cs | 2 +- 10 files changed, 80 insertions(+), 29 deletions(-) create mode 100644 mROA/Implementation/CommandExecution/AsyncCommandExecution.cs diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 6ac3cb7..08ec27a 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -73,6 +73,7 @@ class Program var page = disposingPrinter.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); Console.WriteLine("Page printed"); + Console.WriteLine(page.Value.ToString()); var data = page.Value.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index a54d5d6..c298688 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -1,4 +1,5 @@ using System; +using mROA.Implementation; namespace mROA.Abstract { @@ -6,7 +7,7 @@ namespace mROA.Abstract { int ResisterObject(object o); void ClearObject(int id); - object GetObject(int id); + T GetObjectBySharedObject(SharedObject sharedObject); T? GetObject(int id); object GetSingleObject(Type type); int GetObjectIndex(object o); diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 8e8114e..1ee01c8 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -50,7 +50,7 @@ namespace mROA.Implementation.Backend throw new Exception($"Command {command.CommandId} not found"); var context = command.ObjectId != -1 - ? contextRepository.GetObject(command.ObjectId) + ? contextRepository.GetObject(command.ObjectId) : contextRepository.GetSingleObject(currentCommand.DeclaringType!); var parameter = command.Parameter; diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 2831a38..b771a3d 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -10,8 +10,11 @@ namespace mROA.Implementation.Backend { public class ContextRepository : IContextRepository { - private Dictionary? _singletons; - private object?[] _storage = new object[StartupSize]; + private int _debugId = -1; + private static int LastDebugId = -1; + // [CanBeNull] + private Dictionary _singletons; + private object?[] _storage; private Task _lastIndexFinder = Task.FromResult(0); @@ -19,6 +22,11 @@ namespace mROA.Implementation.Backend private const int GrowSize = 128; + public ContextRepository() + { + _storage = new object[StartupSize]; + } + public void FillSingletons(params Assembly[] assembly) { var types = assembly.SelectMany(x => x.GetTypes()).Where(type => @@ -50,8 +58,14 @@ namespace mROA.Implementation.Backend _lastIndexFinder = Task.FromResult(id); } + public T GetObjectBySharedObject(SharedObject sharedObject) + { + return (T)GetObject(sharedObject.ContextId); + } + public object GetObject(int id) { + // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 5aa906a..4d76987 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -37,9 +37,14 @@ namespace mROA.Implementation.Backend GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id); } + public T GetObjectBySharedObject(SharedObject sharedObject) + { + return GetRepository(sharedObject.OwnerId).GetObject(sharedObject.ContextId); + } + public object GetObject(int id) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); + return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); } public T? GetObject(int id) diff --git a/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs new file mode 100644 index 0000000..fcddf6e --- /dev/null +++ b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs @@ -0,0 +1,12 @@ +using System; +using mROA.Abstract; + +namespace mROA.Implementation.CommandExecution +{ + public class AsyncCommandExecution : ICommandExecution + { + public Guid Id { get; set; } + public int ClientId { get; set; } + public int CommandId { get; set; } + } +} \ No newline at end of file diff --git a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs index 6d18129..c9d32ab 100644 --- a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs @@ -16,11 +16,4 @@ namespace mROA.Implementation.CommandExecution return new RemoteException(Exception) { CallRequestId = Id }; } } - - public class AsyncCommandExecution : ICommandExecution - { - public Guid Id { get; set; } - public int ClientId { get; set; } - public int CommandId { get; set; } - } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 0b7611d..70cd543 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -8,6 +8,7 @@ namespace mROA.Implementation { private IRepresentationModuleProducer? _representationProducer; public static Dictionary RemoteTypes = new(); + public int ResisterObject(object o) { throw new NotSupportedException(); @@ -18,6 +19,17 @@ namespace mROA.Implementation throw new NotSupportedException(); } + public T GetObjectBySharedObject(SharedObject sharedObject) + { + 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, sharedObject.ContextId, + _representationProducer.Produce(sharedObject.OwnerId))!; + return remote; + } + public object GetObject(int id) { throw new NotSupportedException(); @@ -27,9 +39,10 @@ namespace mROA.Implementation { 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()))!; + var remote = (T)Activator.CreateInstance(remoteType, id, + _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; return remote; } @@ -37,8 +50,9 @@ namespace mROA.Implementation { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); - - return Activator.CreateInstance(RemoteTypes[type], -1, _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; + + return Activator.CreateInstance(RemoteTypes[type], -1, + _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; } public int GetObjectIndex(object o) @@ -47,6 +61,7 @@ namespace mROA.Implementation { return remote.Id; } + throw new NotSupportedException(); } diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 5afc4c9..00f89c4 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -39,17 +39,28 @@ namespace mROA.Implementation _representationModule.GetMessageAsync(requestId: request.Id, MessageType.ExceptionCommandExecution, localTokenSource.Token); + cancellationToken.Register(async () => + { + Console.WriteLine("Cancelling task"); + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, + new CancelRequest + { + Id = request.Id + }); + localTokenSource.Cancel(); + }); + Task.WaitAny(new Task[] { successResponse, errorResponse }, cancellationToken); - if (cancellationToken.IsCancellationRequested) - { - await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); - localTokenSource.Cancel(); - cancellationToken.ThrowIfCancellationRequested(); - } + // if (cancellationToken.IsCancellationRequested) + // { + // await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); + // localTokenSource.Cancel(); + // cancellationToken.ThrowIfCancellationRequested(); + // } if (successResponse.IsCompletedSuccessfully) { @@ -96,12 +107,6 @@ namespace mROA.Implementation Console.WriteLine($"Handling message"); - // if (cancellationToken.IsCancellationRequested) - // { - // localTokenSource.Cancel(); - // return; - // } - if (successResponse.IsCompletedSuccessfully) return; @@ -115,5 +120,10 @@ namespace mROA.Implementation return; CallAsync(-1).Wait(); } + + public override string ToString() + { + return $"{{Id : {_id}, OwnerId : {OwnerId} }}"; + } } } \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index cf44c46..8008b1f 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -69,7 +69,7 @@ namespace mROA.Implementation set { _contextId = value; - Value = GetDefaultContextRepository().GetObject(_contextId)!; + Value = GetDefaultContextRepository().GetObjectBySharedObject(this)!; } } From 14c74c577551ab54c12934dceffde3e993cef030 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 24 Feb 2025 12:48:31 +0300 Subject: [PATCH 10/66] =?UTF-8?q?=D0=97=D0=B0=D0=BF=D0=B8=D1=81=D1=8C=20Cb?= =?UTF-8?q?or?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Benchmark/Program.cs | 7 +- mROA.Cbor/CborSerializaitonToolkit.cs | 144 +++++++++++++++++++ mROA.Cbor/IContextualSerializationToolKit.cs | 17 +++ mROA.Cbor/mROA.Cbor.csproj | 16 +++ mROA.sln | 6 + mROA/Abstract/IEndPointContext.cs | 9 ++ mROA/Implementation/SharedObject.cs | 4 + 7 files changed, 199 insertions(+), 4 deletions(-) create mode 100644 mROA.Cbor/CborSerializaitonToolkit.cs create mode 100644 mROA.Cbor/IContextualSerializationToolKit.cs create mode 100644 mROA.Cbor/mROA.Cbor.csproj create mode 100644 mROA/Abstract/IEndPointContext.cs diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs index c4ebb5e..a99f392 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -10,9 +10,8 @@ namespace mROA.Benchmark { static void Main(string[] args) { - Console.WriteLine("Hello, World!"); - var summary = BenchmarkRunner.Run(); - + // Console.WriteLine("Hello, World!"); + // var summary = BenchmarkRunner.Run(); } } @@ -26,7 +25,7 @@ namespace mROA.Benchmark public CollectionsSpeed() { _array = Enumerable.Range(0, N).ToArray(); - _immutable = [.._array]; + // _immutable = [.._array]; } [Benchmark] diff --git a/mROA.Cbor/CborSerializaitonToolkit.cs b/mROA.Cbor/CborSerializaitonToolkit.cs new file mode 100644 index 0000000..07d4e8d --- /dev/null +++ b/mROA.Cbor/CborSerializaitonToolkit.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Formats.Cbor; +using System.Linq; +using mROA.Abstract; +using mROA.Implementation; + +namespace mROA.Cbor +{ + public class CborSerializaitonToolkit : IContextualSerializationToolKit + { + public byte[] Serialize(T objectToSerialize, IEndPointContext context) + { + return Serialize(objectToSerialize, typeof(T), context); + } + + public byte[] Serialize(object objectToSerialize, Type type, IEndPointContext context) + { + } + + public T Deserialize(byte[] rawData, IEndPointContext context) + { + return (T)Deserialize(rawData, typeof(T), context); + } + + public object? Deserialize(byte[] rawData, Type type, IEndPointContext context) + { + return Deserialize(rawData.AsSpan(), type, context); + } + + public T Deserialize(Span rawData, IEndPointContext context) + { + return (T)Deserialize(rawData, typeof(T), context); + } + + public object? Deserialize(Span rawData, Type type, IEndPointContext context) + { + return null; + } + + public T Cast(object nonCasted, IEndPointContext context) + { + return (T)Cast(nonCasted, typeof(T), context); + } + + public object Cast(object nonCasted, Type type, IEndPointContext context) + { + return null; + } + + private void WriteData(object? obj, CborWriter writer) + { + 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 decimal dec: + writer.WriteDecimal(dec); + 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 byte[] bytes: + writer.WriteByteString(bytes); + break; + case IDictionary dictionary: + WriteDictionary(dictionary, writer); + break; + case IEnumerable enumerable: + WriteEnumerable(enumerable, writer); + break; + case SharedObject sharedObject: + break; + default: + WriteObject(obj, writer); + break; + } + } + + private void WriteEnumerable(IEnumerable enumerable, CborWriter writer) + { + List list = new List(); + + foreach (var element in enumerable) + list.Add(element); + + writer.WriteStartArray(list.Count); + + foreach (var element in list) + WriteData(element, writer); + + writer.WriteEndArray(); + } + + private void WriteDictionary(IDictionary dictionary, CborWriter writer) + { + 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); + WriteData(valuesEnumerator.Current, writer); + } + writer.WriteEndMap(); + } + + private void WriteObject(object obj, CborWriter writer) + { + var type = obj.GetType(); + var properties = type.GetProperties(); + var values = properties.Select(property => property.GetValue(obj)); + WriteEnumerable(values, writer); + } + } +} \ No newline at end of file diff --git a/mROA.Cbor/IContextualSerializationToolKit.cs b/mROA.Cbor/IContextualSerializationToolKit.cs new file mode 100644 index 0000000..b96b27e --- /dev/null +++ b/mROA.Cbor/IContextualSerializationToolKit.cs @@ -0,0 +1,17 @@ +using System; +using mROA.Abstract; + +namespace mROA.Cbor +{ + public interface IContextualSerializationToolKit + { + byte[] Serialize(T objectToSerialize, IEndPointContext context); + byte[] Serialize(object objectToSerialize, Type type, IEndPointContext context); + T Deserialize(byte[] rawData, IEndPointContext context); + object? Deserialize(byte[] rawData, Type type, IEndPointContext context); + T Deserialize(Span rawData, IEndPointContext context); + object? Deserialize(Span rawData, Type type, IEndPointContext context); + T Cast(object nonCasted, IEndPointContext context); + object Cast(object nonCasted, Type type, IEndPointContext context); + } +} \ No newline at end of file diff --git a/mROA.Cbor/mROA.Cbor.csproj b/mROA.Cbor/mROA.Cbor.csproj new file mode 100644 index 0000000..7f66dce --- /dev/null +++ b/mROA.Cbor/mROA.Cbor.csproj @@ -0,0 +1,16 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + diff --git a/mROA.sln b/mROA.sln index 7586eb3..34c47ba 100644 --- a/mROA.sln +++ b/mROA.sln @@ -19,6 +19,8 @@ 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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -53,6 +55,10 @@ 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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs new file mode 100644 index 0000000..dbaf7d6 --- /dev/null +++ b/mROA/Abstract/IEndPointContext.cs @@ -0,0 +1,9 @@ +namespace mROA.Abstract +{ + public interface IEndPointContext + { + IContextRepository RealRepository { get; } + IContextRepository RemoteRepository { get; } + int HostId { get; } + } +} \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 8008b1f..8dcfcf9 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -32,6 +32,10 @@ namespace mROA.Implementation } + public class SharedObject : SharedObject + { + + } public class SharedObject where T : notnull { private IContextRepository GetDefaultContextRepository() => From 05ee651e89d784556e991c9fda80916d5e940a57 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 24 Feb 2025 18:01:34 +0300 Subject: [PATCH 11/66] =?UTF-8?q?=D0=9F=D1=80=D0=B8=D1=87=D0=B5=D1=81?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Backend/BasicExecutionModule.cs | 20 +++++++++------- .../Backend/ContextRepository.cs | 2 +- .../Backend/MultiClientContextRepository.cs | 24 ++++++++++++------- .../CreativeRepresentationModuleProducer.cs | 5 ++-- .../Frontend/NetworkFrontendBridge.cs | 4 +++- .../Frontend/RequestExtractor.cs | 3 ++- .../NextGenerationInteractionModule.cs | 3 ++- .../Implementation/RemoteContextRepository.cs | 9 ++++--- mROA/Implementation/RemoteObjectBase.cs | 1 + mROA/Implementation/RepresentationModule.cs | 15 +++++++----- mROA/Implementation/SharedObject.cs | 2 +- 11 files changed, 56 insertions(+), 32 deletions(-) diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 1ee01c8..56ec2ea 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -88,10 +88,11 @@ namespace mROA.Implementation.Backend { try { - var finalResult = currentCommand.Invoke(context, parameter is null + var finalParameter = parameter is null ? Array.Empty() : new[] - { parameter }); + { parameter }; + var finalResult = currentCommand.Invoke(context, finalParameter); return new TypedFinalCommandExecution { @@ -120,10 +121,11 @@ namespace mROA.Implementation.Backend token.Register(() => Console.WriteLine($"Cancellation requested check {command.Id}")); try { - var result = (Task)currentCommand.Invoke(context, parameter is null + var finalParameter = parameter is null ? new object[] { token } : new[] - { parameter, token })!; + { parameter, token }; + var result = (Task)currentCommand.Invoke(context, finalParameter)!; result.ContinueWith(_ => @@ -140,6 +142,7 @@ namespace mROA.Implementation.Backend var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); multiClientOwnershipRepository?.FreeOwnership(); @@ -170,11 +173,12 @@ namespace mROA.Implementation.Backend var token = tokenSource.Token; try { + var finalParameter = parameter is null + ? new object[] { token } + : new[] + { parameter, token }; var result = - (Task)currentCommand.Invoke(context, parameter is null - ? new object[] { token } - : new[] - { parameter, token })!; + (Task)currentCommand.Invoke(context, finalParameter)!; result.ContinueWith(t => { diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index b771a3d..109c02a 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -76,7 +76,7 @@ namespace mROA.Implementation.Backend public object GetSingleObject(Type type) { - return _singletons!.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); + return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); } public int GetObjectIndex(object o) diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 4d76987..d997ad2 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -29,42 +29,50 @@ namespace mROA.Implementation.Backend public int ResisterObject(object o) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.ResisterObject(o); } public void ClearObject(int id) { - GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + repository.ClearObject(id); } public T GetObjectBySharedObject(SharedObject sharedObject) { - return GetRepository(sharedObject.OwnerId).GetObject(sharedObject.ContextId); + var repository = GetRepository(sharedObject.OwnerId); + return repository.GetObject(sharedObject.ContextId); } public object GetObject(int id) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.GetObject(id); } public T? GetObject(int id) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.GetObject(id); } public object GetSingleObject(Type type) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetSingleObject(type); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.GetSingleObject(type); } public int GetObjectIndex(object o) { - return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObjectIndex(o); + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.GetObjectIndex(o); } public IContextRepository GetRepository(int clientId) { - return GetRepositoryByClientId(clientId); + var repository = GetRepositoryByClientId(clientId); + return repository; } } } \ No newline at end of file diff --git a/mROA/Implementation/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs index 667c2f4..5ac35cc 100644 --- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs +++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs @@ -33,8 +33,9 @@ namespace mROA.Implementation foreach (var creationModule in _creationModules) produced.Inject(creationModule); - - produced.Inject(_hub.GetInteracion(id)); + + var interaction = _hub.GetInteracion(id); + produced.Inject(interaction); return produced; } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 53da9fc..5616e5b 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -45,7 +45,9 @@ namespace mROA.Implementation.Frontend throw new Exception($"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.SchemaId.ToString()}"); } - TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize(welcomeMessage.Data)!.Id); + + var assignment = _serialization.Deserialize(welcomeMessage.Data)!; + TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); } } } \ No newline at end of file diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 83bc460..87741e8 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -91,7 +91,8 @@ namespace mROA.Implementation.Frontend if (request.Parameter is not null) { - var parameterType = _methodRepository!.GetMethod(request.CommandId).GetParameters().First() + var method = _methodRepository!.GetMethod(request.CommandId); + var parameterType = method.GetParameters().First() .ParameterType; request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType); diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index cbe6731..f31664c 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -51,7 +51,8 @@ namespace mROA.Implementation var rawMessage = _serialization.Serialize(message); - await BaseStream.WriteAsync(BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort))); + var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); + await BaseStream.WriteAsync(header); await BaseStream.WriteAsync(rawMessage); } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 70cd543..9fb7191 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -25,8 +25,9 @@ namespace mROA.Implementation throw new NullReferenceException("representation producer is not initialized"); if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException(); + var representationModule = _representationProducer.Produce(sharedObject.OwnerId); var remote = (T)Activator.CreateInstance(remoteType, sharedObject.ContextId, - _representationProducer.Produce(sharedObject.OwnerId))!; + representationModule)!; return remote; } @@ -41,8 +42,9 @@ namespace mROA.Implementation 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, - _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; + representationModule)!; return remote; } @@ -51,8 +53,9 @@ namespace mROA.Implementation if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); + var representationModule = _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); return Activator.CreateInstance(RemoteTypes[type], -1, - _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; + representationModule)!; } public int GetObjectIndex(object o) diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 00f89c4..0c993f1 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -27,6 +27,7 @@ namespace mROA.Implementation { var request = new DefaultCallRequest { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); var localTokenSource = new CancellationTokenSource(); diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 54c9c76..67c26ce 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -29,16 +29,18 @@ namespace mROA.Implementation { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - - return _serialization.Deserialize(await GetRawMessage(requestId, messageType, token))!; + + var rawMessage = await GetRawMessage(requestId, messageType, token); + return _serialization.Deserialize(rawMessage)!; } public T GetMessage(Guid? requestId = null, MessageType? messageType = null) { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - - return _serialization.Deserialize(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!; + + var rawMessage = GetRawMessage(requestId, messageType).GetAwaiter().GetResult(); + return _serialization.Deserialize(rawMessage)!; } public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null, CancellationToken token = default) @@ -82,9 +84,10 @@ namespace mROA.Implementation throw new NullReferenceException("Serialization toolkit is not initialized"); Console.WriteLine($"Posting message: {id} - {messageType}"); - + + var serialized = _serialization.Serialize(payload, payloadType); await _interaction.PostMessage(new NetworkMessage - { Id = id, SchemaId = messageType, Data = _serialization.Serialize(payload, payloadType) }); + { Id = id, SchemaId = messageType, Data = serialized }); } public void PostCallMessage(Guid id, MessageType messageType, T payload) where T : notnull diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 8dcfcf9..a9e56dc 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -73,7 +73,7 @@ namespace mROA.Implementation set { _contextId = value; - Value = GetDefaultContextRepository().GetObjectBySharedObject(this)!; + Value = GetDefaultContextRepository().GetObjectBySharedObject(this); } } From c0bb3c523af0f8c76cb767bec3a21e7dd9d4c049 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 25 Feb 2025 08:43:01 +0300 Subject: [PATCH 12/66] =?UTF-8?q?Cbor=20=D1=87=D0=B0=D1=81=D1=82=D1=8C=202?= =?UTF-8?q?,=20=D0=B4=D0=B5=D1=81=D0=B5=D1=80=D0=B8=D0=B0=D0=BB=D0=B8?= =?UTF-8?q?=D0=B7=D0=B0=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Cbor/CborSerializaitonToolkit.cs | 213 +++++++++++++++--- mROA.Cbor/IContextualSerializationToolKit.cs | 10 +- mROA.Test/CborTest.cs | 115 ++++++++++ mROA.Test/NextGenTest.cs | 1 + mROA.Test/mROA.Test.csproj | 3 +- .../SerializationIgnoreAttribute.cs | 9 + mROA/Implementation/SharedObject.cs | 9 +- 7 files changed, 322 insertions(+), 38 deletions(-) create mode 100644 mROA.Test/CborTest.cs create mode 100644 mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs diff --git a/mROA.Cbor/CborSerializaitonToolkit.cs b/mROA.Cbor/CborSerializaitonToolkit.cs index 07d4e8d..fa7d658 100644 --- a/mROA.Cbor/CborSerializaitonToolkit.cs +++ b/mROA.Cbor/CborSerializaitonToolkit.cs @@ -3,20 +3,28 @@ using System.Collections; using System.Collections.Generic; using System.Formats.Cbor; using System.Linq; +using System.Reflection; +using System.Text.Json; using mROA.Abstract; using mROA.Implementation; +using mROA.Implementation.Attributes; namespace mROA.Cbor { public class CborSerializaitonToolkit : IContextualSerializationToolKit { - public byte[] Serialize(T objectToSerialize, IEndPointContext context) + public byte[] Serialize(object objectToSerialize, IEndPointContext context) { - return Serialize(objectToSerialize, typeof(T), context); + var writer = new CborWriter(); + WriteData(objectToSerialize, writer, context); + return writer.Encode(); } - public byte[] Serialize(object objectToSerialize, Type type, IEndPointContext context) + 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) @@ -24,19 +32,20 @@ namespace mROA.Cbor return (T)Deserialize(rawData, typeof(T), context); } - public object? Deserialize(byte[] rawData, Type type, IEndPointContext context) + public object Deserialize(byte[] rawData, Type type, IEndPointContext context) { - return Deserialize(rawData.AsSpan(), type, context); + return Deserialize(rawData.AsMemory(), type, context); } - public T Deserialize(Span rawData, IEndPointContext context) + public T Deserialize(ReadOnlyMemory rawData, IEndPointContext context) { return (T)Deserialize(rawData, typeof(T), context); } - public object? Deserialize(Span rawData, Type type, IEndPointContext context) + public object Deserialize(ReadOnlyMemory rawData, Type type, IEndPointContext context) { - return null; + var reader = new CborReader(rawData); + return ReadData(reader, type, context); } public T Cast(object nonCasted, IEndPointContext context) @@ -49,7 +58,7 @@ namespace mROA.Cbor return null; } - private void WriteData(object? obj, CborWriter writer) + private void WriteData(object? obj, CborWriter writer, IEndPointContext context) { switch (obj) { @@ -65,9 +74,9 @@ namespace mROA.Cbor case double d: writer.WriteDouble(d); break; - case decimal dec: - writer.WriteDecimal(dec); - break; + // case decimal dec: + // writer.WriteDecimal(dec); + // break; case bool b: writer.WriteBoolean(b); break; @@ -90,35 +99,41 @@ namespace mROA.Cbor writer.WriteByteString(bytes); break; case IDictionary dictionary: - WriteDictionary(dictionary, writer); + WriteDictionary(dictionary, writer, context); break; - case IEnumerable enumerable: - WriteEnumerable(enumerable, writer); + case IList enumerable: + WriteList(enumerable, writer, context); break; - case SharedObject sharedObject: + case ISharedObject sharedObject: + sharedObject.EndPointContext = context; + WriteObject(sharedObject, writer, context); break; default: - WriteObject(obj, writer); + if (obj.GetType().IsEnum) + { + writer.WriteUInt32((uint)obj); + break; + } + + WriteObject(obj, writer, context); break; } } - private void WriteEnumerable(IEnumerable enumerable, CborWriter writer) + private void WriteList(IList list, CborWriter writer, IEndPointContext context) { - List list = new List(); - foreach (var element in enumerable) - list.Add(element); + writer.WriteStartArray(list.Count); foreach (var element in list) - WriteData(element, writer); + WriteData(element, writer, context); writer.WriteEndArray(); } - private void WriteDictionary(IDictionary dictionary, CborWriter writer) + private void WriteDictionary(IDictionary dictionary, CborWriter writer, IEndPointContext context) { writer.WriteStartMap(dictionary.Count); var keysEnumerator = dictionary.Keys.GetEnumerator(); @@ -127,18 +142,158 @@ namespace mROA.Cbor { keysEnumerator.MoveNext(); valuesEnumerator.MoveNext(); - WriteData(keysEnumerator.Current, writer); - WriteData(valuesEnumerator.Current, writer); + 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) + private void WriteObject(object obj, CborWriter writer, IEndPointContext context) { var type = obj.GetType(); - var properties = type.GetProperties(); - var values = properties.Select(property => property.GetValue(obj)); - WriteEnumerable(values, writer); + 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)) + return reader.ReadInt32(); + if (type == typeof(long)) + return reader.ReadInt64(); + if (type == typeof(uint) || type.IsEnum) + return reader.ReadUInt32(); + if (type == typeof(ulong)) + return reader.ReadUInt64(); + break; + case CborReaderState.ByteString: + return reader.ReadByteString(); + case CborReaderState.TextString: + return reader.ReadTextString(); + case CborReaderState.Null: + return null; + case CborReaderState.DoublePrecisionFloat: + return reader.ReadDouble(); + case CborReaderState.SinglePrecisionFloat: + return reader.ReadSingle(); + case CborReaderState.StartArray: + if (type == null) + return ReadList(reader, null, context); + + if (type.IsSubclassOf(typeof(ISharedObject))) + return ReadSharedObject(reader, type, context); + + if (type.IsSubclassOf(typeof(IList))) + 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 Array ReadList(CborReader reader, Type? type, IEndPointContext context) + { + var length = reader.ReadStartArray(); + if (length != null) + { + var values = new object[length.Value]; + + Type elementType = typeof(object); + + if (type is { IsArray: true }) + elementType = type.GetGenericArguments()[0]; + + + for (int i = 0; i < length; i++) + { + values[i] = ReadData(reader, elementType, context); + } + } + + return Array.Empty(); + } + + 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) + { + var instance = Activator.CreateInstance(type)!; + + FillObject(instance, type, reader, context); + + return instance; + } + + private ISharedObject ReadSharedObject(CborReader reader, Type type, IEndPointContext context) + { + var sharedObject = (Activator.CreateInstance(type) as ISharedObject)!; + sharedObject.EndPointContext = context; + + FillObject(sharedObject, type, reader, context); + + return sharedObject; + } + + private void FillObject(object obj, Type type, CborReader reader, IEndPointContext context) + { + var properties = FilterProperties(type.GetProperties()); + + _ = reader.ReadStartArray(); + + foreach (var property in properties) + { + var value = ReadData(reader, property.PropertyType, context); + property.SetValue(obj, value); + } + + reader.ReadEndArray(); + } + + private List FilterProperties(PropertyInfo[] properties) + { + var finalProperties = new List(properties.Length); + foreach (var property in properties) + { + if (property.GetCustomAttribute() == null) + finalProperties.Add(property); + } + + return finalProperties; } } } \ No newline at end of file diff --git a/mROA.Cbor/IContextualSerializationToolKit.cs b/mROA.Cbor/IContextualSerializationToolKit.cs index b96b27e..c7ee66c 100644 --- a/mROA.Cbor/IContextualSerializationToolKit.cs +++ b/mROA.Cbor/IContextualSerializationToolKit.cs @@ -5,12 +5,12 @@ namespace mROA.Cbor { public interface IContextualSerializationToolKit { - byte[] Serialize(T objectToSerialize, IEndPointContext context); - byte[] Serialize(object objectToSerialize, Type type, IEndPointContext context); + byte[] Serialize(object objectToSerialize, IEndPointContext context); + void Serialize(object objectToSerialize, Span destination, IEndPointContext context); T Deserialize(byte[] rawData, IEndPointContext context); - object? Deserialize(byte[] rawData, Type type, IEndPointContext context); - T Deserialize(Span rawData, IEndPointContext context); - object? Deserialize(Span rawData, Type type, IEndPointContext context); + object Deserialize(byte[] rawData, Type type, IEndPointContext context); + T Deserialize(ReadOnlyMemory rawData, IEndPointContext context); + object Deserialize(ReadOnlyMemory rawData, Type type, IEndPointContext context); T Cast(object nonCasted, IEndPointContext context); object Cast(object nonCasted, Type type, IEndPointContext context); } diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs new file mode 100644 index 0000000..95610e7 --- /dev/null +++ b/mROA.Test/CborTest.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using mROA.Cbor; + +namespace mROA.Test; + +public class CborTest +{ + private ComplexTestObject _complexTestObject; + private IContextualSerializationToolKit _serializationToolKit; + private BasicCollectionElement _basicCollectionElement; + + [SetUp] + public void Setup() + { + _complexTestObject = new () + { + IntValue = 123, + DoubleValue = 3.14159, + StringValue = "abc", + CollectionElements = + [ + _basicCollectionElement, + new BasicCollectionElement { A = 8_000_000, B = "Fi number", C = 1.618f } + ], + IntArray = [1, 4, 8, 16, 87] + }; + _basicCollectionElement = new() { A = 567565, B = "test text", C = 2.781f }; + _serializationToolKit = new CborSerializaitonToolkit(); + } + + [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; + List first = [1, 2, 3]; + List second = [1, 2, 3]; + var eq = first.Equals(second); + var data = _serializationToolKit.Serialize(value, null); + var deserialize = _serializationToolKit.Deserialize(data, null); + Assert.That(value, Is.EqualTo(deserialize)); + } + + [Test] + public void ComplexFull() + { + } + + public void SharedObject() + { + } + + + private class ComplexTestObject + { + public int IntValue { get; set; } + public double DoubleValue { get; set; } + public string StringValue { get; set; } + public int[] IntArray { get; set; } + public BasicCollectionElement[] CollectionElements { get; set; } + + protected bool Equals(ComplexTestObject other) + { + return IntValue == other.IntValue && DoubleValue.Equals(other.DoubleValue) && StringValue == other.StringValue && IntArray.Equals(other.IntArray) && CollectionElements.Equals(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); + } + } +} \ No newline at end of file diff --git a/mROA.Test/NextGenTest.cs b/mROA.Test/NextGenTest.cs index 76a53c5..8eaebb0 100644 --- a/mROA.Test/NextGenTest.cs +++ b/mROA.Test/NextGenTest.cs @@ -70,6 +70,7 @@ namespace mROA.Test [TearDown] public void TearDown() { + _listener.Stop(); _listener.Dispose(); } } diff --git a/mROA.Test/mROA.Test.csproj b/mROA.Test/mROA.Test.csproj index 4d1d9e4..bff76ec 100644 --- a/mROA.Test/mROA.Test.csproj +++ b/mROA.Test/mROA.Test.csproj @@ -1,7 +1,7 @@  - netstandard2.1 + net9.0 latest enable @@ -27,6 +27,7 @@ + diff --git a/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs new file mode 100644 index 0000000..b63d4d3 --- /dev/null +++ b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs @@ -0,0 +1,9 @@ +using System; + +namespace mROA.Implementation.Attributes +{ + public class SerializationIgnoreAttribute : Attribute + { + + } +} \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index a9e56dc..17f6d53 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -32,11 +32,12 @@ namespace mROA.Implementation } - public class SharedObject : SharedObject + public interface ISharedObject { - + IEndPointContext EndPointContext { get; set; } } - public class SharedObject where T : notnull + + public class SharedObject : ISharedObject where T : notnull { private IContextRepository GetDefaultContextRepository() => (OwnerId == TransmissionConfig.OwnershipRepository.GetHostOwnershipId() @@ -103,5 +104,7 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); + + public IEndPointContext EndPointContext { get; set; } } } \ No newline at end of file From 9c493fd8fedffe33c3e22c8fa1649bbddfacb55c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 25 Feb 2025 08:52:18 +0300 Subject: [PATCH 13/66] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=201.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Cbor/CborSerializaitonToolkit.cs | 2 +- mROA.Test/CborTest.cs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/mROA.Cbor/CborSerializaitonToolkit.cs b/mROA.Cbor/CborSerializaitonToolkit.cs index fa7d658..c6e776d 100644 --- a/mROA.Cbor/CborSerializaitonToolkit.cs +++ b/mROA.Cbor/CborSerializaitonToolkit.cs @@ -194,7 +194,7 @@ namespace mROA.Cbor if (type.IsSubclassOf(typeof(ISharedObject))) return ReadSharedObject(reader, type, context); - if (type.IsSubclassOf(typeof(IList))) + if (type.IsSubclassOf(typeof(IList)) || type.IsArray) return ReadList(reader, type, context); return ReadObject(reader, type, context); diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs index 95610e7..0b8a68e 100644 --- a/mROA.Test/CborTest.cs +++ b/mROA.Test/CborTest.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using mROA.Cbor; namespace mROA.Test; @@ -43,9 +44,6 @@ public class CborTest public void ComplexFlat() { var value = _basicCollectionElement; - List first = [1, 2, 3]; - List second = [1, 2, 3]; - var eq = first.Equals(second); var data = _serializationToolKit.Serialize(value, null); var deserialize = _serializationToolKit.Deserialize(data, null); Assert.That(value, Is.EqualTo(deserialize)); @@ -54,6 +52,10 @@ public class CborTest [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() @@ -71,7 +73,7 @@ public class CborTest protected bool Equals(ComplexTestObject other) { - return IntValue == other.IntValue && DoubleValue.Equals(other.DoubleValue) && StringValue == other.StringValue && IntArray.Equals(other.IntArray) && CollectionElements.Equals(other.CollectionElements); + 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) From ac5eded1478e99193f23a95a6d5968f5ebc3492f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 25 Feb 2025 08:57:58 +0300 Subject: [PATCH 14/66] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=202.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Cbor/CborSerializaitonToolkit.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mROA.Cbor/CborSerializaitonToolkit.cs b/mROA.Cbor/CborSerializaitonToolkit.cs index c6e776d..3b8a171 100644 --- a/mROA.Cbor/CborSerializaitonToolkit.cs +++ b/mROA.Cbor/CborSerializaitonToolkit.cs @@ -221,13 +221,14 @@ namespace mROA.Cbor Type elementType = typeof(object); if (type is { IsArray: true }) - elementType = type.GetGenericArguments()[0]; + elementType = type.GetElementType(); for (int i = 0; i < length; i++) { values[i] = ReadData(reader, elementType, context); } + return values; } return Array.Empty(); From d1a4d6f97e48c53b7d368e79fc86654640d2c9cb Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 25 Feb 2025 17:09:04 +0300 Subject: [PATCH 15/66] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=87=D1=82=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D1=81=D0=BF=D0=B8=D1=81=D0=BA=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...Toolkit.cs => CborSerializationToolkit.cs} | 25 +++++++++++-------- mROA.Test/CborTest.cs | 9 ++++--- mROA/Abstract/IEndPointContext.cs | 1 + mROA/Implementation/EndPointContext.cs | 20 +++++++++++++++ mROA/Implementation/SharedObject.cs | 15 ++++++++--- 5 files changed, 51 insertions(+), 19 deletions(-) rename mROA.Cbor/{CborSerializaitonToolkit.cs => CborSerializationToolkit.cs} (94%) create mode 100644 mROA/Implementation/EndPointContext.cs diff --git a/mROA.Cbor/CborSerializaitonToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs similarity index 94% rename from mROA.Cbor/CborSerializaitonToolkit.cs rename to mROA.Cbor/CborSerializationToolkit.cs index 3b8a171..f950fff 100644 --- a/mROA.Cbor/CborSerializaitonToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -11,7 +11,7 @@ using mROA.Implementation.Attributes; namespace mROA.Cbor { - public class CborSerializaitonToolkit : IContextualSerializationToolKit + public class CborSerializationToolkit : IContextualSerializationToolKit { public byte[] Serialize(object objectToSerialize, IEndPointContext context) { @@ -122,9 +122,6 @@ namespace mROA.Cbor private void WriteList(IList list, CborWriter writer, IEndPointContext context) { - - - writer.WriteStartArray(list.Count); foreach (var element in list) @@ -193,10 +190,10 @@ namespace mROA.Cbor if (type.IsSubclassOf(typeof(ISharedObject))) return ReadSharedObject(reader, type, context); - - if (type.IsSubclassOf(typeof(IList)) || type.IsArray) + + if (typeof(IList).IsAssignableFrom(type) || type.IsArray) return ReadList(reader, type, context); - + return ReadObject(reader, type, context); case CborReaderState.StartMap: @@ -216,21 +213,27 @@ namespace mROA.Cbor var length = reader.ReadStartArray(); if (length != null) { - var values = new object[length.Value]; - - Type elementType = typeof(object); + var elementType = typeof(object); if (type is { IsArray: true }) elementType = type.GetElementType(); + else if (typeof(IList).IsAssignableFrom(type)) + elementType = type.GetGenericArguments()[0]; + + Array values = Array.CreateInstance(elementType, length.Value); for (int i = 0; i < length; i++) { - values[i] = ReadData(reader, elementType, context); + values.SetValue(ReadData(reader, elementType, context), i); } + + reader.ReadEndArray(); return values; } + reader.ReadEndArray(); + return Array.Empty(); } diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs index 0b8a68e..a6d1bf2 100644 --- a/mROA.Test/CborTest.cs +++ b/mROA.Test/CborTest.cs @@ -14,7 +14,9 @@ public class CborTest [SetUp] public void Setup() { - _complexTestObject = new () + _basicCollectionElement = new() { A = 567565, B = "test text", C = 2.781f }; + + _complexTestObject = new ComplexTestObject { IntValue = 123, DoubleValue = 3.14159, @@ -26,8 +28,7 @@ public class CborTest ], IntArray = [1, 4, 8, 16, 87] }; - _basicCollectionElement = new() { A = 567565, B = "test text", C = 2.781f }; - _serializationToolKit = new CborSerializaitonToolkit(); + _serializationToolKit = new CborSerializationToolkit(); } [Test] @@ -69,7 +70,7 @@ public class CborTest public double DoubleValue { get; set; } public string StringValue { get; set; } public int[] IntArray { get; set; } - public BasicCollectionElement[] CollectionElements { get; set; } + public List CollectionElements { get; set; } protected bool Equals(ComplexTestObject other) { diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs index dbaf7d6..5d6e4c6 100644 --- a/mROA/Abstract/IEndPointContext.cs +++ b/mROA/Abstract/IEndPointContext.cs @@ -5,5 +5,6 @@ IContextRepository RealRepository { get; } IContextRepository RemoteRepository { get; } int HostId { get; } + int OwnerId { get; } } } \ No newline at end of file diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs new file mode 100644 index 0000000..7ceb5df --- /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(); + set + { + OwnerFunc = () => value; + } } + } +} \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 17f6d53..f99d420 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -1,6 +1,7 @@ using System; using System.Text.Json.Serialization; using mROA.Abstract; + // ReSharper disable UnusedMember.Global #pragma warning disable CS8618, CS9264 @@ -20,7 +21,8 @@ namespace mROA.Implementation public static IContextRepository RemoteEndpointContextRepository { - get => _remoteEndpointContextRepository ?? throw new NullReferenceException("RemoteEndpointContextRepository is null"); + get => _remoteEndpointContextRepository ?? + throw new NullReferenceException("RemoteEndpointContextRepository is null"); set => _remoteEndpointContextRepository = value; } @@ -29,14 +31,13 @@ namespace mROA.Implementation get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); set => _ownershipRepository = value; } - } public interface ISharedObject { IEndPointContext EndPointContext { get; set; } } - + public class SharedObject : ISharedObject where T : notnull { private IContextRepository GetDefaultContextRepository() => @@ -105,6 +106,12 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); - public IEndPointContext EndPointContext { get; set; } + public IEndPointContext EndPointContext { get; set; } = new EndPointContext + { + RealRepository = TransmissionConfig.RealContextRepository, + RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, + HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), + OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId + }; } } \ No newline at end of file From c36e7682101fd803f23ad90db772c9f37c44c38c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 25 Feb 2025 22:38:53 +0300 Subject: [PATCH 16/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D1=80=D0=B5=D0=BF=D1=80=D0=BE?= =?UTF-8?q?=D1=86=D0=B5=D1=81=D1=81=D0=BE=D1=80=D0=B0=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BE=D1=87=D0=B8=D1=81=D1=82=D0=BA=D0=B8=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=81=D0=BE=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 4 ++++ Example.Backend/Printer.cs | 2 -- Example.Frontend/Program.cs | 1 - mROA.Benchmark/Program.cs | 4 +--- mROA.Cbor/CborSerializationToolkit.cs | 1 - mROA.sln | 8 ++++---- mROA/Abstract/ISerialisationModule.cs | 1 - .../Backend/BasicExecutionModule.cs | 9 ++++++++- .../Frontend/RequestExtractor.cs | 9 +++++++-- .../NextGenerationInteractionModule.cs | 2 ++ mROA/Implementation/RemoteObjectBase.cs | 7 ++++++- mROA/Implementation/RepresentationModule.cs | 20 +++++++++++-------- mROA/Implementation/SharedObject.cs | 4 +++- mROA/LegacyExtentions.cs | 9 ++++----- mROA/mROA.csproj | 10 ++++++++++ 15 files changed, 61 insertions(+), 30 deletions(-) diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index 3eac518..4f357b7 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -10,6 +10,10 @@ 9 + + + + diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 92960e4..a5ba4ac 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -1,6 +1,4 @@ using System; -using System.Security.Cryptography; -using System.Text; using System.Threading; using System.Threading.Tasks; using Example.Shared; diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 08ec27a..98d4f5f 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Net; using System.Text; using System.Threading; diff --git a/mROA.Benchmark/Program.cs b/mROA.Benchmark/Program.cs index a99f392..217a6d7 100644 --- a/mROA.Benchmark/Program.cs +++ b/mROA.Benchmark/Program.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using BenchmarkDotNet.Attributes; -using BenchmarkDotNet.Running; namespace mROA.Benchmark { diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index f950fff..af66e5e 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.Formats.Cbor; using System.Linq; using System.Reflection; -using System.Text.Json; using mROA.Abstract; using mROA.Implementation; using mROA.Implementation.Attributes; diff --git a/mROA.sln b/mROA.sln index 34c47ba..6899901 100644 --- a/mROA.sln +++ b/mROA.sln @@ -27,18 +27,18 @@ Global 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 diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/ISerialisationModule.cs index a25e00e..a297fd8 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/ISerialisationModule.cs @@ -1,7 +1,6 @@ using System; using System.Threading; using System.Threading.Tasks; -using System.Windows.Input; using mROA.Implementation; using mROA.Implementation.CommandExecution; diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 56ec2ea..3173d37 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -21,8 +21,9 @@ namespace mROA.Implementation.Backend public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, IRepresentationModule representationModule) { +#if TRACE Console.WriteLine(command.GetType().Name); - +#endif if (_cancellationRepo is null) throw new NullReferenceException("Method repository was not defined"); @@ -34,7 +35,9 @@ namespace mROA.Implementation.Backend if (command is CancelRequest) { +#if TRACE Console.WriteLine("Final cancelling request"); +#endif var cts = _cancellationRepo.GetCancellation(command.Id); cts.Cancel(); _cancellationRepo.FreeCancelation(command.Id); @@ -68,7 +71,9 @@ namespace mROA.Implementation.Backend var result = Execute(currentCommand, context, parameter, command); if (command.CommandId == -1) { +#if TRACE Console.WriteLine("Disposing object"); +#endif contextRepository.ClearObject(command.ObjectId); } @@ -118,7 +123,9 @@ namespace mROA.Implementation.Backend 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 { var finalParameter = parameter is null diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 87741e8..cfcf9ce 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -63,7 +63,9 @@ namespace mROA.Implementation.Frontend { while (true) { +#if TRACE Console.WriteLine("Waiting for request..."); +#endif var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var defaultRequest = @@ -74,12 +76,15 @@ namespace mROA.Implementation.Frontend messageType: MessageType.CancelRequest, token: token); Task.WaitAny(defaultRequest, cancelRequest); - + +#if TRACE Console.WriteLine("Request received"); - +#endif if (cancelRequest.IsCompleted) { +#if TRACE Console.WriteLine("Cancelling request"); +#endif var req = cancelRequest.Result; tokenSource.Cancel(); _executeModule.Execute(req, _contextRepository, _representationModule); diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index f31664c..e9416e9 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -87,7 +87,9 @@ namespace mROA.Implementation // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); var message = _serialization.Deserialize(localSpan.Span); +#if TRACE Console.WriteLine($"Received Message {message.SchemaId} - {message.Id}"); +#endif _messageBuffer.Add(message); _currentReceiving = Task.Run(async () => await GetNextMessage()); diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 0c993f1..a81c255 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -42,7 +42,9 @@ namespace mROA.Implementation cancellationToken.Register(async () => { +#if TRACE Console.WriteLine("Cancelling task"); +#endif await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, new CancelRequest { @@ -92,7 +94,9 @@ namespace mROA.Implementation cancellationToken.Register(async () => { +#if TRACE Console.WriteLine("Cancelling task"); +#endif await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, new CancelRequest { @@ -106,8 +110,9 @@ namespace mROA.Implementation errorResponse, successResponse }, cancellationToken); +#if TRACE Console.WriteLine($"Handling message"); - +#endif if (successResponse.IsCompletedSuccessfully) return; diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 67c26ce..73e2275 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -23,9 +23,11 @@ namespace mROA.Implementation } } - public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId; + public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")) + .ConnectionId; - public async Task GetMessageAsync(Guid? requestId, MessageType? messageType, CancellationToken token = default) + public async Task GetMessageAsync(Guid? requestId, MessageType? messageType, + CancellationToken token = default) { if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); @@ -43,25 +45,26 @@ namespace mROA.Implementation return _serialization.Deserialize(rawMessage)!; } - public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null, CancellationToken token = default) + public async Task GetRawMessage(Guid? requestId = null, MessageType? messageType = null, + CancellationToken token = default) { if (_interaction == null) throw new NullReferenceException("Interaction toolkit is not initialized"); - + var fromBuffer = _interaction.FirstByFilter(message => (requestId is null || message.Id == requestId) && (messageType is null || message.SchemaId == messageType)); - + 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)) + (messageType is not null && message.SchemaId != messageType)) continue; - + _interaction.HandleMessage(message); return message.Data; } @@ -82,8 +85,9 @@ namespace mROA.Implementation throw new NullReferenceException("Interaction toolkit is not initialized"); if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - +#if TRACE Console.WriteLine($"Posting message: {id} - {messageType}"); +#endif var serialized = _serialization.Serialize(payload, payloadType); await _interaction.PostMessage(new NetworkMessage diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index f99d420..e2e112c 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -79,7 +79,8 @@ namespace mROA.Implementation } } - [JsonIgnore] public T Value { get; private set; } + [JsonIgnore] + public T Value { get; private set; } // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once UnusedMember.Global @@ -106,6 +107,7 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); + [JsonIgnore] public IEndPointContext EndPointContext { get; set; } = new EndPointContext { RealRepository = TransmissionConfig.RealContextRepository, diff --git a/mROA/LegacyExtentions.cs b/mROA/LegacyExtentions.cs index d35c5a9..d0a3b29 100644 --- a/mROA/LegacyExtentions.cs +++ b/mROA/LegacyExtentions.cs @@ -1,8 +1,7 @@ -using System.Collections.Generic; -using global::System; -using global::System.IO; -using global::System.Threading; -using global::System.Threading.Tasks; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace mROA { diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index a436d48..cb237bf 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -12,6 +12,16 @@ git RPC 9 + Debug;Release + AnyCPU + + + + + + + + From b4ccfdd51c1b9fa6ee27c721bc4e7ada78f91fa4 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Wed, 26 Feb 2025 12:22:16 +0300 Subject: [PATCH 17/66] =?UTF-8?q?=D0=A4=D1=83=D0=BD=D0=BA=D1=86=D0=B8?= =?UTF-8?q?=D0=BE=D0=BD=D0=B0=D0=BB=20TransmittionConfig=20=D0=B2=D1=8B?= =?UTF-8?q?=D0=BD=D0=B5=D1=81=D0=B5=D0=BD=20=D0=B2=20=D0=BD=D0=B5=20=D1=81?= =?UTF-8?q?=D1=82=D0=B0=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20?= =?UTF-8?q?EndpointContext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Implementation/SharedObject.cs | 31 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index e2e112c..84d18bb 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json.Serialization; +using System.Threading.Tasks; using mROA.Abstract; // ReSharper disable UnusedMember.Global @@ -40,10 +41,18 @@ namespace mROA.Implementation public class SharedObject : ISharedObject where T : notnull { + [JsonIgnore] + public IEndPointContext EndPointContext { get; set; } = new EndPointContext + { + RealRepository = TransmissionConfig.RealContextRepository, + RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, + HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), + OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId + }; private IContextRepository GetDefaultContextRepository() => - (OwnerId == TransmissionConfig.OwnershipRepository.GetHostOwnershipId() - ? TransmissionConfig.RealContextRepository - : TransmissionConfig.RemoteEndpointContextRepository) ?? + (OwnerId == EndPointContext.HostId + ? EndPointContext.RealRepository + : EndPointContext.RemoteRepository) ?? throw new NullReferenceException( "DefaultContextRepository was not defined"); @@ -54,7 +63,7 @@ namespace mROA.Implementation { get { - _ownerId = _ownerId == -1 ? TransmissionConfig.OwnershipRepository.GetOwnershipId() : _ownerId; + _ownerId = _ownerId == -1 ? EndPointContext.OwnerId : _ownerId; return _ownerId; } set => _ownerId = value; @@ -69,7 +78,7 @@ namespace mROA.Implementation if (_contextId != -2) return _contextId; - _contextId = TransmissionConfig.RealContextRepository.GetObjectIndex(Value); + _contextId = EndPointContext.RealRepository.GetObjectIndex(Value); return _contextId; } set @@ -99,21 +108,13 @@ namespace mROA.Implementation _contextId = ro.Id; } else - _ownerId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(); + _ownerId = EndPointContext.HostId; } public static implicit operator T(SharedObject value) => value.Value; public static implicit operator SharedObject(T value) => new(value); - - [JsonIgnore] - public IEndPointContext EndPointContext { get; set; } = new EndPointContext - { - RealRepository = TransmissionConfig.RealContextRepository, - RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, - HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), - OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId - }; + } } \ No newline at end of file From 46732da78078e7b916e80fdcd7ef55438169f64f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 27 Feb 2025 00:12:52 +0300 Subject: [PATCH 18/66] =?UTF-8?q?=D0=94=D0=BE=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=BA=D0=B8=20=D0=B8=20=D0=B2=D0=BD=D0=B5=D0=B4=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20cbor=20=D1=81=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Program.cs | 4 +- Example.Frontend/Program.cs | 5 +- Example.Shared/Example.Shared.csproj | 1 + mROA.Cbor/CborSerializationToolkit.cs | 185 +++++++++++++----- mROA.Cbor/IContextualSerializationToolKit.cs | 18 +- mROA.Cbor/PreParsedValue.cs | 37 ++++ mROA.Test/CborTest.cs | 7 + mROA/Abstract/ISerializationToolkit.cs | 4 +- mROA/Implementation/CallRequest.cs | 3 +- .../CommandExecution/FinalCommandExecution.cs | 5 +- .../TypedFinalCommandExecution.cs | 3 +- mROA/Implementation/SharedObject.cs | 5 +- 12 files changed, 213 insertions(+), 64 deletions(-) create mode 100644 mROA.Cbor/PreParsedValue.cs diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 06bec62..30b50f6 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,6 +1,7 @@ using System.Net; using Example.Backend; using mROA.Abstract; +using mROA.Cbor; using mROA.Codegen; using mROA.Implementation; using mROA.Implementation.Backend; @@ -12,7 +13,8 @@ class Program public static void Main(string[] args) { var builder = new FullMixBuilder(); - builder.UseJsonSerialisation(); + // builder.UseJsonSerialisation(); + builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new BackendIdentityGenerator()); builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule), builder.GetModule()!); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 98d4f5f..93e5c81 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -5,6 +5,7 @@ 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; @@ -17,7 +18,9 @@ class Program { var builder = new FullMixBuilder(); new RemoteTypeBinder(); - builder.Modules.Add(new JsonSerializationToolkit()); + // 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()); diff --git a/Example.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj index 3d97856..f2050a6 100644 --- a/Example.Shared/Example.Shared.csproj +++ b/Example.Shared/Example.Shared.csproj @@ -9,6 +9,7 @@ + diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index af66e5e..3b7da43 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -26,38 +26,43 @@ namespace mROA.Cbor writer.Encode(destination); } - public T Deserialize(byte[] rawData, IEndPointContext context) + public T Deserialize(byte[] rawData, IEndPointContext? context) { - return (T)Deserialize(rawData, typeof(T), context); + return (T)Deserialize(rawData, typeof(T), context) ?? default; } - public object Deserialize(byte[] rawData, Type type, IEndPointContext context) + public object? Deserialize(byte[] rawData, Type type, IEndPointContext? context) { return Deserialize(rawData.AsMemory(), type, context); } - public T Deserialize(ReadOnlyMemory rawData, IEndPointContext context) + public T Deserialize(ReadOnlyMemory rawMemory, IEndPointContext? context) { - return (T)Deserialize(rawData, typeof(T), context); + return (T)Deserialize(rawMemory, typeof(T), context); } - public object Deserialize(ReadOnlyMemory rawData, Type type, IEndPointContext context) + public object? Deserialize(ReadOnlyMemory rawMemory, Type type, IEndPointContext? context) { - var reader = new CborReader(rawData); + var reader = new CborReader(rawMemory); return ReadData(reader, type, context); } - public T Cast(object nonCasted, IEndPointContext context) + public T Cast(object nonCasted, IEndPointContext? context) { return (T)Cast(nonCasted, typeof(T), context); } - public object Cast(object nonCasted, Type type, IEndPointContext context) + public object Cast(object nonCasted, Type type, IEndPointContext? context) { + if (nonCasted.GetType() == type) + return nonCasted; + + if (nonCasted is PreParsedValue preParsed) + return preParsed.ToObject(type, context); return null; } - private void WriteData(object? obj, CborWriter writer, IEndPointContext context) + private void WriteData(object? obj, CborWriter writer, IEndPointContext? context) { switch (obj) { @@ -94,6 +99,9 @@ namespace mROA.Cbor case DateTimeOffset dto: writer.WriteDateTimeOffset(dto); break; + case Guid g: + writer.WriteByteString(g.ToByteArray()); + break; case byte[] bytes: writer.WriteByteString(bytes); break; @@ -104,13 +112,14 @@ namespace mROA.Cbor WriteList(enumerable, writer, context); break; case ISharedObject sharedObject: - sharedObject.EndPointContext = context; + if (context != null) + sharedObject.EndPointContext = context; WriteObject(sharedObject, writer, context); break; default: if (obj.GetType().IsEnum) { - writer.WriteUInt32((uint)obj); + writer.WriteInt32((int)obj); break; } @@ -119,7 +128,7 @@ namespace mROA.Cbor } } - private void WriteList(IList list, CborWriter writer, IEndPointContext context) + private void WriteList(IList list, CborWriter writer, IEndPointContext? context) { writer.WriteStartArray(list.Count); @@ -129,7 +138,7 @@ namespace mROA.Cbor writer.WriteEndArray(); } - private void WriteDictionary(IDictionary dictionary, CborWriter writer, IEndPointContext context) + private void WriteDictionary(IDictionary dictionary, CborWriter writer, IEndPointContext? context) { writer.WriteStartMap(dictionary.Count); var keysEnumerator = dictionary.Keys.GetEnumerator(); @@ -147,7 +156,7 @@ namespace mROA.Cbor (valuesEnumerator as IDisposable)?.Dispose(); } - private void WriteObject(object obj, CborWriter writer, IEndPointContext context) + private void WriteObject(object obj, CborWriter writer, IEndPointContext? context) { var type = obj.GetType(); var properties = FilterProperties(type.GetProperties()); @@ -155,7 +164,7 @@ namespace mROA.Cbor WriteList(values, writer, context); } - private object ReadData(CborReader reader, Type? type, IEndPointContext context) + private object? ReadData(CborReader reader, Type? type, IEndPointContext? context) { var state = reader.PeekState(); switch (state) @@ -164,20 +173,24 @@ namespace mROA.Cbor return reader.ReadBoolean(); case CborReaderState.UnsignedInteger: case CborReaderState.NegativeInteger: - if (type == typeof(int)) + if (type == typeof(int) || type is { IsEnum: true }) return reader.ReadInt32(); if (type == typeof(long)) return reader.ReadInt64(); - if (type == typeof(uint) || type.IsEnum) + if (type == typeof(uint)) return reader.ReadUInt32(); if (type == typeof(ulong)) return reader.ReadUInt64(); - break; + + return reader.ReadInt32(); 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(); @@ -207,36 +220,51 @@ namespace mROA.Cbor } - private Array ReadList(CborReader reader, Type? type, IEndPointContext context) + 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(); - else if (typeof(IList).IsAssignableFrom(type)) + 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]; - - Array values = Array.CreateInstance(elementType, length.Value); - + else elementType = typeof(object); + Type genericListType = typeof(List<>).MakeGenericType(elementType); + var list = (IList)Activator.CreateInstance(genericListType, length); for (int i = 0; i < length; i++) { - values.SetValue(ReadData(reader, elementType, context), i); + list.Add(ReadData(reader, elementType, context)); } reader.ReadEndArray(); - return values; + + + return list; + + + return null; } - reader.ReadEndArray(); - - return Array.Empty(); + return null; } - private IDictionary ReadDictionary(CborReader reader, Type type, IEndPointContext context) + private IDictionary ReadDictionary(CborReader reader, Type type, IEndPointContext? context) { var dictionaryInstance = (Activator.CreateInstance(type) as IDictionary)!; var length = reader.ReadStartArray(); @@ -253,8 +281,13 @@ namespace mROA.Cbor return dictionaryInstance; } - private object ReadObject(CborReader reader, Type type, IEndPointContext context) + private object ReadObject(CborReader reader, Type type, IEndPointContext? context) { + if (type == typeof(object)) + { + return new PreParsedValue(ReadList(reader, null, context) as List); + } + var instance = Activator.CreateInstance(type)!; FillObject(instance, type, reader, context); @@ -262,32 +295,50 @@ namespace mROA.Cbor return instance; } - private ISharedObject ReadSharedObject(CborReader reader, Type type, IEndPointContext context) + private ISharedObject ReadSharedObject(CborReader reader, Type type, IEndPointContext? context) { var sharedObject = (Activator.CreateInstance(type) as ISharedObject)!; - sharedObject.EndPointContext = context; + if (context != null) + { + sharedObject.EndPointContext = context; + } FillObject(sharedObject, type, reader, context); return sharedObject; } - private void FillObject(object obj, Type type, CborReader reader, IEndPointContext context) + private void FillObject(object obj, Type type, CborReader reader, IEndPointContext? context) { - var properties = FilterProperties(type.GetProperties()); - - _ = reader.ReadStartArray(); - - foreach (var property in properties) + try { - var value = ReadData(reader, property.PropertyType, context); - property.SetValue(obj, value); - } + var propertyInfos = type.GetProperties(); + var properties = FilterProperties(propertyInfos); - reader.ReadEndArray(); + var length = reader.ReadStartArray(); +#if TRACE + Console.WriteLine($"Reading list of {length} objects, {properties.Count} properties found"); +#endif + + for (var index = 0; index < length; index++) + { + var property = properties[index]; + var value = ReadData(reader, property.PropertyType, context); + property.SetValue(obj, value); + } + + reader.ReadEndArray(); + } + catch (Exception e) + { + Console.WriteLine(e); + reader.ReadEndArray(); + + throw; + } } - private List FilterProperties(PropertyInfo[] properties) + public static List FilterProperties(PropertyInfo[] properties) { var finalProperties = new List(properties.Length); foreach (var property in properties) @@ -298,5 +349,49 @@ namespace mROA.Cbor return finalProperties; } + + 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); + } } } \ No newline at end of file diff --git a/mROA.Cbor/IContextualSerializationToolKit.cs b/mROA.Cbor/IContextualSerializationToolKit.cs index c7ee66c..957ca29 100644 --- a/mROA.Cbor/IContextualSerializationToolKit.cs +++ b/mROA.Cbor/IContextualSerializationToolKit.cs @@ -3,15 +3,15 @@ using mROA.Abstract; namespace mROA.Cbor { - public interface IContextualSerializationToolKit + public interface IContextualSerializationToolKit : ISerializationToolkit { - byte[] Serialize(object objectToSerialize, IEndPointContext context); - void Serialize(object objectToSerialize, Span destination, IEndPointContext context); - T Deserialize(byte[] rawData, IEndPointContext context); - object Deserialize(byte[] rawData, Type type, IEndPointContext context); - T Deserialize(ReadOnlyMemory rawData, IEndPointContext context); - object Deserialize(ReadOnlyMemory rawData, Type type, IEndPointContext context); - T Cast(object nonCasted, IEndPointContext context); - object Cast(object nonCasted, Type type, IEndPointContext context); + byte[] Serialize(object objectToSerialize, IEndPointContext? context); + void Serialize(object objectToSerialize, Span destination, IEndPointContext? context); + T Deserialize(byte[] rawData, IEndPointContext? context); + object? Deserialize(byte[] rawData, Type type, IEndPointContext? context); + T Deserialize(ReadOnlyMemory rawMemory, IEndPointContext? context); + object? Deserialize(ReadOnlyMemory rawMemory, Type type, IEndPointContext? context); + T Cast(object nonCasted, IEndPointContext? context); + object? Cast(object nonCasted, Type type, IEndPointContext? context); } } \ No newline at end of file diff --git a/mROA.Cbor/PreParsedValue.cs b/mROA.Cbor/PreParsedValue.cs new file mode 100644 index 0000000..e8e6379 --- /dev/null +++ b/mROA.Cbor/PreParsedValue.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using mROA.Abstract; +using mROA.Implementation; + +namespace mROA.Cbor +{ + public class PreParsedValue + { + public List Properties { get; set; } + + public PreParsedValue(List properties) + { + Properties = properties; + } + + public object? ToObject(Type type, IEndPointContext? context) + { + var instance = Activator.CreateInstance(type); + if (instance == null) + return null; + + if (instance is ISharedObject sharedObject && context != null) + { + sharedObject.EndPointContext = context; + } + + var properties = CborSerializationToolkit.FilterProperties(type.GetProperties()); + for (var index = 0; index < properties.Count; index++) + { + var property = properties[index]; + property.SetValue(instance, Properties[index]); + } + return instance; + } + } +} \ No newline at end of file diff --git a/mROA.Test/CborTest.cs b/mROA.Test/CborTest.cs index a6d1bf2..cfa7d20 100644 --- a/mROA.Test/CborTest.cs +++ b/mROA.Test/CborTest.cs @@ -21,6 +21,7 @@ public class CborTest IntValue = 123, DoubleValue = 3.14159, StringValue = "abc", + EnumValue = TestEnum.X, CollectionElements = [ _basicCollectionElement, @@ -69,6 +70,7 @@ public class CborTest 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; } @@ -115,4 +117,9 @@ public class CborTest return HashCode.Combine(A, B, C); } } + + public enum TestEnum + { + X = -5, Y, Z + } } \ No newline at end of file diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs index fbb48d2..b3502f8 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -10,8 +10,8 @@ namespace mROA.Abstract 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); + T? Cast(object nonCasted); + object? Cast(object nonCasted, Type type); } } \ No newline at end of file diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 1d51e7e..db38e5e 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json.Serialization; +using mROA.Implementation.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global @@ -20,7 +21,7 @@ namespace mROA.Implementation public int CommandId { get; set; } public int ObjectId { get; set; } = -1; - [JsonIgnore] + [SerializationIgnore] public Type? ParameterType { get; set; } public object? Parameter { get; set; } diff --git a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs index 5fa3f31..331928d 100644 --- a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs @@ -1,6 +1,7 @@ using System; using System.Text.Json.Serialization; using mROA.Abstract; +using mROA.Implementation.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -9,9 +10,9 @@ namespace mROA.Implementation.CommandExecution public class FinalCommandExecution : ICommandExecution { public Guid Id { get; set; } - [JsonIgnore] + [SerializationIgnore] public int ClientId { get; set; } - [JsonIgnore] + [SerializationIgnore] public int CommandId { get; set; } } diff --git a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs b/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs index b998737..47ff4b1 100644 --- a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs @@ -1,11 +1,12 @@ using System; using System.Text.Json.Serialization; +using mROA.Implementation.Attributes; namespace mROA.Implementation.CommandExecution { public class TypedFinalCommandExecution : FinalCommandExecution { - [JsonIgnore] + [SerializationIgnore] // ReSharper disable once UnusedAutoPropertyAccessor.Global public Type? Type { get; set; } } diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 84d18bb..2eb3b47 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -2,6 +2,7 @@ using System.Text.Json.Serialization; using System.Threading.Tasks; using mROA.Abstract; +using mROA.Implementation.Attributes; // ReSharper disable UnusedMember.Global #pragma warning disable CS8618, CS9264 @@ -41,7 +42,7 @@ namespace mROA.Implementation public class SharedObject : ISharedObject where T : notnull { - [JsonIgnore] + [SerializationIgnore] public IEndPointContext EndPointContext { get; set; } = new EndPointContext { RealRepository = TransmissionConfig.RealContextRepository, @@ -88,7 +89,7 @@ namespace mROA.Implementation } } - [JsonIgnore] + [SerializationIgnore] public T Value { get; private set; } // ReSharper disable once MemberCanBePrivate.Global From 5718f9c313bed63365304a1e11cb7687991c7f7a Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 27 Feb 2025 08:40:22 +0300 Subject: [PATCH 19/66] cbor works --- Example.Backend/Example.Backend.csproj | 4 ++ Example.Backend/Program.cs | 2 +- Example.Frontend/Example.Frontend.csproj | 8 ++++ mROA.Cbor/mROA.Cbor.csproj | 8 ++++ mROA/Abstract/ICommandExecution.cs | 2 - .../Backend/BasicExecutionModule.cs | 47 ++++++++++--------- .../CommandExecution/AsyncCommandExecution.cs | 2 - .../ExceptionCommandExecution.cs | 2 - .../CommandExecution/FinalCommandExecution.cs | 5 -- .../TypedFinalCommandExecution.cs | 13 ----- 10 files changed, 45 insertions(+), 48 deletions(-) delete mode 100644 mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index 4f357b7..b951e33 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -14,6 +14,10 @@ + + + + diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 30b50f6..7c5bcc9 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -34,7 +34,7 @@ class Program })); builder.SetupMethodsRepository(new CoCodegenMethodRepository()); builder.Modules.Add(new CreativeRepresentationModuleProducer( - new IInjectableModule[] { builder.GetModule()! }, + new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); builder.Modules.Add(new CancellationRepository()); diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index 35760b9..207a2b2 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -9,6 +9,14 @@ 9 + + + + + + + + diff --git a/mROA.Cbor/mROA.Cbor.csproj b/mROA.Cbor/mROA.Cbor.csproj index 7f66dce..a2dbaf9 100644 --- a/mROA.Cbor/mROA.Cbor.csproj +++ b/mROA.Cbor/mROA.Cbor.csproj @@ -5,6 +5,14 @@ enable + + + + + + + + diff --git a/mROA/Abstract/ICommandExecution.cs b/mROA/Abstract/ICommandExecution.cs index 210b976..5037a4e 100644 --- a/mROA/Abstract/ICommandExecution.cs +++ b/mROA/Abstract/ICommandExecution.cs @@ -5,7 +5,5 @@ namespace mROA.Abstract public interface ICommandExecution { Guid Id { get; set; } - int ClientId { get; set; } - int CommandId { get; } } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 3173d37..c1522ca 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -43,8 +43,7 @@ namespace mROA.Implementation.Backend _cancellationRepo.FreeCancelation(command.Id); return new FinalCommandExecution { - Id = command.Id, - CommandId = command.CommandId + Id = command.Id }; } @@ -76,7 +75,7 @@ namespace mROA.Implementation.Backend #endif contextRepository.ClearObject(command.ObjectId); } - + return result; } catch (Exception e) @@ -84,8 +83,6 @@ namespace mROA.Implementation.Backend Console.WriteLine(e); throw; } - - } private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, @@ -98,19 +95,26 @@ namespace mROA.Implementation.Backend : new[] { parameter }; var finalResult = currentCommand.Invoke(context, finalParameter); - - return new TypedFinalCommandExecution + + if (currentCommand.ReturnType.Name == "Void") { - CommandId = command.CommandId, Result = finalResult, - Id = command.Id, - Type = currentCommand.ReturnType + return new FinalCommandExecution + { + Id = command.Id + }; + } + + return new FinalCommandExecution + { + Result = finalResult, + Id = command.Id }; } catch (Exception e) { return new ExceptionCommandExecution { - Id = command.Id, CommandId = command.CommandId, + Id = command.Id, Exception = e.ToString() }; } @@ -139,17 +143,16 @@ namespace mROA.Implementation.Backend { if (token.IsCancellationRequested) return; - + var payload = new FinalCommandExecution { - Id = command.Id, - CommandId = command.CommandId + 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(); @@ -157,14 +160,14 @@ namespace mROA.Implementation.Backend return new AsyncCommandExecution { - Id = command.Id, CommandId = command.CommandId + Id = command.Id }; } catch (Exception e) { return new ExceptionCommandExecution { - Id = command.Id, CommandId = command.CommandId, + Id = command.Id, Exception = e.ToString() }; } @@ -190,12 +193,10 @@ namespace mROA.Implementation.Backend result.ContinueWith(t => { var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); - var payload = new TypedFinalCommandExecution + var payload = new FinalCommandExecution { Id = command.Id, - Result = finalResult, - CommandId = command.CommandId, - Type = finalResult?.GetType() + Result = finalResult }; _cancellationRepo.FreeCancelation(command.Id); @@ -208,14 +209,14 @@ namespace mROA.Implementation.Backend return new AsyncCommandExecution { - Id = command.Id, CommandId = command.CommandId + Id = command.Id }; } catch (Exception e) { return new ExceptionCommandExecution { - Id = command.Id, CommandId = command.CommandId, + Id = command.Id, Exception = e.ToString() }; } diff --git a/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs index fcddf6e..7dea41d 100644 --- a/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/AsyncCommandExecution.cs @@ -6,7 +6,5 @@ namespace mROA.Implementation.CommandExecution public class AsyncCommandExecution : ICommandExecution { public Guid Id { get; set; } - public int ClientId { get; set; } - public int CommandId { get; set; } } } \ No newline at end of file diff --git a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs index c9d32ab..82a63de 100644 --- a/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/ExceptionCommandExecution.cs @@ -7,8 +7,6 @@ namespace mROA.Implementation.CommandExecution public class ExceptionCommandExecution : ICommandExecution { public Guid Id { get; set; } - public int ClientId { get; set; } - public int CommandId { get; set; } public string Exception { get; set; } public RemoteException GetException() diff --git a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs index 331928d..2a99331 100644 --- a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs @@ -1,7 +1,6 @@ using System; using System.Text.Json.Serialization; using mROA.Abstract; -using mROA.Implementation.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -10,10 +9,6 @@ namespace mROA.Implementation.CommandExecution public class FinalCommandExecution : ICommandExecution { public Guid Id { get; set; } - [SerializationIgnore] - public int ClientId { get; set; } - [SerializationIgnore] - public int CommandId { get; set; } } public class FinalCommandExecution : FinalCommandExecution diff --git a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs b/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs deleted file mode 100644 index 47ff4b1..0000000 --- a/mROA/Implementation/CommandExecution/TypedFinalCommandExecution.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Text.Json.Serialization; -using mROA.Implementation.Attributes; - -namespace mROA.Implementation.CommandExecution -{ - public class TypedFinalCommandExecution : FinalCommandExecution - { - [SerializationIgnore] - // ReSharper disable once UnusedAutoPropertyAccessor.Global - public Type? Type { get; set; } - } -} \ No newline at end of file From 906bda7000e9f8b6cec99752ce968f67619ecbef Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 27 Feb 2025 09:01:21 +0300 Subject: [PATCH 20/66] =?UTF-8?q?=D0=98=D1=82=D0=BE=D0=B3=D0=BE=D0=B2?= =?UTF-8?q?=D0=BE=D0=B5=20=D1=83=D0=BC=D0=B5=D0=BD=D1=8C=D1=88=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B0=D0=B2=D0=B0?= =?UTF-8?q?=D0=B5=D0=BC=D0=BE=D0=B9=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D0=B8=20=D0=B2=204=20=D1=80=D0=B0=D0=B7?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 4 ++-- Example.Backend/Program.cs | 2 +- Example.Frontend/Example.Frontend.csproj | 2 +- mROA/Implementation/CallRequest.cs | 4 ---- mROA/Implementation/NextGenerationInteractionModule.cs | 3 +++ mROA/Implementation/RemoteObjectBase.cs | 6 ++++-- mROA/Implementation/SharedObject.cs | 9 ++++++--- mROA/mROA.csproj | 2 +- 8 files changed, 18 insertions(+), 14 deletions(-) diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index b951e33..d29fff5 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -11,11 +11,11 @@ - + TRACE - + TRACE; diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 7c5bcc9..f31f557 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -34,7 +34,7 @@ class Program })); builder.SetupMethodsRepository(new CoCodegenMethodRepository()); builder.Modules.Add(new CreativeRepresentationModuleProducer( - new IInjectableModule[] { builder.GetModule()! }, + new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); builder.Modules.Add(new CancellationRepository()); diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index 207a2b2..a12fa05 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -14,7 +14,7 @@ - + TRACE; diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index db38e5e..a6235f1 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -1,5 +1,4 @@ using System; -using System.Text.Json.Serialization; using mROA.Implementation.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -21,9 +20,6 @@ namespace mROA.Implementation public int CommandId { get; set; } public int ObjectId { get; set; } = -1; - [SerializationIgnore] - public Type? ParameterType { get; set; } - public object? Parameter { get; set; } public override string ToString() { diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index e9416e9..68239ea 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -82,6 +82,7 @@ namespace mROA.Implementation var len = BitConverter.ToUInt16(new[] { firstBit, secondBit}); var localSpan = _buffer.Slice(0, len); + await BaseStream.ReadExactlyAsync(localSpan); // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); @@ -89,6 +90,8 @@ namespace mROA.Implementation var message = _serialization.Deserialize(localSpan.Span); #if TRACE Console.WriteLine($"Received Message {message.SchemaId} - {message.Id}"); + TransmissionConfig.TotalTransmittedBytes += len; + Console.WriteLine($"Total recieced bytes are {TransmissionConfig.TotalTransmittedBytes}"); #endif _messageBuffer.Add(message); _currentReceiving = Task.Run(async () => await GetNextMessage()); diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index a81c255..e1381dd 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -26,7 +26,8 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; + { CommandId = methodId, ObjectId = _id, Parameter = parameter + }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); @@ -79,7 +80,8 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _id, Parameter = parameter, ParameterType = parameter?.GetType() }; + { CommandId = methodId, ObjectId = _id, Parameter = parameter + }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); var localTokenSource = new CancellationTokenSource(); diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 2eb3b47..b9d5256 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -11,6 +11,9 @@ namespace mROA.Implementation { public static class TransmissionConfig { +#if TRACE + public static int TotalTransmittedBytes { get; set; } = 0; +#endif private static IContextRepository? _realContextRepository; private static IContextRepository? _remoteEndpointContextRepository; private static IOwnershipRepository? _ownershipRepository; @@ -43,6 +46,7 @@ namespace mROA.Implementation public class SharedObject : ISharedObject where T : notnull { [SerializationIgnore] + [JsonIgnore] public IEndPointContext EndPointContext { get; set; } = new EndPointContext { RealRepository = TransmissionConfig.RealContextRepository, @@ -50,6 +54,7 @@ namespace mROA.Implementation HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId }; + private IContextRepository GetDefaultContextRepository() => (OwnerId == EndPointContext.HostId ? EndPointContext.RealRepository @@ -89,8 +94,7 @@ namespace mROA.Implementation } } - [SerializationIgnore] - public T Value { get; private set; } + [JsonIgnore] [SerializationIgnore] public T Value { get; private set; } // ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once UnusedMember.Global @@ -116,6 +120,5 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); - } } \ No newline at end of file diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index cb237bf..5702597 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - + TRACE; From 3c88e4f768f6cef43735668457a396d0815707bb Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 1 Mar 2025 15:11:11 +0300 Subject: [PATCH 21/66] =?UTF-8?q?=D0=9F=D0=BE=D0=BA=D0=B0=20=D1=87=D1=82?= =?UTF-8?q?=D0=BE=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20IDa?= =?UTF-8?q?taList=20=D0=B8=D0=B7=20=D0=B4=D0=B5=D0=BC=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Shared/IDataList.cs | 12 +++ mROA.Codegen/mROASourceGenerator.cs | 76 ++----------------- .../Backend/BasicExecutionModule.cs | 2 +- mROA/Implementation/SharedObject.cs | 2 +- 4 files changed, 21 insertions(+), 71 deletions(-) create mode 100644 Example.Shared/IDataList.cs diff --git a/Example.Shared/IDataList.cs b/Example.Shared/IDataList.cs new file mode 100644 index 0000000..90792d4 --- /dev/null +++ b/Example.Shared/IDataList.cs @@ -0,0 +1,12 @@ +using mROA.Implementation.Attributes; + +namespace Example.Shared +{ + // [SharedObjectInterface] + // public interface IDataList + // { + // T Get(int index); + // void Add(T item); + // void Set(int index, T item); + // } +} \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 70eefa9..b0cd06c 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -30,48 +30,6 @@ namespace {Namespace} }} }}"; - // 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). - /// - /// Syntax context, based on CreateSyntaxProvider predicate - /// The specific cast and whether the attribute was found. - // private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen( - // GeneratorSyntaxContext context) - // { - // var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node; - // - // // Go through all attributes of the class. - // foreach (AttributeListSyntax attributeListSyntax in classDeclarationSyntax.AttributeLists) - // foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) - // { - // 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. @@ -99,6 +57,8 @@ namespace {Namespace} var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); + + // 'Identifier' means the token of the node. Get class name from the syntax node. var className = classDeclarationSyntax.Identifier.Text; @@ -112,14 +72,13 @@ namespace {Namespace} var methodsText = new List(); - + foreach (var method in methodBody) { var index = methods.Count; methods.Add((namespaceName + "." + originalName, method)); var sb = new StringBuilder(); - bool isAsync = method.ReturnType.Name == "Task"; bool isVoid = method.ReturnType.Name == "Void" || method.ReturnType.ToString() == "System.Threading.Tasks.Task"; @@ -151,30 +110,6 @@ namespace {Namespace} 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\t" + prefix + caller + postfix + ";"); sb.AppendLine("\t\t}"); @@ -213,8 +148,11 @@ namespace {namespaceName} if (methods.Count != 0) { + // var methodsStringed = methods.Select(i => + // $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})") + // .ToList(); var methodsStringed = methods.Select(i => - $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})") + $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\")") .ToList(); var coCodegenRepoCode = @$"// diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index c1522ca..443a366 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -148,7 +148,7 @@ namespace mROA.Implementation.Backend { Id = command.Id }; - _cancellationRepo.FreeCancelation(command.Id); + _cancellationRepo?.FreeCancelation(command.Id); var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index b9d5256..af7847e 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -12,7 +12,7 @@ namespace mROA.Implementation public static class TransmissionConfig { #if TRACE - public static int TotalTransmittedBytes { get; set; } = 0; + public static int TotalTransmittedBytes { get; set; } #endif private static IContextRepository? _realContextRepository; private static IContextRepository? _remoteEndpointContextRepository; From af65f22aa9bc7019326de20735982164dd96cf40 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 1 Mar 2025 15:54:01 +0300 Subject: [PATCH 22/66] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BD=D0=B0=20Uni?= =?UTF-8?q?versalObjectIdentifier.=20=D0=A7=D0=B0=D1=81=D1=82=D1=8C=201?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 2 +- Example.Frontend/Example.Frontend.csproj | 2 +- mROA.Cbor/CborSerializationToolkit.cs | 2 ++ mROA.Test/UnSOization.cs | 26 +++++++++++++++ mROA/Implementation/RemoteObjectBase.cs | 16 ++++----- mROA/Implementation/SharedObject.cs | 41 ++++++++++++++++++++++++ mROA/mROA.csproj | 2 +- 7 files changed, 80 insertions(+), 11 deletions(-) create mode 100644 mROA.Test/UnSOization.cs diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index d29fff5..06f0ed2 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -15,7 +15,7 @@ - TRACE; + diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index a12fa05..8ad6b28 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -14,7 +14,7 @@ - TRACE; + diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 3b7da43..6c50427 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -12,6 +12,7 @@ namespace mROA.Cbor { public class CborSerializationToolkit : IContextualSerializationToolKit { + private List _remoteTypes; public byte[] Serialize(object objectToSerialize, IEndPointContext context) { var writer = new CborWriter(); @@ -352,6 +353,7 @@ namespace mROA.Cbor public void Inject(T dependency) { + _remoteTypes = RemoteContextRepository.RemoteTypes.Keys.ToList(); } public byte[] Serialize(T objectToSerialize) diff --git a/mROA.Test/UnSOization.cs b/mROA.Test/UnSOization.cs new file mode 100644 index 0000000..afdcb9e --- /dev/null +++ b/mROA.Test/UnSOization.cs @@ -0,0 +1,26 @@ +using mROA.Implementation; + +namespace mROA.Test; + +public class UnSOization +{ + private UniversalObjectIdentifier _uoi; + + [SetUp] + public void Setup() + { + _uoi = new UniversalObjectIdentifier + { + ContextId = -123, OwnerId = 123 + }; + } + + [Test] + public void FlatTest() + { + var flat = _uoi.Flat; + var next = new UniversalObjectIdentifier { Flat = flat }; + + Assert.That(_uoi, Is.EqualTo(next)); + } +} \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index e1381dd..535d5ba 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -10,23 +10,23 @@ namespace mROA.Implementation { public abstract class RemoteObjectBase : IDisposable { - private readonly int _id; + private readonly UniversalObjectIdentifier _identifier; private readonly IRepresentationModule _representationModule; protected RemoteObjectBase(int id, IRepresentationModule representationModule) { - _id = id; + _identifier = new UniversalObjectIdentifier { ContextId = id, OwnerId = representationModule.Id }; _representationModule = representationModule; } - public int Id => _id; - public int OwnerId => _representationModule.Id; + public int Id => _identifier.ContextId; + public int OwnerId => _identifier.OwnerId; protected async Task GetResultAsync(int methodId, object? parameter = default, CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _id, Parameter = parameter + { CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); @@ -80,7 +80,7 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _id, Parameter = parameter + { CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); @@ -124,14 +124,14 @@ namespace mROA.Implementation public void Dispose() { - if (_id == -1) + if (_identifier.IsStatic) return; CallAsync(-1).Wait(); } public override string ToString() { - return $"{{Id : {_id}, OwnerId : {OwnerId} }}"; + return _identifier.ToString(); } } } \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index af7847e..67c97d9 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -121,4 +121,45 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); } + + public struct UniversalObjectIdentifier : IEquatable + { + public int ContextId; + public int OwnerId; + + public override string ToString() + { + return $"{nameof(ContextId)}: {ContextId}, {nameof(OwnerId)}: {OwnerId}"; + } + + public bool IsStatic => ContextId == -1; + + public ulong Flat + { + get + { + return (ulong)OwnerId << 32 | (uint)ContextId; + } + set + { + OwnerId = (int)(value >> 32); + ContextId = (int)(value & 0xFFFFFFFF); + } + } + + public bool Equals(UniversalObjectIdentifier other) + { + return ContextId == other.ContextId && OwnerId == other.OwnerId; + } + + public override bool Equals(object? obj) + { + return obj is UniversalObjectIdentifier other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(ContextId, OwnerId); + } + } } \ No newline at end of file diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 5702597..e9d980c 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - TRACE; + From 8f891ff59e051d972e170c72d35e391b5847c06f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 1 Mar 2025 16:40:40 +0300 Subject: [PATCH 23/66] =?UTF-8?q?=D0=AF=20=D1=81=D0=B0=D0=BC=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=B7=D0=BD=D0=B0=D1=8E=20=D0=BA=D0=B0=D0=BA=20=D0=B8?= =?UTF-8?q?=20=D1=87=D1=82=D0=BE,=20=D0=BD=D0=BE=20=D0=BE=D0=BD=D0=BE=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=BA=D0=B0?= =?UTF-8?q?=D0=BA=20=D1=82=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Cbor/CborSerializationToolkit.cs | 12 +- mROA.Cbor/PreParsedValue.cs | 32 +++++- .../Backend/ContextRepository.cs | 2 +- .../Backend/MultiClientContextRepository.cs | 4 +- .../Implementation/RemoteContextRepository.cs | 4 +- mROA/Implementation/RemoteObjectBase.cs | 2 +- mROA/Implementation/SharedObject.cs | 107 +++++++----------- .../UniversalObjectIdentifier.cs | 47 ++++++++ 8 files changed, 128 insertions(+), 82 deletions(-) create mode 100644 mROA/Implementation/UniversalObjectIdentifier.cs diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 6c50427..3fda2b2 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -183,7 +183,7 @@ namespace mROA.Cbor if (type == typeof(ulong)) return reader.ReadUInt64(); - return reader.ReadInt32(); + return reader.ReadUInt64(); case CborReaderState.ByteString: if (type == typeof(Guid)) return new Guid(reader.ReadByteString()); @@ -284,6 +284,7 @@ namespace mROA.Cbor private object ReadObject(CborReader reader, Type type, IEndPointContext? context) { + if (type == typeof(object)) { return new PreParsedValue(ReadList(reader, null, context) as List); @@ -311,12 +312,13 @@ namespace mROA.Cbor private void FillObject(object obj, Type type, CborReader reader, IEndPointContext? context) { + var propertyInfos = type.GetProperties(); + var properties = FilterProperties(propertyInfos); + + var length = reader.ReadStartArray(); try { - var propertyInfos = type.GetProperties(); - var properties = FilterProperties(propertyInfos); - var length = reader.ReadStartArray(); #if TRACE Console.WriteLine($"Reading list of {length} objects, {properties.Count} properties found"); #endif @@ -342,7 +344,7 @@ namespace mROA.Cbor public static List FilterProperties(PropertyInfo[] properties) { var finalProperties = new List(properties.Length); - foreach (var property in properties) + foreach (var property in properties.Where(i => i.CanWrite && i.CanRead)) { if (property.GetCustomAttribute() == null) finalProperties.Add(property); diff --git a/mROA.Cbor/PreParsedValue.cs b/mROA.Cbor/PreParsedValue.cs index e8e6379..5109c98 100644 --- a/mROA.Cbor/PreParsedValue.cs +++ b/mROA.Cbor/PreParsedValue.cs @@ -5,13 +5,18 @@ using mROA.Implementation; namespace mROA.Cbor { - public class PreParsedValue + public interface IPreParsedValue { - public List Properties { get; set; } + object? ToObject(Type type, IEndPointContext? context); + } + + public class PreParsedValue : IPreParsedValue + { + private List _properties { get; set; } public PreParsedValue(List properties) { - Properties = properties; + _properties = properties; } public object? ToObject(Type type, IEndPointContext? context) @@ -24,14 +29,31 @@ namespace mROA.Cbor { sharedObject.EndPointContext = context; } - + var properties = CborSerializationToolkit.FilterProperties(type.GetProperties()); for (var index = 0; index < properties.Count; index++) { var property = properties[index]; - property.SetValue(instance, Properties[index]); + property.SetValue(instance, _properties[index] is IPreParsedValue ppv ? ppv.ToObject(property.PropertyType, context) : _properties[index]); } + return instance; } } + + public class ParsedValue : IPreParsedValue + { + public ParsedValue(object? value) + { + _value = value; + } + + private object? _value; + + + public object? ToObject(Type type, IEndPointContext? context) + { + return _value; + } + } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 109c02a..65c4acf 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -60,7 +60,7 @@ namespace mROA.Implementation.Backend public T GetObjectBySharedObject(SharedObject sharedObject) { - return (T)GetObject(sharedObject.ContextId); + return (T)GetObject(sharedObject.Identifier.ContextId); } public object GetObject(int id) diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index d997ad2..e89be32 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -41,8 +41,8 @@ namespace mROA.Implementation.Backend public T GetObjectBySharedObject(SharedObject sharedObject) { - var repository = GetRepository(sharedObject.OwnerId); - return repository.GetObject(sharedObject.ContextId); + var repository = GetRepository(sharedObject.Identifier.OwnerId); + return repository.GetObject(sharedObject.Identifier.ContextId); } public object GetObject(int id) diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 9fb7191..1990780 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -25,8 +25,8 @@ namespace mROA.Implementation throw new NullReferenceException("representation producer is not initialized"); if (!RemoteTypes.TryGetValue(typeof(T), out var remoteType)) throw new NotSupportedException(); - var representationModule = _representationProducer.Produce(sharedObject.OwnerId); - var remote = (T)Activator.CreateInstance(remoteType, sharedObject.ContextId, + var representationModule = _representationProducer.Produce(sharedObject.Identifier.OwnerId); + var remote = (T)Activator.CreateInstance(remoteType, sharedObject.Identifier.ContextId, representationModule)!; return remote; } diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 535d5ba..b74b58a 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -21,7 +21,7 @@ namespace mROA.Implementation public int Id => _identifier.ContextId; public int OwnerId => _identifier.OwnerId; - + public UniversalObjectIdentifier Identifier => _identifier; protected async Task GetResultAsync(int methodId, object? parameter = default, CancellationToken cancellationToken = default) { diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index 67c97d9..1f8aae5 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -56,44 +56,58 @@ namespace mROA.Implementation }; private IContextRepository GetDefaultContextRepository() => - (OwnerId == EndPointContext.HostId + (_identifier.OwnerId == EndPointContext.HostId ? EndPointContext.RealRepository : EndPointContext.RemoteRepository) ?? throw new NullReferenceException( "DefaultContextRepository was not defined"); - private int _contextId = -2; - private int _ownerId = -1; + private UniversalObjectIdentifier _identifier = UniversalObjectIdentifier.Null; - public int OwnerId + public UniversalObjectIdentifier Identifier { get { - _ownerId = _ownerId == -1 ? EndPointContext.OwnerId : _ownerId; - return _ownerId; - } - set => _ownerId = value; - } - - // ReSharper disable once MemberCanBePrivate.Global - public int ContextId - { - // ReSharper disable once UnusedMember.Global - get - { - if (_contextId != -2) - return _contextId; - - _contextId = EndPointContext.RealRepository.GetObjectIndex(Value); - return _contextId; + _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; + return _identifier; } set { - _contextId = value; + _identifier = value; Value = GetDefaultContextRepository().GetObjectBySharedObject(this); } } + + // public int OwnerId + // { + // get + // { + // _ownerId = _ownerId == -1 ? EndPointContext.OwnerId : _ownerId; + // return _ownerId; + // } + // set => _ownerId = value; + // } + // + // // ReSharper disable once MemberCanBePrivate.Global + // public int ContextId + // { + // // ReSharper disable once UnusedMember.Global + // get + // { + // if (_contextId != -2) + // return _contextId; + // + // _contextId = EndPointContext.RealRepository.GetObjectIndex(Value); + // return _contextId; + // } + // set + // { + // _contextId = value; + // Value = GetDefaultContextRepository().GetObjectBySharedObject(this); + // } + // } + [JsonIgnore] [SerializationIgnore] public T Value { get; private set; } // ReSharper disable once MemberCanBePrivate.Global @@ -109,11 +123,13 @@ namespace mROA.Implementation if (value is RemoteObjectBase ro) { - _ownerId = ro.OwnerId; - _contextId = ro.Id; + _identifier = ro.Identifier; } else - _ownerId = EndPointContext.HostId; + { + _identifier.OwnerId = EndPointContext.HostId; + _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value); + } } public static implicit operator T(SharedObject value) => value.Value; @@ -121,45 +137,4 @@ namespace mROA.Implementation public static implicit operator SharedObject(T value) => new(value); } - - public struct UniversalObjectIdentifier : IEquatable - { - public int ContextId; - public int OwnerId; - - public override string ToString() - { - return $"{nameof(ContextId)}: {ContextId}, {nameof(OwnerId)}: {OwnerId}"; - } - - public bool IsStatic => ContextId == -1; - - public ulong Flat - { - get - { - return (ulong)OwnerId << 32 | (uint)ContextId; - } - set - { - OwnerId = (int)(value >> 32); - ContextId = (int)(value & 0xFFFFFFFF); - } - } - - public bool Equals(UniversalObjectIdentifier other) - { - return ContextId == other.ContextId && OwnerId == other.OwnerId; - } - - public override bool Equals(object? obj) - { - return obj is UniversalObjectIdentifier other && Equals(other); - } - - public override int GetHashCode() - { - return HashCode.Combine(ContextId, OwnerId); - } - } } \ No newline at end of file diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs new file mode 100644 index 0000000..445292f --- /dev/null +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -0,0 +1,47 @@ +using System; + +namespace mROA.Implementation +{ +#pragma warning disable CS8618, CS9264 + public struct UniversalObjectIdentifier : IEquatable + { + public int ContextId; + public int OwnerId; + + public static UniversalObjectIdentifier Null = new UniversalObjectIdentifier { ContextId = -2, OwnerId = -1 }; + public override string ToString() + { + return $"{{ {nameof(ContextId)}: {ContextId}, {nameof(OwnerId)}: {OwnerId} }}"; + } + + public bool IsStatic => ContextId == -1; + + public ulong Flat + { + get + { + return (ulong)OwnerId << 32 | (uint)ContextId; + } + set + { + OwnerId = (int)(value >> 32); + ContextId = (int)(value & 0xFFFFFFFF); + } + } + + public bool Equals(UniversalObjectIdentifier other) + { + return ContextId == other.ContextId && OwnerId == other.OwnerId; + } + + public override bool Equals(object? obj) + { + return obj is UniversalObjectIdentifier other && Equals(other); + } + + public override int GetHashCode() + { + return HashCode.Combine(ContextId, OwnerId); + } + } +} \ No newline at end of file From b5b766342e1a9219fd047baf46895fed606c7bd4 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 1 Mar 2025 16:53:00 +0300 Subject: [PATCH 24/66] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=B5=D0=BC?= =?UTF-8?q?=D0=BA=D0=B8=20=D0=B1=D0=B5=D0=B7=20=D1=81=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=82=D0=BE=D1=80=D0=B0=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 2 +- Example.Backend/PrinterFactory.cs | 14 +++++++------- Example.Frontend/ClientBasedPrinter.cs | 2 +- Example.Frontend/Program.cs | 11 +++++------ Example.Shared/IPrinter.cs | 2 +- Example.Shared/IPrinterFactory.cs | 8 ++++---- mROA.Cbor/CborSerializationToolkit.cs | 3 +++ 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index a5ba4ac..242b174 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -14,7 +14,7 @@ namespace Example.Backend return Name; } - public async Task> Print(string text, CancellationToken cancellationToken = default) + public async Task Print(string text, CancellationToken cancellationToken = default) { // throw new Exception("The method or operation is not implemented."); return new Page {Text = text}; diff --git a/Example.Backend/PrinterFactory.cs b/Example.Backend/PrinterFactory.cs index 697b2e4..1fc2624 100644 --- a/Example.Backend/PrinterFactory.cs +++ b/Example.Backend/PrinterFactory.cs @@ -12,27 +12,27 @@ namespace Example.Backend { private List _printers = new List(); - public SharedObject Create(string printerName) + public IPrinter Create(string printerName) { Console.WriteLine("Creating printer"); return new Printer { Name = printerName }; } - public void Register(SharedObject printer) + public void Register(IPrinter printer) { - _printers.Add(printer.Value); + _printers.Add(printer); Console.WriteLine("Registered printer"); } - public SharedObject GetPrinterByName(string printerName) + public IPrinter GetPrinterByName(string printerName) { Console.WriteLine("Getting printer"); - return new SharedObject(_printers.Find(i => i.GetName() == printerName)!); + return (_printers.Find(i => i.GetName() == printerName)!); } - public SharedObject GetFirstPrinter() + public IPrinter GetFirstPrinter() { - return new SharedObject(_printers.First()); + return _printers.First(); } public string[] CollectAllNames() diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 00b1984..b449a6d 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -14,7 +14,7 @@ namespace Example.Frontend return "ClientBasedPrinter from mroa"; } - public async Task> Print(string text, CancellationToken cancellationToken) + public async Task Print(string text, CancellationToken cancellationToken) { Console.WriteLine($"Printed: {text}"); await Task.Yield(); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 93e5c81..6eb9181 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -46,8 +46,7 @@ class Program var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory; //правильный порядок команд 8-5-10-7 - var printer = factory.Create("Test"); - using (var disposingPrinter = printer.Value) + using (var disposingPrinter = factory.Create("Test")) { Console.WriteLine("Printer created"); Thread.Sleep(100); @@ -57,7 +56,7 @@ class Program Thread.Sleep(100); - factory.Register(new SharedObject(new ClientBasedPrinter())); + factory.Register(new ClientBasedPrinter()); Console.WriteLine("Registered printer"); Thread.Sleep(100); @@ -66,7 +65,7 @@ class Program Console.WriteLine("First printer"); Thread.Sleep(100); - Console.WriteLine(registred.Value); + Console.WriteLine(registred); Console.WriteLine("Collecting all printers"); var names = factory.CollectAllNames(); Thread.Sleep(100); @@ -75,8 +74,8 @@ class Program var page = disposingPrinter.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); Console.WriteLine("Page printed"); - Console.WriteLine(page.Value.ToString()); - var data = page.Value.GetData(); + Console.WriteLine(page.ToString()); + var data = page.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); Console.WriteLine("Dispose printer"); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 6c4fe9a..085b965 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -10,7 +10,7 @@ namespace Example.Shared public interface IPrinter : IDisposable { string GetName(); - Task> Print(string text, CancellationToken cancellationToken); + Task Print(string text, CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs index bc18270..a2febb9 100644 --- a/Example.Shared/IPrinterFactory.cs +++ b/Example.Shared/IPrinterFactory.cs @@ -6,10 +6,10 @@ namespace Example.Shared [SharedObjectInterface] public interface IPrinterFactory { - SharedObject Create(string printerName); - void Register(SharedObject printer); - SharedObject GetPrinterByName(string printerName); - SharedObject GetFirstPrinter(); + IPrinter Create(string printerName); + void Register(IPrinter printer); + IPrinter GetPrinterByName(string printerName); + IPrinter GetFirstPrinter(); string[] CollectAllNames(); } diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 3fda2b2..cd63254 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -160,6 +160,9 @@ namespace mROA.Cbor private void WriteObject(object obj, CborWriter writer, IEndPointContext? context) { var type = obj.GetType(); + + + var properties = FilterProperties(type.GetProperties()); var values = properties.Select(property => property.GetValue(obj)).ToList(); WriteList(values, writer, context); From bd3c6236264b002a4885c2a9467e7de9f9844fea Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 1 Mar 2025 19:06:18 +0300 Subject: [PATCH 25/66] =?UTF-8?q?=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D0=B1=D0=B5=D0=B7=20=D1=88=D0=B5=D0=BB=D0=B0=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Shared/IDataList.cs | 2 +- Example.Shared/ILoadTest.cs | 3 +- Example.Shared/IPage.cs | 3 +- Example.Shared/IPrinter.cs | 2 +- Example.Shared/IPrinterFactory.cs | 3 +- mROA.Cbor/CborSerializationToolkit.cs | 57 +++++-- mROA.Cbor/PreParsedValue.cs | 16 +- mROA/Abstract/IContextRepository.cs | 2 +- mROA/Abstract/IShared.cs | 7 + .../Backend/ContextRepository.cs | 4 +- .../Backend/MultiClientContextRepository.cs | 6 +- .../Implementation/RemoteContextRepository.cs | 6 +- mROA/Implementation/SharedObject.cs | 140 ------------------ mROA/Implementation/SharedObjectShell.cs | 100 +++++++++++++ mROA/Implementation/TransmissionConfig.cs | 35 +++++ .../UniversalObjectIdentifier.cs | 9 +- 16 files changed, 219 insertions(+), 176 deletions(-) create mode 100644 mROA/Abstract/IShared.cs delete mode 100644 mROA/Implementation/SharedObject.cs create mode 100644 mROA/Implementation/SharedObjectShell.cs create mode 100644 mROA/Implementation/TransmissionConfig.cs diff --git a/Example.Shared/IDataList.cs b/Example.Shared/IDataList.cs index 90792d4..44eea30 100644 --- a/Example.Shared/IDataList.cs +++ b/Example.Shared/IDataList.cs @@ -3,7 +3,7 @@ using mROA.Implementation.Attributes; namespace Example.Shared { // [SharedObjectInterface] - // public interface IDataList + // public interface IDataList : IShared // { // T Get(int index); // void Add(T item); diff --git a/Example.Shared/ILoadTest.cs b/Example.Shared/ILoadTest.cs index e9f958f..8234f1f 100644 --- a/Example.Shared/ILoadTest.cs +++ b/Example.Shared/ILoadTest.cs @@ -1,11 +1,12 @@ using System.Threading; using System.Threading.Tasks; +using mROA.Implementation; using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface ILoadTest + public interface ILoadTest : IShared { int Next(int last); int Last(int next); diff --git a/Example.Shared/IPage.cs b/Example.Shared/IPage.cs index a8d21f9..c7517ff 100644 --- a/Example.Shared/IPage.cs +++ b/Example.Shared/IPage.cs @@ -1,9 +1,10 @@ +using mROA.Implementation; using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPage + public interface IPage : IShared { byte[] GetData(); } diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 085b965..489bada 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -7,7 +7,7 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPrinter : IDisposable + public interface IPrinter : IDisposable, IShared { string GetName(); Task Print(string text, CancellationToken cancellationToken); diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs index a2febb9..884293d 100644 --- a/Example.Shared/IPrinterFactory.cs +++ b/Example.Shared/IPrinterFactory.cs @@ -4,13 +4,12 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPrinterFactory + 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.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index cd63254..58b9ee2 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -12,7 +12,6 @@ namespace mROA.Cbor { public class CborSerializationToolkit : IContextualSerializationToolKit { - private List _remoteTypes; public byte[] Serialize(object objectToSerialize, IEndPointContext context) { var writer = new CborWriter(); @@ -79,9 +78,6 @@ namespace mROA.Cbor case double d: writer.WriteDouble(d); break; - // case decimal dec: - // writer.WriteDecimal(dec); - // break; case bool b: writer.WriteBoolean(b); break; @@ -112,7 +108,7 @@ namespace mROA.Cbor case IList enumerable: WriteList(enumerable, writer, context); break; - case ISharedObject sharedObject: + case ISharedObjectShell sharedObject: if (context != null) sharedObject.EndPointContext = context; WriteObject(sharedObject, writer, context); @@ -160,9 +156,24 @@ namespace mROA.Cbor 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); @@ -204,7 +215,7 @@ namespace mROA.Cbor if (type == null) return ReadList(reader, null, context); - if (type.IsSubclassOf(typeof(ISharedObject))) + if (type.IsSubclassOf(typeof(ISharedObjectShell))) return ReadSharedObject(reader, type, context); if (typeof(IList).IsAssignableFrom(type) || type.IsArray) @@ -287,12 +298,30 @@ namespace mROA.Cbor private object ReadObject(CborReader reader, Type type, IEndPointContext? context) { - if (type == typeof(object)) { return new PreParsedValue(ReadList(reader, null, context) as List); } + if (type.IsInterface) + { + Console.WriteLine("Interface"); + + var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type); + var so = + Activator.CreateInstance(sharedShell) as + ISharedObjectShell; + if (context != null) + so.EndPointContext = context; + + reader.ReadStartArray(); + var identifier = reader.ReadUInt64(); + reader.ReadEndArray(); + + so.Identifier = UniversalObjectIdentifier.FromFlat(identifier); + return so.UniversalValue; + } + var instance = Activator.CreateInstance(type)!; FillObject(instance, type, reader, context); @@ -300,9 +329,9 @@ namespace mROA.Cbor return instance; } - private ISharedObject ReadSharedObject(CborReader reader, Type type, IEndPointContext? context) + private ISharedObjectShell ReadSharedObject(CborReader reader, Type type, IEndPointContext? context) { - var sharedObject = (Activator.CreateInstance(type) as ISharedObject)!; + var sharedObject = (Activator.CreateInstance(type) as ISharedObjectShell)!; if (context != null) { sharedObject.EndPointContext = context; @@ -321,9 +350,8 @@ namespace mROA.Cbor var length = reader.ReadStartArray(); try { - #if TRACE - Console.WriteLine($"Reading list of {length} objects, {properties.Count} properties found"); + Console.WriteLine($"Reading list of {length} objects, {properties.Count} properties found"); #endif for (var index = 0; index < length; index++) @@ -358,7 +386,6 @@ namespace mROA.Cbor public void Inject(T dependency) { - _remoteTypes = RemoteContextRepository.RemoteTypes.Keys.ToList(); } public byte[] Serialize(T objectToSerialize) diff --git a/mROA.Cbor/PreParsedValue.cs b/mROA.Cbor/PreParsedValue.cs index 5109c98..8140f47 100644 --- a/mROA.Cbor/PreParsedValue.cs +++ b/mROA.Cbor/PreParsedValue.cs @@ -21,11 +21,25 @@ namespace mROA.Cbor public object? ToObject(Type type, IEndPointContext? context) { + + if (type.IsInterface) + { + var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type); + var so = + Activator.CreateInstance(sharedShell) as + ISharedObjectShell; + if (context != null) + so.EndPointContext = context; + + so.Identifier = UniversalObjectIdentifier.FromFlat((ulong)_properties[0]); + return so.UniversalValue; + } + var instance = Activator.CreateInstance(type); if (instance == null) return null; - if (instance is ISharedObject sharedObject && context != null) + if (instance is ISharedObjectShell sharedObject && context != null) { sharedObject.EndPointContext = context; } diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index c298688..f9c643b 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -7,7 +7,7 @@ namespace mROA.Abstract { int ResisterObject(object o); void ClearObject(int id); - T GetObjectBySharedObject(SharedObject sharedObject); + T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell); T? GetObject(int id); object GetSingleObject(Type type); int GetObjectIndex(object o); 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/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 65c4acf..e0371f8 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -58,9 +58,9 @@ namespace mROA.Implementation.Backend _lastIndexFinder = Task.FromResult(id); } - public T GetObjectBySharedObject(SharedObject sharedObject) + public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) { - return (T)GetObject(sharedObject.Identifier.ContextId); + return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); } public object GetObject(int id) diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index e89be32..f5c7bf4 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -39,10 +39,10 @@ namespace mROA.Implementation.Backend repository.ClearObject(id); } - public T GetObjectBySharedObject(SharedObject sharedObject) + public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) { - var repository = GetRepository(sharedObject.Identifier.OwnerId); - return repository.GetObject(sharedObject.Identifier.ContextId); + var repository = GetRepository(sharedObjectShellShell.Identifier.OwnerId); + return repository.GetObject(sharedObjectShellShell.Identifier.ContextId); } public object GetObject(int id) diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 1990780..7648d80 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -19,14 +19,14 @@ namespace mROA.Implementation throw new NotSupportedException(); } - public T GetObjectBySharedObject(SharedObject sharedObject) + public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) { 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(sharedObject.Identifier.OwnerId); - var remote = (T)Activator.CreateInstance(remoteType, sharedObject.Identifier.ContextId, + var representationModule = _representationProducer.Produce(sharedObjectShellShell.Identifier.OwnerId); + var remote = (T)Activator.CreateInstance(remoteType, sharedObjectShellShell.Identifier.ContextId, representationModule)!; return remote; } diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs deleted file mode 100644 index 1f8aae5..0000000 --- a/mROA/Implementation/SharedObject.cs +++ /dev/null @@ -1,140 +0,0 @@ -using System; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using mROA.Abstract; -using mROA.Implementation.Attributes; - -// ReSharper disable UnusedMember.Global -#pragma warning disable CS8618, CS9264 - -namespace mROA.Implementation -{ - public static class TransmissionConfig - { -#if TRACE - public static int TotalTransmittedBytes { get; set; } -#endif - private static IContextRepository? _realContextRepository; - private static IContextRepository? _remoteEndpointContextRepository; - private static IOwnershipRepository? _ownershipRepository; - - public static IContextRepository RealContextRepository - { - get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); - set => _realContextRepository = value; - } - - public static IContextRepository RemoteEndpointContextRepository - { - get => _remoteEndpointContextRepository ?? - throw new NullReferenceException("RemoteEndpointContextRepository is null"); - set => _remoteEndpointContextRepository = value; - } - - public static IOwnershipRepository OwnershipRepository - { - get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); - set => _ownershipRepository = value; - } - } - - public interface ISharedObject - { - IEndPointContext EndPointContext { get; set; } - } - - public class SharedObject : ISharedObject where T : notnull - { - [SerializationIgnore] - [JsonIgnore] - public IEndPointContext EndPointContext { get; set; } = new EndPointContext - { - RealRepository = TransmissionConfig.RealContextRepository, - RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, - HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), - OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId - }; - - private IContextRepository GetDefaultContextRepository() => - (_identifier.OwnerId == EndPointContext.HostId - ? EndPointContext.RealRepository - : EndPointContext.RemoteRepository) ?? - throw new NullReferenceException( - "DefaultContextRepository was not defined"); - - private UniversalObjectIdentifier _identifier = UniversalObjectIdentifier.Null; - - public UniversalObjectIdentifier Identifier - { - get - { - _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; - return _identifier; - } - set - { - _identifier = value; - Value = GetDefaultContextRepository().GetObjectBySharedObject(this); - } - } - - - // public int OwnerId - // { - // get - // { - // _ownerId = _ownerId == -1 ? EndPointContext.OwnerId : _ownerId; - // return _ownerId; - // } - // set => _ownerId = value; - // } - // - // // ReSharper disable once MemberCanBePrivate.Global - // public int ContextId - // { - // // ReSharper disable once UnusedMember.Global - // get - // { - // if (_contextId != -2) - // return _contextId; - // - // _contextId = EndPointContext.RealRepository.GetObjectIndex(Value); - // return _contextId; - // } - // set - // { - // _contextId = value; - // Value = GetDefaultContextRepository().GetObjectBySharedObject(this); - // } - // } - - [JsonIgnore] [SerializationIgnore] public T Value { get; private set; } - - // 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) - { - _identifier = ro.Identifier; - } - else - { - _identifier.OwnerId = EndPointContext.HostId; - _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value); - } - } - - 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..3e55a78 --- /dev/null +++ b/mROA/Implementation/SharedObjectShell.cs @@ -0,0 +1,100 @@ +using System; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using mROA.Abstract; +using mROA.Implementation.Attributes; + +// ReSharper disable UnusedMember.Global +#pragma warning disable CS8618, CS9264 + +namespace mROA.Implementation +{ + public interface ISharedObjectShell + { + IEndPointContext EndPointContext { get; set; } + UniversalObjectIdentifier Identifier { get; set; } + object UniversalValue { get; set; } + } + + public class SharedObjectShellShell : ISharedObjectShell where T : notnull + { + [SerializationIgnore] + [JsonIgnore] + public IEndPointContext EndPointContext { get; set; } = new EndPointContext + { + RealRepository = TransmissionConfig.RealContextRepository, + RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, + HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), + OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId + }; + + private IContextRepository GetDefaultContextRepository() => + (_identifier.OwnerId == EndPointContext.HostId + ? EndPointContext.RealRepository + : EndPointContext.RemoteRepository) ?? + throw new NullReferenceException( + "DefaultContextRepository was not defined"); + + private UniversalObjectIdentifier _identifier = UniversalObjectIdentifier.Null; + + public UniversalObjectIdentifier Identifier + { + get + { + _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; + return _identifier; + } + set + { + _identifier = value; + Value = GetDefaultContextRepository().GetObjectBySharedObject(this); + } + } + + public object UniversalValue + { + get => _value; + set => _value = (T)value; + } + + private T _value; + + [JsonIgnore] + [SerializationIgnore] + public T Value + { + get => _value; + set + { + _value = value; + + if (value is RemoteObjectBase ro) + { + _identifier = ro.Identifier; + } + else + { + _identifier.OwnerId = EndPointContext.HostId; + _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value); + } + } + } + + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedMember.Global + public SharedObjectShellShell() + { + } + + // ReSharper disable once UnusedMember.Global + public SharedObjectShellShell(T value) + { + Value = value; + } + + public static implicit operator T(SharedObjectShellShell value) => value.Value; + + public static implicit operator SharedObjectShellShell(T value) => + new(value); + } +} \ No newline at end of file diff --git a/mROA/Implementation/TransmissionConfig.cs b/mROA/Implementation/TransmissionConfig.cs new file mode 100644 index 0000000..5302f9c --- /dev/null +++ b/mROA/Implementation/TransmissionConfig.cs @@ -0,0 +1,35 @@ +using System; +using mROA.Abstract; + +namespace mROA.Implementation +{ +#pragma warning disable CS8618, CS9264 + public static class TransmissionConfig + { +#if TRACE + public static int TotalTransmittedBytes { get; set; } +#endif + private static IContextRepository? _realContextRepository; + private static IContextRepository? _remoteEndpointContextRepository; + private static IOwnershipRepository? _ownershipRepository; + + public static IContextRepository RealContextRepository + { + get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); + set => _realContextRepository = value; + } + + public static IContextRepository RemoteEndpointContextRepository + { + get => _remoteEndpointContextRepository ?? + throw new NullReferenceException("RemoteEndpointContextRepository is null"); + set => _remoteEndpointContextRepository = value; + } + + public static IOwnershipRepository OwnershipRepository + { + get => _ownershipRepository ?? throw new NullReferenceException("OwnershipRepository is null"); + set => _ownershipRepository = value; + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 445292f..0348c0f 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -9,19 +9,18 @@ namespace mROA.Implementation public int OwnerId; public static UniversalObjectIdentifier Null = new UniversalObjectIdentifier { ContextId = -2, OwnerId = -1 }; + public static UniversalObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat }; + public override string ToString() { return $"{{ {nameof(ContextId)}: {ContextId}, {nameof(OwnerId)}: {OwnerId} }}"; } public bool IsStatic => ContextId == -1; - + public ulong Flat { - get - { - return (ulong)OwnerId << 32 | (uint)ContextId; - } + get { return (ulong)OwnerId << 32 | (uint)ContextId; } set { OwnerId = (int)(value >> 32); From 853dcf9af6c1518c4df3911d826a20d62ce14a7d Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sun, 2 Mar 2025 16:49:20 +0300 Subject: [PATCH 26/66] =?UTF-8?q?=D0=9E=D1=87=D0=B8=D1=89=D0=B5=D0=BD=20?= =?UTF-8?q?=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=20=D0=B2=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=81=D0=BE=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Shared/IPrinter.cs | 1 - mROA.Cbor/CborSerializationToolkit.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 489bada..c71c540 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -11,6 +11,5 @@ namespace Example.Shared { string GetName(); Task Print(string text, CancellationToken cancellationToken); - } } \ No newline at end of file diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 58b9ee2..6050272 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -305,7 +305,6 @@ namespace mROA.Cbor if (type.IsInterface) { - Console.WriteLine("Interface"); var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type); var so = From 2b48c3e3192c78344581c63a973bb82443726c67 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 3 Mar 2025 07:53:14 +0300 Subject: [PATCH 27/66] =?UTF-8?q?=D0=91=D0=B0=D0=B7=D0=B0=20=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D0=B0?= =?UTF-8?q?=20=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=D0=B0=20=D0=BC=D0=B5=D1=82?= =?UTF-8?q?=D0=BE=D0=B4=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/IMethodInvoker.cs | 13 +++++++++++++ mROA/Implementation/MethodInvoker.cs | 19 +++++++++++++++++++ .../UniversalObjectIdentifier.cs | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 mROA/Abstract/IMethodInvoker.cs create mode 100644 mROA/Implementation/MethodInvoker.cs diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs new file mode 100644 index 0000000..35ec3b1 --- /dev/null +++ b/mROA/Abstract/IMethodInvoker.cs @@ -0,0 +1,13 @@ +using System; + +namespace mROA.Abstract +{ + public interface IMethodInvoker + { + bool IsAsync { get; } + bool IsVoid { get; } + Type[] ParameterTypes { get; } + Type? ReturnType { get; } + object? Invoke(object instance, object?[] parameters, object[] special); + } +} \ No newline at end of file diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs new file mode 100644 index 0000000..b49593f --- /dev/null +++ b/mROA/Implementation/MethodInvoker.cs @@ -0,0 +1,19 @@ +using System; +using mROA.Abstract; + +namespace mROA.Implementation +{ + public class MethodInvoker : IMethodInvoker + { + public bool IsAsync { get; set; } + public bool IsVoid { get; set; } + public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; + public Type? ReturnType { get; set; } + public Func Invoking { get; set; } + + public object? Invoke(object instance, object?[] parameters, object[] special) + { + return Invoking(instance, parameters, special); + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 0348c0f..781567e 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -20,7 +20,7 @@ namespace mROA.Implementation public ulong Flat { - get { return (ulong)OwnerId << 32 | (uint)ContextId; } + get => (ulong)OwnerId << 32 | (uint)ContextId; set { OwnerId = (int)(value >> 32); From be6dedaee41b8077244f7ab9df991d839a19d2c9 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 4 Mar 2025 14:51:46 +0300 Subject: [PATCH 28/66] =?UTF-8?q?=D0=A3=D0=BF=D1=80=D0=BE=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D0=B8=20=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B2=D1=8B?= =?UTF-8?q?=D0=B9=20=D0=BA=D0=BE=D0=B4=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=B1=D1=8D=D0=BA=D0=B5=D0=BD=D0=B4=D0=B0=20=D0=B2?= =?UTF-8?q?=D1=8B=D0=B7=D0=BE=D0=B2=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Codegen/mROASourceGenerator.cs | 11 ----- mROA/Abstract/IMethodRepository.cs | 6 +-- .../Backend/BasicConfigurationExtensions.cs | 5 -- mROA/Implementation/EndPointContext.cs | 7 ++- mROA/Implementation/MethodInvoker.cs | 14 +++++- mROA/Implementation/MethodRepository.cs | 47 ------------------- 6 files changed, 17 insertions(+), 73 deletions(-) delete mode 100644 mROA/Implementation/MethodRepository.cs diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index b0cd06c..28438f3 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -180,17 +180,6 @@ namespace mROA.Codegen 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) {{ }} diff --git a/mROA/Abstract/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs index 9e448f9..a08faf8 100644 --- a/mROA/Abstract/IMethodRepository.cs +++ b/mROA/Abstract/IMethodRepository.cs @@ -1,13 +1,9 @@ -using System.Collections.Generic; -using System.Reflection; +using System.Reflection; namespace mROA.Abstract { public interface IMethodRepository : IInjectableModule { MethodInfo GetMethod(int id); - int RegisterMethod(MethodInfo method); - - IEnumerable GetMethods(); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs index 16b1851..b7f2460 100644 --- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs +++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs @@ -8,11 +8,6 @@ namespace mROA.Implementation.Backend { public static class BasicConfigurationExtensions { - public static void UseJsonSerialisation(this FullMixBuilder builder) - { - 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)); diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index 7ceb5df..1d80548 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -9,12 +9,11 @@ namespace mROA.Implementation public IContextRepository RealRepository { get; set; } public IContextRepository RemoteRepository { get; set; } public int HostId { get; set; } + public int OwnerId { get => OwnerFunc(); - set - { - OwnerFunc = () => value; - } } + set { OwnerFunc = () => value; } + } } } \ No newline at end of file diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index b49593f..337ec46 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -9,11 +9,23 @@ namespace mROA.Implementation public bool IsVoid { get; set; } public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } - public Func Invoking { get; set; } + public Func Invoking { get; set; } public object? Invoke(object instance, object?[] parameters, object[] special) { return Invoking(instance, parameters, special); } + + public static MethodInvoker Dispose = new MethodInvoker + { + IsAsync = false, + IsVoid = true, + ReturnType = null, + Invoking = ((instance, parameters, special) => + { + (instance as IDisposable)?.Dispose(); + return null; + }) + }; } } \ No newline at end of file diff --git a/mROA/Implementation/MethodRepository.cs b/mROA/Implementation/MethodRepository.cs deleted file mode 100644 index 020f7fc..0000000 --- a/mROA/Implementation/MethodRepository.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using mROA.Abstract; -using mROA.Implementation.Attributes; - -namespace mROA.Implementation -{ - public class MethodRepository : IMethodRepository - { - private readonly List _methods = new() { }; - - 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 From c802f337c7528e151862504ccf20325ea2ac323b Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 6 Mar 2025 14:10:52 +0300 Subject: [PATCH 29/66] =?UTF-8?q?=D0=91=D0=B0=D0=B7=D0=B0=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B3=D0=BE=20=D0=B1=D1=8D?= =?UTF-8?q?=D0=BA=D1=8D=D0=BD=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/CsTest.cs | 18 ++ Example.Backend/PagesList.cs | 24 +++ Example.Backend/Program.cs | 2 + Example.Frontend/ClientBasedPrinter.cs | 1 + Example.Frontend/Program.cs | 4 +- Example.Shared/IDataList.cs | 17 +- Example.Shared/IPagesList.cs | 9 + mROA.Cbor/CborSerializationToolkit.cs | 5 +- mROA.Codegen/mROASourceGenerator.cs | 109 ++++++------ mROA/Abstract/IMethodInvoker.cs | 3 +- mROA/Abstract/IMethodRepository.cs | 2 +- mROA/Abstract/ISerializationToolkit.cs | 4 +- .../Backend/BasicExecutionModule.cs | 158 ++++++++++-------- mROA/Implementation/CallRequest.cs | 6 +- .../Frontend/RequestExtractor.cs | 9 - mROA/Implementation/MethodInvoker.cs | 13 +- mROA/Implementation/RemoteObjectBase.cs | 8 +- mROA/Implementation/RequestContext.cs | 16 ++ 18 files changed, 245 insertions(+), 163 deletions(-) create mode 100644 Example.Backend/CsTest.cs create mode 100644 Example.Backend/PagesList.cs create mode 100644 Example.Shared/IPagesList.cs create mode 100644 mROA/Implementation/RequestContext.cs diff --git a/Example.Backend/CsTest.cs b/Example.Backend/CsTest.cs new file mode 100644 index 0000000..8db1c75 --- /dev/null +++ b/Example.Backend/CsTest.cs @@ -0,0 +1,18 @@ +using System; +using Example.Shared; + +namespace Example.Backend +{ + public class CsTest + { + public T FinalCasted(IDataList list, int index) + { + return list.Get(index); + } + + public object NonCasted(object list, int index) + { + return FinalCasted(list as IDataList, index); + } + } +} \ No newline at end of file diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs new file mode 100644 index 0000000..6505303 --- /dev/null +++ b/Example.Backend/PagesList.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Example.Shared; + +namespace Example.Backend +{ + public class PagesList : IPagesList + { + public IReadOnlyList Collection { get; } + public IPage Get(int index) + { + throw new System.NotImplementedException(); + } + + public void Add(IPage item) + { + throw new System.NotImplementedException(); + } + + public void Set(int index, IPage item) + { + throw new System.NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index f31f557..a6b3ffc 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,5 +1,6 @@ using System.Net; using Example.Backend; +using Example.Shared; using mROA.Abstract; using mROA.Cbor; using mROA.Codegen; @@ -48,5 +49,6 @@ class Program var gateway = builder.GetModule(); gateway.Run(); + } } \ No newline at end of file diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index b449a6d..4d9c661 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -11,6 +11,7 @@ namespace Example.Frontend public string GetName() { Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); + return "ClientBasedPrinter from mroa"; } diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 6eb9181..d47c620 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -17,7 +17,7 @@ class Program public static void Main(string[] args) { var builder = new FullMixBuilder(); - new RemoteTypeBinder(); + // new RemoteTypeBinder(); // builder.Modules.Add(new JsonSerializationToolkit()); builder.Modules.Add(new CborSerializationToolkit()); @@ -106,5 +106,7 @@ class Program // 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/IDataList.cs b/Example.Shared/IDataList.cs index 44eea30..c0e2cc7 100644 --- a/Example.Shared/IDataList.cs +++ b/Example.Shared/IDataList.cs @@ -1,12 +1,15 @@ +using System; +using System.Collections.Generic; +using mROA.Implementation; using mROA.Implementation.Attributes; namespace Example.Shared { - // [SharedObjectInterface] - // public interface IDataList : IShared - // { - // T Get(int index); - // void Add(T item); - // void Set(int index, T item); - // } + public interface IDataList : IShared, IDisposable + { + IReadOnlyList Collection { get; } + T Get(int index); + void Add(T item); + void Set(int index, T item); + } } \ No newline at end of file diff --git a/Example.Shared/IPagesList.cs b/Example.Shared/IPagesList.cs new file mode 100644 index 0000000..05bcc6a --- /dev/null +++ b/Example.Shared/IPagesList.cs @@ -0,0 +1,9 @@ +using mROA.Implementation.Attributes; + +namespace Example.Shared +{ + [SharedObjectInterface] + public interface IPagesList : IDataList + { + } +} \ No newline at end of file diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 6050272..847f2cc 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -52,8 +52,11 @@ namespace mROA.Cbor return (T)Cast(nonCasted, typeof(T), context); } - public object Cast(object nonCasted, Type type, IEndPointContext? context) + public object? Cast(object? nonCasted, Type type, IEndPointContext? context) { + if (nonCasted == null) + return null; + if (nonCasted.GetType() == type) return nonCasted; diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 28438f3..7881618 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -17,74 +17,57 @@ namespace mROA.Codegen [Generator] public class mROASourceGenerator : ISourceGenerator { - 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 - {{ - }} -}}"; - - /// - /// 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(GeneratorExecutionContext 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) - { - // We need to get semantic model of the class to retrieve metadata. + { var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree); - - // 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 methodBody = CollectMethods(classSymbol); + var originalName = className; - // Build up the source code + className = className.TrimStart('I') + "RemoteEndpoint"; - var methodsText = new List(); - + foreach (var method in methodBody) { var index = methods.Count; methods.Add((namespaceName + "." + originalName, method)); var sb = new StringBuilder(); + + bool isParametrized; - bool isAsync = method.ReturnType.Name == "Task"; - bool isVoid = method.ReturnType.Name == "Void" || - method.ReturnType.ToString() == "System.Threading.Tasks.Task"; - bool isParametrized = method.Parameters.Length == 1 && !isAsync || - method.Parameters.Length == 2 && isAsync; + bool isAsync; + bool isVoid; + switch (method.ReturnType) + { + case INamedTypeSymbol namedType: + isAsync = namedType.Name == "Task"; + isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void"; + isParametrized = method.Parameters.Length == 1 && !isAsync || + method.Parameters.Length == 2 && isAsync; + break; + case IArrayTypeSymbol: + isAsync = false; + isVoid = false; + isParametrized = method.Parameters.Length != 0; + break; + default: + continue; + } //Creating signature sb.AppendLine("public" + (isAsync @@ -140,7 +123,7 @@ namespace {namespaceName} // Add the source code to the compilation. - context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); + // context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); frontendContextRepo.Add( $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); @@ -148,31 +131,27 @@ namespace {namespaceName} if (methods.Count != 0) { - // var methodsStringed = methods.Select(i => - // $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})") - // .ToList(); - var methodsStringed = methods.Select(i => - $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\")") - .ToList(); + var methodsStringed = Array.Empty(); var coCodegenRepoCode = @$"// using System.Collections.Generic; using System.Reflection; using mROA.Abstract; +using mROA.Implementation; using System; namespace mROA.Codegen {{ public class CoCodegenMethodRepository : IMethodRepository {{ - private readonly List _methods = new () {{ + private readonly List _methods = new () {{ {string.Join(",\r\n\t\t\t", methodsStringed)} }}; - public MethodInfo GetMethod(int id) + public IMethodInvoker GetMethod(int id) {{ if (id == -1) - return typeof(IDisposable).GetMethod(""Dispose""); + return mROA.Implementation.MethodInvoker.Dispose; if (_methods.Count <= id) return null; @@ -186,7 +165,7 @@ namespace mROA.Codegen }} }} "; - context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); + context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); } if (frontendContextRepo.Count != 0) @@ -209,7 +188,7 @@ namespace mROA.Codegen }} }} "; - context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); + // context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); } } @@ -225,9 +204,7 @@ namespace mROA.Codegen private string ExtractTaskType(ITypeSymbol taskType) { - var type = taskType.ToString(); - type = type.Substring(type.IndexOf('<') + 1); - return type.Substring(0, type.Length - 1); + return (taskType as INamedTypeSymbol).TypeParameters[0].ToDisplayString(); } public void Initialize(GeneratorInitializationContext context) @@ -266,8 +243,7 @@ namespace mROA.Codegen private bool ContainsSOIAttribute(SyntaxList attributes, GeneratorExecutionContext context, InterfaceDeclarationSyntax interfaceDeclarationSyntax) { - foreach (AttributeListSyntax attributeListSyntax in attributes) - foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes) + foreach (var attributeSyntax in attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes)) { if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree) .GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) @@ -282,5 +258,16 @@ namespace mROA.Codegen return false; } + + private List CollectMethods(INamedTypeSymbol type) + { + var methods = type.GetMembers().OfType().ToList(); + foreach (var inner in type.AllInterfaces) + { + methods.AddRange(inner.GetMembers().OfType()); + } + + return methods.OrderBy(i => i.Name).ToList(); + } } } \ No newline at end of file diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs index 35ec3b1..439434a 100644 --- a/mROA/Abstract/IMethodInvoker.cs +++ b/mROA/Abstract/IMethodInvoker.cs @@ -8,6 +8,7 @@ namespace mROA.Abstract bool IsVoid { get; } Type[] ParameterTypes { get; } Type? ReturnType { get; } - object? Invoke(object instance, object?[] parameters, object[] special); + object? Invoke(object instance, object?[]? parameters, object[] special); + Type SuitableType { get; } } } \ No newline at end of file diff --git a/mROA/Abstract/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs index a08faf8..ec67928 100644 --- a/mROA/Abstract/IMethodRepository.cs +++ b/mROA/Abstract/IMethodRepository.cs @@ -4,6 +4,6 @@ namespace mROA.Abstract { public interface IMethodRepository : IInjectableModule { - MethodInfo GetMethod(int id); + IMethodInvoker GetMethod(int id); } } \ No newline at end of file diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs index b3502f8..c7ce9f4 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -10,8 +10,8 @@ namespace mROA.Abstract 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); + T? Cast(object? nonCasted); + object? Cast(object? nonCasted, Type type); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 443a366..31e9ee1 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; using System.Threading; using System.Threading.Tasks; @@ -11,11 +12,22 @@ namespace mROA.Implementation.Backend { private IMethodRepository? _methodRepo; private ICancellationRepository? _cancellationRepo; + private ISerializationToolkit? _serialization; public void Inject(T dependency) { - if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo; - if (dependency is ICancellationRepository cancellationRepo) _cancellationRepo = cancellationRepo; + switch (dependency) + { + 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, @@ -24,50 +36,69 @@ namespace mROA.Implementation.Backend #if TRACE Console.WriteLine(command.GetType().Name); #endif - 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"); - - if (command is CancelRequest) - { -#if TRACE - Console.WriteLine("Final cancelling request"); -#endif - var cts = _cancellationRepo.GetCancellation(command.Id); - cts.Cancel(); - _cancellationRepo.FreeCancelation(command.Id); - return new FinalCommandExecution - { - Id = command.Id - }; - } - - 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, _cancellationRepo, - representationModule); - - if (currentCommand.ReturnType == typeof(Task)) - return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo, - representationModule); try { - var result = Execute(currentCommand, context, parameter, command); + 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"); + + if (command is CancelRequest) + { +#if TRACE + Console.WriteLine("Final cancelling request"); +#endif + 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 + }; + } + + var invoker = _methodRepo.GetMethod(command.CommandId); + if (invoker == null) + throw new Exception($"Command {command.CommandId} not found"); + + var context = command.ObjectId != -1 + ? contextRepository.GetObject(command.ObjectId) + : contextRepository.GetSingleObject(invoker.SuitableType); + + if (context == null) + throw new NullReferenceException("Instance can't be null"); + + + object?[]? castedParams = null; + + if (invoker.ParameterTypes != Type.EmptyTypes) + { + castedParams = new object[invoker.ParameterTypes.Length]; + for (int i = 0; i < castedParams.Length; i++) + { + castedParams[i] = _serialization.Cast(command.Parameters![i], invoker.ParameterTypes[i]); + } + } + + var execContext = new RequestContext(command.Id, representationModule.Id); + + if (invoker is { IsAsync: true, IsVoid: false }) + return TypedExecuteAsync(invoker, context, castedParams, command, _cancellationRepo, + representationModule, execContext); + + if (invoker.IsAsync) + return ExecuteAsync(invoker, context, castedParams, command, _cancellationRepo, + representationModule, execContext); + + var result = Execute(invoker, context, castedParams, command, execContext); if (command.CommandId == -1) { #if TRACE @@ -80,23 +111,22 @@ namespace mROA.Implementation.Backend } catch (Exception e) { - Console.WriteLine(e); - throw; + return new ExceptionCommandExecution + { + Id = command.Id, + Exception = e.ToString() + }; } } - private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter, - ICallRequest command) + private static ICommandExecution Execute(IMethodInvoker invoker, object instance, object?[] parameter, + ICallRequest command, RequestContext executionContext) { try { - var finalParameter = parameter is null - ? Array.Empty() - : new[] - { parameter }; - var finalResult = currentCommand.Invoke(context, finalParameter); + var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext }); - if (currentCommand.ReturnType.Name == "Void") + if (invoker.IsVoid) { return new FinalCommandExecution { @@ -120,9 +150,9 @@ namespace mROA.Implementation.Backend } } - private ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + private ICommandExecution ExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, - IRepresentationModule representationModule) + IRepresentationModule representationModule, RequestContext executionContext) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -132,11 +162,7 @@ namespace mROA.Implementation.Backend #endif try { - var finalParameter = parameter is null - ? new object[] { token } - : new[] - { parameter, token }; - var result = (Task)currentCommand.Invoke(context, finalParameter)!; + var result = (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!; result.ContinueWith(_ => @@ -173,9 +199,9 @@ namespace mROA.Implementation.Backend } } - private ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, + private ICommandExecution TypedExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, - IRepresentationModule representationModule) + IRepresentationModule representationModule, RequestContext executionContext) { var tokenSource = new CancellationTokenSource(); cancellationRepository.RegisterCancellation(command.Id, tokenSource); @@ -183,12 +209,8 @@ namespace mROA.Implementation.Backend var token = tokenSource.Token; try { - var finalParameter = parameter is null - ? new object[] { token } - : new[] - { parameter, token }; var result = - (Task)currentCommand.Invoke(context, finalParameter)!; + (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!; result.ContinueWith(t => { @@ -198,7 +220,7 @@ namespace mROA.Implementation.Backend Id = command.Id, Result = finalResult }; - _cancellationRepo.FreeCancelation(command.Id); + _cancellationRepo!.FreeCancelation(command.Id); var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index a6235f1..9066319 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -11,7 +11,7 @@ namespace mROA.Implementation Guid Id { get; } int CommandId { get; } int ObjectId { get; } - object? Parameter { get; } + object?[]? Parameters { get; } } public class DefaultCallRequest : ICallRequest @@ -20,7 +20,7 @@ namespace mROA.Implementation public int CommandId { get; set; } public int ObjectId { get; set; } = -1; - public object? Parameter { get; set; } + public object?[]? Parameters { get; set; } public override string ToString() { return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; @@ -32,7 +32,7 @@ namespace mROA.Implementation public Guid Id { get; set; } public int CommandId { get; set; } = -2; public int ObjectId { get; set; } = -2; - public object? Parameter { get; set; } = null; + public object?[]? Parameters { get; set; } = null; public override string ToString() { return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index cfcf9ce..c08f21a 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -94,15 +94,6 @@ namespace mROA.Implementation.Frontend tokenSource.Cancel(); var request = defaultRequest.Result; - if (request.Parameter is not null) - { - var method = _methodRepository!.GetMethod(request.CommandId); - var parameterType = method.GetParameters().First() - .ParameterType; - - request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType); - } - var result = _executeModule.Execute(request, _contextRepository, _representationModule); var resultType = MessageType.Unknown; diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index 337ec46..8299a0a 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -9,23 +9,26 @@ namespace mROA.Implementation public bool IsVoid { get; set; } public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } - public Func Invoking { get; set; } + public Func Invoking { get; set; } = (_, _, _) => null; - public object? Invoke(object instance, object?[] parameters, object[] special) + public object? Invoke(object instance, object?[]? parameters, object[] special) { return Invoking(instance, parameters, special); } - public static MethodInvoker Dispose = new MethodInvoker + public Type SuitableType { get; set; } = null!; + + public static readonly IMethodInvoker Dispose = new MethodInvoker { IsAsync = false, IsVoid = true, ReturnType = null, - Invoking = ((instance, parameters, special) => + Invoking = (instance, _, _) => { (instance as IDisposable)?.Dispose(); return null; - }) + }, + SuitableType = typeof(IDisposable) }; } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index b74b58a..e756d5a 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -22,11 +22,11 @@ namespace mROA.Implementation public int Id => _identifier.ContextId; public int OwnerId => _identifier.OwnerId; public UniversalObjectIdentifier Identifier => _identifier; - protected async Task GetResultAsync(int methodId, object? parameter = default, + protected async Task GetResultAsync(int methodId, object?[]? parameters = null, CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter + { CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); @@ -76,11 +76,11 @@ namespace mROA.Implementation throw errorResponse.Result.GetException(); } - protected async Task CallAsync(int methodId, object? parameter = default, + protected async Task CallAsync(int methodId, object?[]? parameters = null, CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter + { CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); 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 From 8d082d1ed474918d93fd2264642e2e9e2098feb2 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 7 Mar 2025 09:01:21 +0300 Subject: [PATCH 30/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6?= =?UTF-8?q?=D0=BA=D0=B0=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA?= =?UTF-8?q?=D0=B8=D1=85=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B2=20=D0=BA=D0=BE=D0=B4=D0=B3=D0=B5=D0=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/PagesList.cs | 12 +++++- Example.Backend/Printer.cs | 12 ++++-- Example.Frontend/ClientBasedPrinter.cs | 14 ++++++- Example.Frontend/Program.cs | 2 +- Example.Shared/IDataList.cs | 4 +- Example.Shared/IPrinter.cs | 3 +- mROA.Codegen/mROA.Codegen.csproj | 5 +++ mROA.Codegen/mROASourceGenerator.cs | 52 ++++++++++++++++++-------- mROA.Codegen/test.tpt | 1 + 9 files changed, 80 insertions(+), 25 deletions(-) create mode 100644 mROA.Codegen/test.tpt diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs index 6505303..3e02b77 100644 --- a/Example.Backend/PagesList.cs +++ b/Example.Backend/PagesList.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Example.Shared; @@ -5,7 +6,6 @@ namespace Example.Backend { public class PagesList : IPagesList { - public IReadOnlyList Collection { get; } public IPage Get(int index) { throw new System.NotImplementedException(); @@ -16,9 +16,17 @@ namespace Example.Backend throw new System.NotImplementedException(); } - public void Set(int index, IPage item) + public void Remove(int index, IPage item) { throw new System.NotImplementedException(); } + + public event Action? OnAdd; + public event Action? OnRemove; + + public void Dispose() + { + // TODO release managed resources here + } } } \ No newline at end of file diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 242b174..170ba16 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -9,20 +9,26 @@ namespace Example.Backend public class Printer : IPrinter { public string Name; + public string GetName() { return Name; } - public async Task Print(string text, CancellationToken cancellationToken = default) + public async Task Print(string text, bool some, CancellationToken cancellationToken = default) { // throw new Exception("The method or operation is not implemented."); - return new Page {Text = text}; + var page = new Page { Text = text }; + OnPrint?.Invoke(page); + 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); + 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.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 4d9c661..888e802 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,6 +8,16 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { + public int Prop { get; set; } + public int get_Prop() + { + return 1; + } + + public int set_Prop(int value) + { + return 1; + } public string GetName() { Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); @@ -15,13 +25,15 @@ namespace Example.Frontend return "ClientBasedPrinter from mroa"; } - public async Task Print(string text, CancellationToken cancellationToken) + public async Task Print(string text, bool some, CancellationToken cancellationToken) { Console.WriteLine($"Printed: {text}"); await Task.Yield(); return new ClientBasedPage(); } + public event Action? OnPrint; + public void Dispose() { diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index d47c620..427df96 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -72,7 +72,7 @@ class Program Console.WriteLine(string.Join(", ", names)); - var page = disposingPrinter.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); + var page = disposingPrinter.Print("Test Page", false, CancellationToken.None).GetAwaiter().GetResult(); Console.WriteLine("Page printed"); Console.WriteLine(page.ToString()); var data = page.GetData(); diff --git a/Example.Shared/IDataList.cs b/Example.Shared/IDataList.cs index c0e2cc7..eb62728 100644 --- a/Example.Shared/IDataList.cs +++ b/Example.Shared/IDataList.cs @@ -10,6 +10,8 @@ namespace Example.Shared IReadOnlyList Collection { get; } T Get(int index); void Add(T item); - void Set(int index, 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/IPrinter.cs b/Example.Shared/IPrinter.cs index c71c540..383961d 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -10,6 +10,7 @@ namespace Example.Shared public interface IPrinter : IDisposable, IShared { string GetName(); - Task Print(string text, CancellationToken cancellationToken); + Task Print(string text, bool someParameter, CancellationToken cancellationToken); + event Action OnPrint; } } \ No newline at end of file diff --git a/mROA.Codegen/mROA.Codegen.csproj b/mROA.Codegen/mROA.Codegen.csproj index 2a23fd6..c9257fd 100644 --- a/mROA.Codegen/mROA.Codegen.csproj +++ b/mROA.Codegen/mROA.Codegen.csproj @@ -31,6 +31,11 @@ + + + + + diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 7881618..1fd31b3 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; +using System.Reflection; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -20,45 +22,59 @@ namespace mROA.Codegen 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 methods = new List<(string, IMethodSymbol)>(); var frontendContextRepo = 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; - + var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - var methodBody = CollectMethods(classSymbol); + var innerMembers = CollectMembers(classSymbol); + var associated = innerMembers.Select(i => i.AssociatedSymbol).Where(i => i != null).Select(i => i!).Distinct(SymbolEqualityComparer.Default).ToList(); var originalName = className; - + className = className.TrimStart('I') + "RemoteEndpoint"; - var methodsText = new List(); - - foreach (var method in methodBody) + var remoteEndpointMember = new List(); + + foreach (var method in innerMembers.OfType()) { + if (method.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove) + continue; + + var index = methods.Count; methods.Add((namespaceName + "." + originalName, method)); 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"; - isParametrized = method.Parameters.Length == 1 && !isAsync || - method.Parameters.Length == 2 && isAsync; + parameters = method.Parameters.ToList(); + parameters.RemoveAll(i => i.Type.Name is "CancellationToken" or "RequestContext"); + isParametrized = parameters.Count != 0; break; case IArrayTypeSymbol: isAsync = false; @@ -77,8 +93,10 @@ namespace mROA.Codegen var prefix = isAsync ? "await " : ""; - var postfix = !isAsync ? (isVoid ? ".Wait()" : ".GetAwaiter().GetResult()") : ""; - var parameterLink = isParametrized ? ", " + method.Parameters.First().Name : string.Empty; + var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : ""; + var parameterLink = isParametrized + ? ", new object[] {" + string.Join(", ", method.Parameters.Select(i => i.Name)) + "}" + : string.Empty; var tokenInsert = isAsync ? isParametrized ? ", cancellationToken : " + method.Parameters[1].Name @@ -97,7 +115,7 @@ namespace mROA.Codegen sb.AppendLine("\t\t}"); - methodsText.Add(sb.ToString()); + remoteEndpointMember.Add(sb.ToString()); } var code = $@"// @@ -116,7 +134,7 @@ namespace {namespaceName} {{ }} - {string.Join("\r\n\t", methodsText)} + {string.Join("\r\n\t", remoteEndpointMember)} }} }} "; @@ -243,7 +261,8 @@ namespace mROA.Codegen private bool ContainsSOIAttribute(SyntaxList attributes, GeneratorExecutionContext context, InterfaceDeclarationSyntax interfaceDeclarationSyntax) { - foreach (var attributeSyntax in attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes)) + foreach (var attributeSyntax in + attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes)) { if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree) .GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol) @@ -259,7 +278,7 @@ namespace mROA.Codegen return false; } - private List CollectMethods(INamedTypeSymbol type) + private List CollectMembers(INamedTypeSymbol type) { var methods = type.GetMembers().OfType().ToList(); foreach (var inner in type.AllInterfaces) @@ -267,6 +286,7 @@ namespace mROA.Codegen methods.AddRange(inner.GetMembers().OfType()); } + methods.RemoveAll(m => m.Name == "Dispose"); return methods.OrderBy(i => i.Name).ToList(); } } 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 From 593a8b0635b9e0f96f7af44288001033be59437f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 7 Mar 2025 15:46:22 +0300 Subject: [PATCH 31/66] =?UTF-8?q?=D0=93=D0=B5=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=BA=D0=BE=D0=B4=D0=B0=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B3=D0=B5=D1=82=D1=82=D0=B5=D1=80=D0=BE=D0=B2=20?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B5=D1=82=D1=82=D0=B5=D1=80=D0=BE=D0=B2=20?= =?UTF-8?q?=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2=20=D0=B8=20=D0=B8?= =?UTF-8?q?=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0=D1=82=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Shared/IDataList.cs | 1 + mROA.Codegen/mROASourceGenerator.cs | 188 +++++++++++------- .../Frontend/RequestExtractor.cs | 1 - 3 files changed, 120 insertions(+), 70 deletions(-) diff --git a/Example.Shared/IDataList.cs b/Example.Shared/IDataList.cs index eb62728..f08bb75 100644 --- a/Example.Shared/IDataList.cs +++ b/Example.Shared/IDataList.cs @@ -8,6 +8,7 @@ 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); diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 1fd31b3..2c31e16 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -28,9 +28,9 @@ namespace mROA.Codegen // var test = asm.GetManifestResourceStream("mROA.Codegen.test.tpt"); // var reader = new StreamReader(test); // var allText = reader.ReadToEnd(); - var methods = new List<(string, IMethodSymbol)>(); var frontendContextRepo = new List(); + List innerMethods = new List(); var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList(); foreach (var classDeclarationSyntax in declarations) { @@ -41,81 +41,36 @@ namespace mROA.Codegen var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - var innerMembers = CollectMembers(classSymbol); - var associated = innerMembers.Select(i => i.AssociatedSymbol).Where(i => i != null).Select(i => i!).Distinct(SymbolEqualityComparer.Default).ToList(); - + innerMethods = CollectMembers(classSymbol) + .Where(i => i.MethodKind != MethodKind.EventAdd || i.MethodKind != MethodKind.EventRemove) + .ToList(); + var associated = innerMethods.Select(i => i.AssociatedSymbol as IPropertySymbol).Where(i => i != null) + .Select(i => i!).Distinct(SymbolEqualityComparer.Default).Cast().ToList(); + var originalName = className; className = className.TrimStart('I') + "RemoteEndpoint"; - var remoteEndpointMember = new List(); - - foreach (var method in innerMembers.OfType()) + + var declaredMethods = new List(); + var propertiesAccessMethods = new List<(string, IMethodSymbol)>(); + var propertiesImplementations = new List(associated.Count); + foreach (var method in innerMethods) { - if (method.MethodKind is MethodKind.EventAdd or MethodKind.EventRemove) - continue; - - - var index = methods.Count; - methods.Add((namespaceName + "." + originalName, method)); - var sb = new StringBuilder(); - - bool isParametrized; - - bool isAsync; - bool isVoid; - - List? parameters; - - switch (method.ReturnType) + switch (method.MethodKind) { - case INamedTypeSymbol namedType: - isAsync = namedType.Name == "Task"; - isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void"; - parameters = method.Parameters.ToList(); - parameters.RemoveAll(i => i.Type.Name is "CancellationToken" or "RequestContext"); - isParametrized = parameters.Count != 0; - break; - case IArrayTypeSymbol: - isAsync = false; - isVoid = false; - isParametrized = method.Parameters.Length != 0; - break; - default: + case MethodKind.PropertyGet or MethodKind.PropertySet: + GeneratePropertyMethod(method, innerMethods, propertiesAccessMethods); continue; + default: + GenerateDeclaretedMethod(method, declaredMethods, innerMethods); + break; } + } - //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(", ", method.Parameters.Select(i => i.Name)) + "}" - : string.Empty; - var tokenInsert = isAsync - ? isParametrized - ? ", cancellationToken : " + method.Parameters[1].Name - : ", cancellationToken : " + method.Parameters[0].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}"); - - remoteEndpointMember.Add(sb.ToString()); + foreach (var prop in associated) + { + var start = $"public {prop.Type.ToDisplayString()} {prop.Name}"; } var code = $@"// @@ -134,7 +89,7 @@ namespace {namespaceName} {{ }} - {string.Join("\r\n\t", remoteEndpointMember)} + {string.Join("\r\n\t", declaredMethods)} }} }} "; @@ -147,7 +102,7 @@ namespace {namespaceName} $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); } - if (methods.Count != 0) + if (innerMethods.Count != 0) { var methodsStringed = Array.Empty(); @@ -210,6 +165,101 @@ namespace mROA.Codegen } } + private void GenerateDeclaretedMethod(IMethodSymbol method, List declaretedMethods, + List methods) + { + var index = methods.IndexOf(method); + 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(i => i.Type.Name is "CancellationToken" or "RequestContext"); + isParametrized = parameters.Count != 0; + break; + case IArrayTypeSymbol: + isAsync = false; + isVoid = false; + 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(", ", method.Parameters.Select(i => i.Name)) + "}" + : string.Empty; + var tokenInsert = isAsync + ? isParametrized + ? ", cancellationToken : " + method.Parameters[1].Name + : ", cancellationToken : " + method.Parameters[0].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}"); + + declaretedMethods.Add(sb.ToString()); + } + + public void GeneratePropertyMethod(IMethodSymbol method, List methods, + List<(string, IMethodSymbol)> propsCollection) + { + var index = methods.IndexOf(method); + var sb = new StringBuilder(); + if (method.MethodKind == MethodKind.PropertyGet) + { + var parametersArray = ""; + if (method.Parameters.Length != 0) + { + parametersArray = $", new object[] {{{string.Join(", ", method.Parameters.Select(p => p.Name))}}}"; + } + + sb.AppendLine( + $"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).Wait();"); + } + else + { + var parametersArray = ""; + if (method.Parameters.Length != 0) + { + parametersArray = ", " + string.Join(", ", method.Parameters.Select(p => p.Name)); + } + + sb.AppendLine( + $"set => CallAsync({index}, new object[] {{ value{parametersArray} }}).GetAwaiter().GetResult();"); + } + + propsCollection.Add((sb.ToString(), method)); + } + private static string ToFullString(IParameterSymbol parameter) => /*parameter.Type.ContainingNamespace is null*/ /*?*/ parameter.ToDisplayString(); diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index c08f21a..751e10d 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -76,7 +76,6 @@ namespace mROA.Implementation.Frontend messageType: MessageType.CancelRequest, token: token); Task.WaitAny(defaultRequest, cancelRequest); - #if TRACE Console.WriteLine("Request received"); #endif From 6aa11ba7c0ff647768498ee9323311599270efdc Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 8 Mar 2025 12:10:12 +0300 Subject: [PATCH 32/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BA=D0=BE=D0=B4=D0=B3=D0=B5=D0=BD=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D0=BA=D1=81=D0=B8=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2=20?= =?UTF-8?q?=D0=B8=20=D0=B8=D0=BD=D0=B4=D0=B5=D0=BA=D1=81=D0=B0=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/PagesList.cs | 16 +++++- mROA.Codegen/mROASourceGenerator.cs | 81 +++++++++++++++++++++-------- 2 files changed, 73 insertions(+), 24 deletions(-) diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs index 3e02b77..1ce6be0 100644 --- a/Example.Backend/PagesList.cs +++ b/Example.Backend/PagesList.cs @@ -1,11 +1,21 @@ using System; using System.Collections.Generic; using Example.Shared; +using mROA.Abstract; +using mROA.Implementation; namespace Example.Backend { - public class PagesList : IPagesList + public class PagesList : RemoteObjectBase, IPagesList { + public IReadOnlyList Collection { get; } + + public Example.Shared.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 System.NotImplementedException(); @@ -28,5 +38,9 @@ namespace Example.Backend { // TODO release managed resources here } + + public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule) + { + } } } \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 2c31e16..22a53ab 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -1,3 +1,5 @@ +// #define DONT_ADD + using System; using System.Collections.Generic; using System.Collections.Immutable; @@ -41,11 +43,13 @@ namespace mROA.Codegen var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - innerMethods = CollectMembers(classSymbol) - .Where(i => i.MethodKind != MethodKind.EventAdd || i.MethodKind != MethodKind.EventRemove) + 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(); - var associated = innerMethods.Select(i => i.AssociatedSymbol as IPropertySymbol).Where(i => i != null) - .Select(i => i!).Distinct(SymbolEqualityComparer.Default).Cast().ToList(); var originalName = className; @@ -68,9 +72,35 @@ namespace mROA.Codegen } } - foreach (var prop in associated) + foreach (var symbol in associated) { - var start = $"public {prop.Type.ToDisplayString()} {prop.Name}"; + 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; + } } var code = $@"// @@ -89,15 +119,16 @@ namespace {namespaceName} {{ }} - {string.Join("\r\n\t", declaredMethods)} + {string.Join("\r\n\t\t", declaredMethods)} }} }} "; // Add the source code to the compilation. - // context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); - +#if !DONT_ADD + context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); +#endif frontendContextRepo.Add( $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); } @@ -161,7 +192,9 @@ namespace mROA.Codegen }} }} "; - // context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); +#if !DONT_ADD + context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8)); +#endif } } @@ -184,12 +217,13 @@ namespace mROA.Codegen isAsync = namedType.Name == "Task"; isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void"; parameters = method.Parameters.ToList(); - parameters.RemoveAll(i => i.Type.Name is "CancellationToken" or "RequestContext"); + parameters.RemoveAll(ParameterFilter); isParametrized = parameters.Count != 0; break; case IArrayTypeSymbol: isAsync = false; isVoid = false; + parameters = new List(); isParametrized = method.Parameters.Length != 0; break; default: @@ -206,12 +240,11 @@ namespace mROA.Codegen var prefix = isAsync ? "await " : ""; var postfix = !isAsync ? isVoid ? ".Wait()" : ".GetAwaiter().GetResult()" : ""; var parameterLink = isParametrized - ? ", new object[] {" + string.Join(", ", method.Parameters.Select(i => i.Name)) + "}" + ? ", new object[] {" + string.Join(", ", parameters.Select(i => i.Name)) + "}" : string.Empty; - var tokenInsert = isAsync - ? isParametrized - ? ", cancellationToken : " + method.Parameters[1].Name - : ", cancellationToken : " + method.Parameters[0].Name + 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})" @@ -229,11 +262,14 @@ namespace mROA.Codegen declaretedMethods.Add(sb.ToString()); } + private static Predicate ParameterFilter = + i => i.Type.Name is "CancellationToken" or "RequestContext"; + public void GeneratePropertyMethod(IMethodSymbol method, List methods, List<(string, IMethodSymbol)> propsCollection) { var index = methods.IndexOf(method); - var sb = new StringBuilder(); + var sb = ""; if (method.MethodKind == MethodKind.PropertyGet) { var parametersArray = ""; @@ -242,19 +278,18 @@ namespace mROA.Codegen parametersArray = $", new object[] {{{string.Join(", ", method.Parameters.Select(p => p.Name))}}}"; } - sb.AppendLine( - $"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).Wait();"); + sb = + $"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).GetAwaiter().GetResult();"; } else { - var parametersArray = ""; + var parametersArray = "value"; if (method.Parameters.Length != 0) { - parametersArray = ", " + string.Join(", ", method.Parameters.Select(p => p.Name)); + parametersArray = string.Join(", ", method.Parameters.Select(p => p.Name)); } - sb.AppendLine( - $"set => CallAsync({index}, new object[] {{ value{parametersArray} }}).GetAwaiter().GetResult();"); + sb = $"set => CallAsync({index}, new object[] {{ {parametersArray} }}).Wait();"; } propsCollection.Add((sb.ToString(), method)); From 4863010b471f0d13454cd03907c26dbb521a49b9 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 8 Mar 2025 19:46:59 +0300 Subject: [PATCH 33/66] =?UTF-8?q?=D0=92=20=D1=82=D0=B5=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BE=D0=BB=D0=B6=D0=B5=D0=BD=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D1=82=D1=8C=20=D0=BE=D0=B1=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=B1=D1=8D=D0=BA?= =?UTF-8?q?=D1=8D=D0=BD=D0=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 3 + Example.Frontend/ClientBasedPrinter.cs | 12 +- Example.Shared/IPrinter.cs | 1 + mROA.Codegen/mROASourceGenerator.cs | 181 ++++++++++++++++-- mROA/Abstract/IMethodInvoker.cs | 4 +- .../Backend/BasicExecutionModule.cs | 100 ++++++---- mROA/Implementation/MethodInvoker.cs | 22 ++- mROA/Implementation/NetworkMessage.cs | 2 +- .../UniversalObjectIdentifier.cs | 8 + 9 files changed, 264 insertions(+), 69 deletions(-) diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 170ba16..78bac1c 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,6 +10,8 @@ namespace Example.Backend { public string Name; + public decimal Resource { get; set; } + public string GetName() { return Name; @@ -30,5 +32,6 @@ namespace Example.Backend 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.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 888e802..754973c 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,16 +8,8 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { - public int Prop { get; set; } - public int get_Prop() - { - return 1; - } - - public int set_Prop(int value) - { - return 1; - } + public decimal Resource { get; set; } + public string GetName() { Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 383961d..c1743db 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -9,6 +9,7 @@ namespace Example.Shared [SharedObjectInterface] public interface IPrinter : IDisposable, IShared { + decimal Resource { get; set; } string GetName(); Task Print(string text, bool someParameter, CancellationToken cancellationToken); event Action OnPrint; diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 22a53ab..d31c93f 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -3,9 +3,7 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; using System.Linq; -using System.Reflection; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -33,6 +31,7 @@ namespace mROA.Codegen var frontendContextRepo = new List(); List innerMethods = new List(); + List invokers = new List(); var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList(); foreach (var classDeclarationSyntax in declarations) { @@ -43,7 +42,7 @@ namespace mROA.Codegen var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - innerMethods = CollectMembers(classSymbol); + innerMethods.AddRange(CollectMembers(classSymbol)); var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null) .Distinct(SymbolEqualityComparer.Default).Cast().ToList(); @@ -58,16 +57,16 @@ namespace mROA.Codegen var declaredMethods = new List(); var propertiesAccessMethods = new List<(string, IMethodSymbol)>(); - var propertiesImplementations = new List(associated.Count); + foreach (var method in innerMethods) { switch (method.MethodKind) { case MethodKind.PropertyGet or MethodKind.PropertySet: - GeneratePropertyMethod(method, innerMethods, propertiesAccessMethods); + GeneratePropertyMethod(method, innerMethods, propertiesAccessMethods, invokers); continue; default: - GenerateDeclaretedMethod(method, declaredMethods, innerMethods); + GenerateDeclaredMethod(method, declaredMethods, innerMethods, invokers); break; } } @@ -135,7 +134,8 @@ namespace {namespaceName} if (innerMethods.Count != 0) { - var methodsStringed = Array.Empty(); + var methodsStringed = invokers; + var coCodegenRepoCode = @$"// using System.Collections.Generic; @@ -143,6 +143,7 @@ using System.Reflection; using mROA.Abstract; using mROA.Implementation; using System; +using System.Threading; namespace mROA.Codegen {{ @@ -169,9 +170,11 @@ namespace mROA.Codegen }} }} "; +#if !DONT_ADD context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); +#endif } - + if (frontendContextRepo.Count != 0) { var fronendRepoCode = @$"// @@ -198,8 +201,17 @@ namespace mROA.Codegen } } - private void GenerateDeclaretedMethod(IMethodSymbol method, List declaretedMethods, - List methods) + public 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 methods, List invokers) { var index = methods.IndexOf(method); var sb = new StringBuilder(); @@ -259,40 +271,173 @@ namespace mROA.Codegen sb.AppendLine("\t\t}"); - declaretedMethods.Add(sb.ToString()); + 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[1] 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} 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} Invoking = (i, parameters, special) => {funcInvoking} +{level}}}"; + + invokers.Add(backend); } private static Predicate ParameterFilter = i => i.Type.Name is "CancellationToken" or "RequestContext"; public void GeneratePropertyMethod(IMethodSymbol method, List methods, - List<(string, IMethodSymbol)> propsCollection) + List<(string, IMethodSymbol)> propsCollection, List invokers) { + var level = "\t\t\t"; var index = methods.IndexOf(method); - var sb = ""; + 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 => + { + 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)}]"; + } + )); + backend = $@"new mROA.Implementation.MethodInvoker +{level}{{ +{level} IsVoid = false, +{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{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} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}, +{level}}}"; } - sb = + frontend = $"get => GetResultAsync<{method.ReturnType.ToDisplayString()}>({index}{parametersArray}).GetAwaiter().GetResult();"; } else { var parametersArray = "value"; - if (method.Parameters.Length != 0) + 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 = false, +{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert}, +{level}}}"; + } + else + { + backend = $@"new mROA.Implementation.MethodInvoker +{level}{{ +{level} IsVoid = false, +{level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}, +{level}}}"; } - sb = $"set => CallAsync({index}, new object[] {{ {parametersArray} }}).Wait();"; + frontend = $"set => CallAsync({index}, new object[] {{ {parametersArray} }}).Wait();"; } - propsCollection.Add((sb.ToString(), method)); + propsCollection.Add((frontend, method)); + invokers.Add(backend); } private static string ToFullString(IParameterSymbol parameter) @@ -307,7 +452,7 @@ namespace mROA.Codegen private string ExtractTaskType(ITypeSymbol taskType) { - return (taskType as INamedTypeSymbol).TypeParameters[0].ToDisplayString(); + return (taskType as INamedTypeSymbol).TypeArguments[0].ToDisplayString(); } public void Initialize(GeneratorInitializationContext context) diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs index 439434a..eb5e182 100644 --- a/mROA/Abstract/IMethodInvoker.cs +++ b/mROA/Abstract/IMethodInvoker.cs @@ -3,12 +3,10 @@ using System; namespace mROA.Abstract { public interface IMethodInvoker - { - bool IsAsync { get; } + { bool IsVoid { get; } Type[] ParameterTypes { get; } Type? ReturnType { get; } - object? Invoke(object instance, object?[]? parameters, object[] special); Type SuitableType { get; } } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 31e9ee1..3e94cb2 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -58,7 +58,7 @@ namespace mROA.Implementation.Backend throw new NullReferenceException("Can't find cancellation for this request"); cts.Cancel(); _cancellationRepo.FreeCancelation(command.Id); - + return new FinalCommandExecution { Id = command.Id @@ -75,7 +75,7 @@ namespace mROA.Implementation.Backend if (context == null) throw new NullReferenceException("Instance can't be null"); - + object?[]? castedParams = null; @@ -87,18 +87,19 @@ namespace mROA.Implementation.Backend castedParams[i] = _serialization.Cast(command.Parameters![i], invoker.ParameterTypes[i]); } } - + var execContext = new RequestContext(command.Id, representationModule.Id); - if (invoker is { IsAsync: true, IsVoid: false }) - return TypedExecuteAsync(invoker, context, castedParams, command, _cancellationRepo, + if (invoker is AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker) + return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command, + _cancellationRepo, representationModule, execContext); - if (invoker.IsAsync) - return ExecuteAsync(invoker, context, castedParams, command, _cancellationRepo, + if (invoker is AsyncMethodInvoker asyncMethodInvoker) + return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo, representationModule, execContext); - var result = Execute(invoker, context, castedParams, command, execContext); + var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); if (command.CommandId == -1) { #if TRACE @@ -119,7 +120,7 @@ namespace mROA.Implementation.Backend } } - private static ICommandExecution Execute(IMethodInvoker invoker, object instance, object?[] parameter, + private static ICommandExecution Execute(MethodInvoker invoker, object instance, object?[] parameter, ICallRequest command, RequestContext executionContext) { try @@ -150,7 +151,7 @@ namespace mROA.Implementation.Backend } } - private ICommandExecution ExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters, + private ICommandExecution ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule, RequestContext executionContext) { @@ -162,10 +163,7 @@ namespace mROA.Implementation.Backend #endif try { - var result = (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!; - - - result.ContinueWith(_ => + invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ => { if (token.IsCancellationRequested) return; @@ -182,7 +180,26 @@ namespace mROA.Implementation.Backend multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, payload); multiClientOwnershipRepository?.FreeOwnership(); - }, token); + }); + + // result.ContinueWith(_ => + // { + // 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(); + // }, token); return new AsyncCommandExecution { @@ -199,7 +216,7 @@ namespace mROA.Implementation.Backend } } - private ICommandExecution TypedExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters, + private ICommandExecution TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, ICallRequest command, ICancellationRepository cancellationRepository, IRepresentationModule representationModule, RequestContext executionContext) { @@ -209,25 +226,42 @@ namespace mROA.Implementation.Backend var token = tokenSource.Token; try { - var result = - (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!; - - result.ContinueWith(t => - { - var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); - var payload = new FinalCommandExecution + invoker.Invoke(instance, parameters, new object[] { executionContext, token }, + finalResult => { - Id = command.Id, - Result = finalResult - }; - _cancellationRepo!.FreeCancelation(command.Id); + 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(); - }, token); + var multiClientOwnershipRepository = + TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; + multiClientOwnershipRepository?.RegisterOwnership(representationModule.Id); + representationModule.PostCallMessage(command.Id, MessageType.FinishedCommandExecution, + payload); + multiClientOwnershipRepository?.FreeOwnership(); + }); + + + + // result.ContinueWith(t => + // { + // var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); + // 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(); + // }, token); return new AsyncCommandExecution { diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index 8299a0a..4edea72 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -5,11 +5,10 @@ namespace mROA.Implementation { public class MethodInvoker : IMethodInvoker { - public bool IsAsync { get; set; } public bool IsVoid { get; set; } public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type? ReturnType { get; set; } - public Func Invoking { get; set; } = (_, _, _) => null; + public Func Invoking { get; set; } = (_, _, _) => null; public object? Invoke(object instance, object?[]? parameters, object[] special) { @@ -17,10 +16,9 @@ namespace mROA.Implementation } public Type SuitableType { get; set; } = null!; - + public static readonly IMethodInvoker Dispose = new MethodInvoker { - IsAsync = false, IsVoid = true, ReturnType = null, Invoking = (instance, _, _) => @@ -31,4 +29,20 @@ namespace mROA.Implementation 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/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 7b04c12..dd71589 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -15,6 +15,6 @@ namespace mROA.Implementation public enum MessageType { - Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCommandExecution, CallRequest, IdAssigning, CancelRequest + Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCommandExecution, CallRequest, IdAssigning, CancelRequest, EventRequest } } \ No newline at end of file diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 781567e..694636c 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -1,10 +1,18 @@ using System; +using mROA.Abstract; namespace mROA.Implementation { #pragma warning disable CS8618, CS9264 public struct UniversalObjectIdentifier : IEquatable { + private static IMethodInvoker x = new MethodInvoker + { + IsVoid = false, + ReturnType = typeof(void), + ParameterTypes = Type.EmptyTypes + + }; public int ContextId; public int OwnerId; From 0e09b479afa3caf9c59088189641932d1d2f5809 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 8 Mar 2025 22:31:40 +0300 Subject: [PATCH 34/66] =?UTF-8?q?=D0=97=D0=B0=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=BB=D0=B0=20=D0=B4=D0=B5=D0=BC=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=81=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=BC=20=D0=B1=D1=8D=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 2 +- mROA.Codegen/mROASourceGenerator.cs | 24 ++++++++++++------- .../Backend/BasicExecutionModule.cs | 2 +- mROA/Implementation/MethodInvoker.cs | 1 - .../UniversalObjectIdentifier.cs | 7 ------ 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 427df96..fdab3b8 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -17,7 +17,7 @@ class Program public static void Main(string[] args) { var builder = new FullMixBuilder(); - // new RemoteTypeBinder(); + new RemoteTypeBinder(); // builder.Modules.Add(new JsonSerializationToolkit()); builder.Modules.Add(new CborSerializationToolkit()); diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index d31c93f..469023e 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -29,8 +29,8 @@ namespace mROA.Codegen // var reader = new StreamReader(test); // var allText = reader.ReadToEnd(); var frontendContextRepo = new List(); + List totalMethods = new List(); - List innerMethods = new List(); List invokers = new List(); var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList(); foreach (var classDeclarationSyntax in declarations) @@ -39,10 +39,11 @@ namespace mROA.Codegen if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol) continue; + List innerMethods = new List(); var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); var className = classDeclarationSyntax.Identifier.Text; - innerMethods.AddRange(CollectMembers(classSymbol)); + innerMethods = CollectMembers(classSymbol); var associated = innerMethods.Select(i => i.AssociatedSymbol).Where(i => i != null) .Distinct(SymbolEqualityComparer.Default).Cast().ToList(); @@ -50,6 +51,8 @@ namespace mROA.Codegen i.MethodKind != MethodKind.EventAdd && i.MethodKind != MethodKind.EventRemove) .ToList(); + totalMethods.AddRange(innerMethods); + var originalName = className; className = className.TrimStart('I') + "RemoteEndpoint"; @@ -63,10 +66,10 @@ namespace mROA.Codegen switch (method.MethodKind) { case MethodKind.PropertyGet or MethodKind.PropertySet: - GeneratePropertyMethod(method, innerMethods, propertiesAccessMethods, invokers); + GeneratePropertyMethod(method, totalMethods, propertiesAccessMethods, invokers); continue; default: - GenerateDeclaredMethod(method, declaredMethods, innerMethods, invokers); + GenerateDeclaredMethod(method, declaredMethods, totalMethods, invokers); break; } } @@ -132,11 +135,10 @@ namespace {namespaceName} $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); } - if (innerMethods.Count != 0) + if (totalMethods.Count != 0) { var methodsStringed = invokers; - - + var coCodegenRepoCode = @$"// using System.Collections.Generic; using System.Reflection; @@ -174,7 +176,7 @@ namespace mROA.Codegen context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); #endif } - + if (frontendContextRepo.Count != 0) { var fronendRepoCode = @$"// @@ -325,6 +327,7 @@ namespace mROA.Codegen {level} IsVoid = {isVoid.ToString().ToLower()}, {(isVoid ? String.Empty : (level + "\t" + "ReturnType = typeof(" + ExtractTaskType(method.ReturnType)) + "),")} {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, special, post) => {funcInvoking}, {level}}}"; else @@ -333,6 +336,7 @@ namespace mROA.Codegen {level} IsVoid = {isVoid.ToString().ToLower()}, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, special) => {funcInvoking} {level}}}"; @@ -373,6 +377,7 @@ namespace mROA.Codegen {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}], {level}}}"; } @@ -382,6 +387,7 @@ namespace mROA.Codegen {level}{{ {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}, {level}}}"; } @@ -420,6 +426,7 @@ namespace mROA.Codegen {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert}, {level}}}"; } @@ -429,6 +436,7 @@ namespace mROA.Codegen {level}{{ {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}, {level}}}"; } diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 3e94cb2..7199b42 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -79,7 +79,7 @@ namespace mROA.Implementation.Backend object?[]? castedParams = null; - if (invoker.ParameterTypes != Type.EmptyTypes) + if (invoker.ParameterTypes.Length != 0) { castedParams = new object[invoker.ParameterTypes.Length]; for (int i = 0; i < castedParams.Length; i++) diff --git a/mROA/Implementation/MethodInvoker.cs b/mROA/Implementation/MethodInvoker.cs index 4edea72..59efb7d 100644 --- a/mROA/Implementation/MethodInvoker.cs +++ b/mROA/Implementation/MethodInvoker.cs @@ -20,7 +20,6 @@ namespace mROA.Implementation public static readonly IMethodInvoker Dispose = new MethodInvoker { IsVoid = true, - ReturnType = null, Invoking = (instance, _, _) => { (instance as IDisposable)?.Dispose(); diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 694636c..29491f2 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -6,13 +6,6 @@ namespace mROA.Implementation #pragma warning disable CS8618, CS9264 public struct UniversalObjectIdentifier : IEquatable { - private static IMethodInvoker x = new MethodInvoker - { - IsVoid = false, - ReturnType = typeof(void), - ParameterTypes = Type.EmptyTypes - - }; public int ContextId; public int OwnerId; From 493f56c99a5bb57c7f60267516d178ba53acd6a7 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 8 Mar 2025 23:22:59 +0300 Subject: [PATCH 35/66] =?UTF-8?q?=D0=9A=D0=B0=D0=BA=20=D1=82=D0=BE=20?= =?UTF-8?q?=D1=85=D1=83=D0=B4=D0=BE-=D0=B1=D0=B5=D0=B4=D0=BD=D0=BE=20?= =?UTF-8?q?=D0=BD=D0=B0=D1=87=D0=B8=D0=BD=D0=B0=D0=B5=D1=82=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0=D1=82=D1=8C=20=D0=BB=D1=83=D1=87=D1=88?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 3 ++- Example.Frontend/ClientBasedPrinter.cs | 2 +- Example.Frontend/Program.cs | 6 ++++++ Example.Shared/IPrinter.cs | 2 +- mROA.Cbor/CborSerializationToolkit.cs | 8 +++++--- mROA.Codegen/mROASourceGenerator.cs | 1 + 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 78bac1c..85bd58a 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,7 +10,7 @@ namespace Example.Backend { public string Name; - public decimal Resource { get; set; } + public double Resource { get; set; } = 100d; public string GetName() { @@ -22,6 +22,7 @@ namespace Example.Backend // throw new Exception("The method or operation is not implemented."); var page = new Page { Text = text }; OnPrint?.Invoke(page); + Resource /= 1.5; return page; } diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 754973c..4c9bea7 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,7 +8,7 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { - public decimal Resource { get; set; } + public double Resource { get; set; } public string GetName() { diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index fdab3b8..07fa4ab 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -75,6 +75,12 @@ class Program var page = disposingPrinter.Print("Test Page", false, CancellationToken.None).GetAwaiter().GetResult(); Console.WriteLine("Page printed"); Console.WriteLine(page.ToString()); + + Console.WriteLine($"Printer resource : {disposingPrinter.Resource}"); + Console.WriteLine("Restoring resource"); + disposingPrinter.Resource = 100; + Console.WriteLine($"Printer resource again : {disposingPrinter.Resource}"); + var data = page.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index c1743db..a94aae4 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -9,7 +9,7 @@ namespace Example.Shared [SharedObjectInterface] public interface IPrinter : IDisposable, IShared { - decimal Resource { get; set; } + double Resource { get; set; } string GetName(); Task Print(string text, bool someParameter, CancellationToken cancellationToken); event Action OnPrint; diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 847f2cc..12016df 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -56,13 +56,13 @@ namespace mROA.Cbor { if (nonCasted == null) return null; - + if (nonCasted.GetType() == type) return nonCasted; if (nonCasted is PreParsedValue preParsed) return preParsed.ToObject(type, context); - return null; + return Convert.ChangeType(nonCasted, type); } private void WriteData(object? obj, CborWriter writer, IEndPointContext? context) @@ -214,6 +214,9 @@ namespace mROA.Cbor 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); @@ -308,7 +311,6 @@ namespace mROA.Cbor if (type.IsInterface) { - var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type); var so = Activator.CreateInstance(sharedShell) as diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 469023e..44217d5 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -436,6 +436,7 @@ namespace mROA.Codegen {level}{{ {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), +{level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.ToDisplayString()}) }}, {level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}, {level}}}"; From e0088ea22c7399b49833919eb4209a03008dcfac Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Sat, 8 Mar 2025 23:55:28 +0300 Subject: [PATCH 36/66] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=B8=D1=81?= =?UTF-8?q?=D0=BA=D0=BB=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D0=B2=D1=8B=D0=B7=D0=BE=D0=B2=D0=B5=20=D1=81=D0=B5?= =?UTF-8?q?=D1=82=D1=82=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Codegen/mROASourceGenerator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 44217d5..b420758 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -423,7 +423,7 @@ namespace mROA.Codegen "parameters[" + (method.Parameters.Length - 1) + "]"); backend = $@"new mROA.Implementation.MethodInvoker {level}{{ -{level} IsVoid = false, +{level} IsVoid = true, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, {level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), @@ -434,7 +434,7 @@ namespace mROA.Codegen { backend = $@"new mROA.Implementation.MethodInvoker {level}{{ -{level} IsVoid = false, +{level} IsVoid = true, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.ToDisplayString()}) }}, {level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), From 0dbc065d9e25594bb6166ece7194e39d8af710fd Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 00:00:24 +0300 Subject: [PATCH 37/66] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=B8=20=D0=B4=D0=BE=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BA=D0=BE=D0=B4=D0=B3=D0=B5?= =?UTF-8?q?=D0=BD,=20=D0=BD=D0=BE=20=D0=BD=D0=B5=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=B4=D0=B5=D0=BC=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/CsTest.cs | 1 - Example.Backend/PagesList.cs | 20 +- Example.Backend/Printer.cs | 13 +- Example.Backend/PrinterFactory.cs | 1 - Example.Backend/Program.cs | 4 +- Example.Frontend/ClientBasedPrinter.cs | 12 +- Example.Frontend/Program.cs | 5 +- Example.Shared/IDataList.cs | 1 - Example.Shared/IPagesList.cs | 2 +- Example.Shared/IPrinter.cs | 6 +- mROA.Codegen/mROASourceGenerator.cs | 223 +++++++++++++----- mROA/Abstract/IMethodRepository.cs | 4 +- .../Backend/BasicExecutionModule.cs | 8 +- mROA/Implementation/CallRequest.cs | 3 +- .../CommandExecution/FinalCommandExecution.cs | 1 - .../Frontend/RequestExtractor.cs | 5 +- mROA/Implementation/SharedObjectShell.cs | 87 ++++--- .../UniversalObjectIdentifier.cs | 1 - 18 files changed, 248 insertions(+), 149 deletions(-) diff --git a/Example.Backend/CsTest.cs b/Example.Backend/CsTest.cs index 8db1c75..ac30cb4 100644 --- a/Example.Backend/CsTest.cs +++ b/Example.Backend/CsTest.cs @@ -1,4 +1,3 @@ -using System; using Example.Shared; namespace Example.Backend diff --git a/Example.Backend/PagesList.cs b/Example.Backend/PagesList.cs index 1ce6be0..1b195c9 100644 --- a/Example.Backend/PagesList.cs +++ b/Example.Backend/PagesList.cs @@ -8,27 +8,31 @@ namespace Example.Backend { public class PagesList : RemoteObjectBase, IPagesList { + public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule) + { + } + public IReadOnlyList Collection { get; } - public Example.Shared.IPage this[int index] + public IPage this[int index] { - get => GetResultAsync(3, new object[] { index }).GetAwaiter().GetResult(); + get => GetResultAsync(3, new object[] { index }).GetAwaiter().GetResult(); set => CallAsync(5, new object[] { index, value }).Wait(); } public IPage Get(int index) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Add(IPage item) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public void Remove(int index, IPage item) { - throw new System.NotImplementedException(); + throw new NotImplementedException(); } public event Action? OnAdd; @@ -39,7 +43,11 @@ namespace Example.Backend // TODO release managed resources here } - public PagesList(int id, IRepresentationModule representationModule) : base(id, representationModule) + public void OnAddExternal(IPage p0) + { + } + + public void OnRemoveExternal(IPage p0) { } } diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 85bd58a..c001071 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,6 +10,10 @@ namespace Example.Backend { public string Name; + public void OnPrintExternal(IPage p0, RequestContext p1) + { + } + public double Resource { get; set; } = 100d; public string GetName() @@ -17,22 +21,23 @@ namespace Example.Backend return Name; } - public async Task Print(string text, bool some, CancellationToken cancellationToken = default) + 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 }; - OnPrint?.Invoke(page); + Console.WriteLine($"Request id : :{context.RequestId}"); + OnPrint?.Invoke(page, context); Resource /= 1.5; return page; } - public event Action? OnPrint; + 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 1fc2624..efc3975 100644 --- a/Example.Backend/PrinterFactory.cs +++ b/Example.Backend/PrinterFactory.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; using System.Linq; using Example.Shared; -using mROA.Implementation; using mROA.Implementation.Attributes; namespace Example.Backend diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index a6b3ffc..73383be 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,6 +1,5 @@ using System.Net; using Example.Backend; -using Example.Shared; using mROA.Abstract; using mROA.Cbor; using mROA.Codegen; @@ -38,7 +37,7 @@ class Program new IInjectableModule[] { builder.GetModule()! }, typeof(RepresentationModule))); builder.Modules.Add(new CancellationRepository()); - + builder.Build(); new RemoteTypeBinder(); @@ -49,6 +48,5 @@ class Program var gateway = builder.GetModule(); gateway.Run(); - } } \ No newline at end of file diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 4c9bea7..ed45914 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,27 +8,31 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { + public void OnPrintExternal(IPage p0, RequestContext p1) + { + } + public double Resource { get; set; } public string GetName() { Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); - + return "ClientBasedPrinter from mroa"; } - public async Task Print(string text, bool some, CancellationToken cancellationToken) + 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 event Action? OnPrint; public void Dispose() { - } } diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 07fa4ab..07bd283 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -72,7 +72,8 @@ class Program Console.WriteLine(string.Join(", ", names)); - var page = disposingPrinter.Print("Test Page", false, CancellationToken.None).GetAwaiter().GetResult(); + var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter() + .GetResult(); Console.WriteLine("Page printed"); Console.WriteLine(page.ToString()); @@ -112,7 +113,5 @@ class Program // 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/IDataList.cs b/Example.Shared/IDataList.cs index f08bb75..bdaae63 100644 --- a/Example.Shared/IDataList.cs +++ b/Example.Shared/IDataList.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using mROA.Implementation; -using mROA.Implementation.Attributes; namespace Example.Shared { diff --git a/Example.Shared/IPagesList.cs b/Example.Shared/IPagesList.cs index 05bcc6a..0b4d5d5 100644 --- a/Example.Shared/IPagesList.cs +++ b/Example.Shared/IPagesList.cs @@ -3,7 +3,7 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPagesList : IDataList + public partial interface IPagesList : IDataList { } } \ No newline at end of file diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index a94aae4..f5b25f0 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -7,11 +7,11 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPrinter : IDisposable, IShared + public partial interface IPrinter : IDisposable, IShared { double Resource { get; set; } string GetName(); - Task Print(string text, bool someParameter, CancellationToken cancellationToken); - event Action OnPrint; + Task Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken); + event Action OnPrint; } } \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index b420758..33e2465 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -9,7 +9,6 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; - namespace mROA.Codegen { /// @@ -19,6 +18,45 @@ namespace mROA.Codegen [Generator] public class mROASourceGenerator : ISourceGenerator { + private static Predicate ParameterFilter = + i => i.Type.Name is "CancellationToken" or "RequestContext"; + + private static Predicate ParameterFilterForType = + i => i.Name is "CancellationToken" or "RequestContext"; + + public void Initialize(GeneratorInitializationContext context) + { + } + + public void Execute(GeneratorExecutionContext context) + { + var trees = context.Compilation.SyntaxTrees; + + var interfaces = new List(); + foreach (var tree in trees) + { + 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) + + if (inside is InterfaceDeclarationSyntax ids2) + if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2)) + interfaces.Add(ids2); + } + } + } + + GenerateCode(context, context.Compilation, interfaces.ToImmutableArray()); + } + private void GenerateCode(GeneratorExecutionContext context, Compilation compilation, ImmutableArray classes) { @@ -31,6 +69,7 @@ namespace mROA.Codegen var frontendContextRepo = 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) @@ -52,7 +91,7 @@ namespace mROA.Codegen .ToList(); totalMethods.AddRange(innerMethods); - + var originalName = className; className = className.TrimStart('I') + "RemoteEndpoint"; @@ -66,10 +105,11 @@ namespace mROA.Codegen switch (method.MethodKind) { case MethodKind.PropertyGet or MethodKind.PropertySet: - GeneratePropertyMethod(method, totalMethods, propertiesAccessMethods, invokers); + GeneratePropertyMethod(method, propertiesAccessMethods, invokers, + classSymbol); continue; default: - GenerateDeclaredMethod(method, declaredMethods, totalMethods, invokers); + GenerateDeclaredMethod(method, declaredMethods, invokers, classSymbol); break; } } @@ -105,6 +145,8 @@ namespace mROA.Codegen } } + GenerateEventImplementation(classSymbol, invokers, declaredMethods, context); + var code = $@"// using mROA; @@ -138,7 +180,7 @@ namespace {namespaceName} if (totalMethods.Count != 0) { var methodsStringed = invokers; - + var coCodegenRepoCode = @$"// using System.Collections.Generic; using System.Reflection; @@ -203,7 +245,61 @@ namespace mROA.Codegen } } - public static string Caster(ITypeSymbol type, string inner) + private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List invokers, + List declaredMethods, GeneratorExecutionContext context) + { + var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) + .OfType().ToList(); + if (events.Count == 0) + return; + + var additionalSignatures = new List(events.Count); + var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); + + for (int i = 0; i < events.Count; i++) + { + var currentEvent = events[i]; + + var additionalMethod = GenerateMethodExternalCaller(currentEvent, out var signature); + declaredMethods.Add(additionalMethod); + additionalSignatures.Add(signature); + GenerateEventCode(currentEvent, invokers, classSymbol); + } + + var partialInterface = $@" +namespace {classSymbol.ContainingNamespace.ToDisplayString()} +{{ + public partial interface {classSymbol.Name} + {{ +{string.Join("\r\n", additionalSignatures)} + }} +}} +"; +#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 + @@ -212,10 +308,10 @@ namespace mROA.Codegen return $"({type.ToDisplayString()})" + inner; } - private void GenerateDeclaredMethod(IMethodSymbol method, List declaredMethods, - List methods, List invokers) + private void GenerateDeclaredMethod(IMethodSymbol method, List declaredMethods, List invokers, + INamedTypeSymbol baseInterace) { - var index = methods.IndexOf(method); + var index = invokers.Count; var sb = new StringBuilder(); bool isParametrized; @@ -327,7 +423,7 @@ namespace mROA.Codegen {level} IsVoid = {isVoid.ToString().ToLower()}, {(isVoid ? String.Empty : (level + "\t" + "ReturnType = typeof(" + ExtractTaskType(method.ReturnType)) + "),")} {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, -{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), +{level} SuitableType = typeof({baseInterace.ToDisplayString()}), {level} Invoking = (i, parameters, special, post) => {funcInvoking}, {level}}}"; else @@ -336,21 +432,62 @@ namespace mROA.Codegen {level} IsVoid = {isVoid.ToString().ToLower()}, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, -{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), +{level} SuitableType = typeof({baseInterace.ToDisplayString()}), {level} Invoking = (i, parameters, special) => {funcInvoking} {level}}}"; invokers.Add(backend); } - private static Predicate ParameterFilter = - i => i.Type.Name is "CancellationToken" or "RequestContext"; - - public void GeneratePropertyMethod(IMethodSymbol method, List methods, - List<(string, IMethodSymbol)> propsCollection, List invokers) + private void GenerateEventCode(IEventSymbol eventSymbol, List invokers, ITypeSymbol baseInterface) { var level = "\t\t\t"; - var index = methods.IndexOf(method); + + 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[1] 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) @@ -363,21 +500,14 @@ namespace mROA.Codegen var parameterTypes = string.Join(", ", $"{string.Join(", ", method.Parameters.Select(p => "typeof(" + p.Type.ToDisplayString() + ")"))}"); var parameterInserts = string.Join(", ", - method.Parameters.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)}]"; - } - )); + 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({method.ContainingType.ToDisplayString()}), +{level} SuitableType = typeof({baseInterace.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}], {level}}}"; } @@ -387,7 +517,7 @@ namespace mROA.Codegen {level}{{ {level} IsVoid = false, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), -{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), +{level} SuitableType = typeof({baseInterace.ToDisplayString()}), {level} Invoking = (i, _, _) => (i as {method.ContainingType.ToDisplayString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}, {level}}}"; } @@ -426,7 +556,7 @@ namespace mROA.Codegen {level} IsVoid = true, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ {parameterTypes} }}, -{level} SuitableType = typeof({method.ContainingType.ToDisplayString()}), +{level} SuitableType = typeof({baseInterace.ToDisplayString()}), {level} Invoking = (i, parameters, _) => (i as {method.ContainingType.ToDisplayString()})[{parameterInserts}] = {valueInsert}, {level}}}"; } @@ -437,7 +567,7 @@ namespace mROA.Codegen {level} IsVoid = true, {level} ReturnType = typeof({method.ReturnType.ToDisplayString()}), {level} ParameterTypes = new Type[] {{ typeof({method.Parameters.First().Type.ToDisplayString()}) }}, -{level} SuitableType = typeof({method.ContainingType.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}}}"; } @@ -464,39 +594,6 @@ namespace mROA.Codegen return (taskType as INamedTypeSymbol).TypeArguments[0].ToDisplayString(); } - public void Initialize(GeneratorInitializationContext context) - { - } - - public void Execute(GeneratorExecutionContext context) - { - var trees = context.Compilation.SyntaxTrees; - - var interfaces = new List(); - foreach (var tree in trees) - { - 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) - - if (inside is InterfaceDeclarationSyntax ids2) - if (ContainsSOIAttribute(ids2.AttributeLists, context, ids2)) - interfaces.Add(ids2); - } - } - } - - GenerateCode(context, context.Compilation, interfaces.ToImmutableArray()); - } - private bool ContainsSOIAttribute(SyntaxList attributes, GeneratorExecutionContext context, InterfaceDeclarationSyntax interfaceDeclarationSyntax) { diff --git a/mROA/Abstract/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs index ec67928..4c468f1 100644 --- a/mROA/Abstract/IMethodRepository.cs +++ b/mROA/Abstract/IMethodRepository.cs @@ -1,6 +1,4 @@ -using System.Reflection; - -namespace mROA.Abstract +namespace mROA.Abstract { public interface IMethodRepository : IInjectableModule { diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 7199b42..aa5b3ba 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -1,8 +1,5 @@ using System; -using System.Linq; -using System.Reflection; using System.Threading; -using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.CommandExecution; @@ -10,8 +7,8 @@ namespace mROA.Implementation.Backend { public class BasicExecutionModule : IExecuteModule { - private IMethodRepository? _methodRepo; private ICancellationRepository? _cancellationRepo; + private IMethodRepository? _methodRepo; private ISerializationToolkit? _serialization; public void Inject(T dependency) @@ -244,8 +241,7 @@ namespace mROA.Implementation.Backend multiClientOwnershipRepository?.FreeOwnership(); }); - - + // result.ContinueWith(t => // { // var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 9066319..0549069 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -1,5 +1,4 @@ using System; -using mROA.Implementation.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global @@ -21,6 +20,7 @@ namespace mROA.Implementation public int ObjectId { get; set; } = -1; public object?[]? Parameters { get; set; } + public override string ToString() { return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; @@ -33,6 +33,7 @@ namespace mROA.Implementation public int CommandId { get; set; } = -2; public int ObjectId { get; set; } = -2; public object?[]? Parameters { get; set; } = null; + public override string ToString() { return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}"; diff --git a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs index 2a99331..fba0dca 100644 --- a/mROA/Implementation/CommandExecution/FinalCommandExecution.cs +++ b/mROA/Implementation/CommandExecution/FinalCommandExecution.cs @@ -1,5 +1,4 @@ using System; -using System.Text.Json.Serialization; using mROA.Abstract; // ReSharper disable UnusedAutoPropertyAccessor.Global diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 751e10d..d4b141c 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -12,10 +11,10 @@ namespace mROA.Implementation.Frontend { public class RequestExtractor : IRequestExtractor { - private IRepresentationModule? _representationModule; private IContextRepository? _contextRepository; - private IMethodRepository? _methodRepository; private IExecuteModule? _executeModule; + private IMethodRepository? _methodRepository; + private IRepresentationModule? _representationModule; private ISerializationToolkit? _serializationToolkit; public void Inject(T dependency) diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 3e55a78..27e1ab2 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -1,6 +1,5 @@ using System; using System.Text.Json.Serialization; -using System.Threading.Tasks; using mROA.Abstract; using mROA.Implementation.Attributes; @@ -18,47 +17,22 @@ namespace mROA.Implementation public class SharedObjectShellShell : ISharedObjectShell where T : notnull { - [SerializationIgnore] - [JsonIgnore] - public IEndPointContext EndPointContext { get; set; } = new EndPointContext - { - RealRepository = TransmissionConfig.RealContextRepository, - RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, - HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), - OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId - }; - - private IContextRepository GetDefaultContextRepository() => - (_identifier.OwnerId == EndPointContext.HostId - ? EndPointContext.RealRepository - : EndPointContext.RemoteRepository) ?? - throw new NullReferenceException( - "DefaultContextRepository was not defined"); - private UniversalObjectIdentifier _identifier = UniversalObjectIdentifier.Null; - public UniversalObjectIdentifier Identifier - { - get - { - _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; - return _identifier; - } - set - { - _identifier = value; - Value = GetDefaultContextRepository().GetObjectBySharedObject(this); - } - } - - public object UniversalValue - { - get => _value; - set => _value = (T)value; - } - private T _value; + // ReSharper disable once MemberCanBePrivate.Global + // ReSharper disable once UnusedMember.Global + public SharedObjectShellShell() + { + } + + // ReSharper disable once UnusedMember.Global + public SharedObjectShellShell(T value) + { + Value = value; + } + [JsonIgnore] [SerializationIgnore] public T Value @@ -80,18 +54,43 @@ namespace mROA.Implementation } } - // ReSharper disable once MemberCanBePrivate.Global - // ReSharper disable once UnusedMember.Global - public SharedObjectShellShell() + [SerializationIgnore] + [JsonIgnore] + public IEndPointContext EndPointContext { get; set; } = new EndPointContext { + RealRepository = TransmissionConfig.RealContextRepository, + RemoteRepository = TransmissionConfig.RemoteEndpointContextRepository, + HostId = TransmissionConfig.OwnershipRepository.GetHostOwnershipId(), + OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId + }; + + public UniversalObjectIdentifier Identifier + { + get + { + _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; + return _identifier; + } + set + { + _identifier = value; + Value = GetDefaultContextRepository().GetObjectBySharedObject(this); + } } - // ReSharper disable once UnusedMember.Global - public SharedObjectShellShell(T value) + public object UniversalValue { - Value = value; + 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(T value) => diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 29491f2..781567e 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -1,5 +1,4 @@ using System; -using mROA.Abstract; namespace mROA.Implementation { From b1424fbe3297a86bb40bcc0aed03dce9b28414e1 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 00:12:13 +0300 Subject: [PATCH 38/66] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B0=D1=81=D0=BF=D0=BE=D0=BB=D0=BE=D0=B6=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=81=D0=BF=D0=B5=D1=86=D0=B8=D0=B0=D0=BB?= =?UTF-8?q?=D1=8C=D0=BD=D1=8B=D1=85=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Codegen/mROASourceGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 33e2465..8db3063 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -385,7 +385,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} parametersInsertList.Add("(CancellationToken)special[1]"); break; case "RequestContext": - parametersInsertList.Add("special[1] as RequestContext"); + parametersInsertList.Add("special[0] as RequestContext"); break; default: parametersInsertList.Add(Caster(parameter.Type, From ce14258bf7808b6af6699bd531e8e591c0bf2e6f Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 11:19:08 +0300 Subject: [PATCH 39/66] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=BA=D0=B8=D0=B4?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BD=D1=82?= =?UTF-8?q?=D0=B5=D0=BA=D1=81=D1=82=D0=B0=20=D0=BA=D0=BE=D0=BD=D0=B5=D1=87?= =?UTF-8?q?=D0=BD=D0=BE=D0=B9=20=D1=82=D0=BE=D1=87=D0=BA=D0=B8=20=D0=B2=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8E=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/IContextRepository.cs | 4 +- .../Backend/ContextRepository.cs | 6 +- .../Backend/MultiClientContextRepository.cs | 8 +- .../Frontend/RequestExtractor.cs | 125 +++++++++--------- .../Implementation/RemoteContextRepository.cs | 4 +- mROA/Implementation/SharedObjectShell.cs | 2 +- 6 files changed, 76 insertions(+), 73 deletions(-) diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index f9c643b..6307373 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -5,11 +5,11 @@ namespace mROA.Abstract { public interface IContextRepository : IInjectableModule { - int ResisterObject(object o); + int ResisterObject(object o, IEndPointContext context); void ClearObject(int id); T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell); T? GetObject(int id); object GetSingleObject(Type type); - int GetObjectIndex(object o); + int GetObjectIndex(object o, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index e0371f8..4351e96 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -39,7 +39,7 @@ namespace mROA.Implementation.Backend Activator.CreateInstance); } - public int ResisterObject(object o) + public int ResisterObject(object o, IEndPointContext context) { if (!_lastIndexFinder.IsCompleted) _lastIndexFinder.Wait(); @@ -79,10 +79,10 @@ namespace mROA.Implementation.Backend return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); } - public int GetObjectIndex(object o) + public int GetObjectIndex(object o, IEndPointContext context) { var index = Array.IndexOf(_storage, o); - return index == -1 ? ResisterObject(o) : index; + return index == -1 ? ResisterObject(o, context) : index; } private int FindLastIndex() diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index f5c7bf4..e8dbef3 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -27,10 +27,10 @@ namespace mROA.Implementation.Backend { } - public int ResisterObject(object o) + public int ResisterObject(object o, IEndPointContext context) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.ResisterObject(o); + return repository.ResisterObject(o, context); } public void ClearObject(int id) @@ -63,10 +63,10 @@ namespace mROA.Implementation.Backend return repository.GetSingleObject(type); } - public int GetObjectIndex(object o) + public int GetObjectIndex(object o, IEndPointContext context) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetObjectIndex(o); + return repository.GetObjectIndex(o, context); } public IContextRepository GetRepository(int clientId) diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index d4b141c..ecda96d 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -39,84 +39,87 @@ namespace mROA.Implementation.Frontend } } - public async Task StartExtraction() + public 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 + return Task.Run(() => { - while (true) + 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 { + while (true) + { #if TRACE Console.WriteLine("Waiting for request..."); #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 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); - Task.WaitAny(defaultRequest, cancelRequest); + Task.WaitAny(defaultRequest, cancelRequest); #if TRACE Console.WriteLine("Request received"); #endif - if (cancelRequest.IsCompleted) - { + if (cancelRequest.IsCompleted) + { #if TRACE Console.WriteLine("Cancelling request"); #endif - var req = cancelRequest.Result; - tokenSource.Cancel(); - _executeModule.Execute(req, _contextRepository, _representationModule); - } - else - { - tokenSource.Cancel(); - var request = defaultRequest.Result; - - var result = _executeModule.Execute(request, _contextRepository, _representationModule); - - var resultType = MessageType.Unknown; - - switch (result) - { - case FinalCommandExecution: - resultType = MessageType.FinishedCommandExecution; - break; - case AsyncCommandExecution: - resultType = MessageType.AsyncCommandExecution; - break; - case ExceptionCommandExecution: - resultType = MessageType.ExceptionCommandExecution; - break; + var req = cancelRequest.Result; + tokenSource.Cancel(); + _executeModule.Execute(req, _contextRepository, _representationModule); } + else + { + tokenSource.Cancel(); + var request = defaultRequest.Result; - _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + var result = _executeModule.Execute(request, _contextRepository, _representationModule); + + var resultType = MessageType.Unknown; + + switch (result) + { + case FinalCommandExecution: + resultType = MessageType.FinishedCommandExecution; + break; + case AsyncCommandExecution: + resultType = MessageType.AsyncCommandExecution; + break; + case ExceptionCommandExecution: + resultType = MessageType.ExceptionCommandExecution; + break; + } + + _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + } } } - } - catch - { - multiClientOwnershipRepository?.FreeOwnership(); - } + catch + { + multiClientOwnershipRepository?.FreeOwnership(); + } + }); } } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 7648d80..4e0f6b6 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation private IRepresentationModuleProducer? _representationProducer; public static Dictionary RemoteTypes = new(); - public int ResisterObject(object o) + public int ResisterObject(object o, IEndPointContext context) { throw new NotSupportedException(); } @@ -58,7 +58,7 @@ namespace mROA.Implementation representationModule)!; } - public int GetObjectIndex(object o) + public int GetObjectIndex(object o, IEndPointContext context) { if (o is RemoteObjectBase remote) { diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 27e1ab2..8a2917d 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -49,7 +49,7 @@ namespace mROA.Implementation else { _identifier.OwnerId = EndPointContext.HostId; - _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value); + _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value, EndPointContext); } } } From e3710ffe209ad1e6e13377ec521e0bfe20f07f16 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 12:34:04 +0300 Subject: [PATCH 40/66] =?UTF-8?q?=D0=90=D0=B1=D1=81=D1=82=D1=80=D0=B0?= =?UTF-8?q?=D0=BA=D1=86=D0=B8=D1=8F=20=D0=B1=D0=B8=D0=BD=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/IContextRepository.cs | 4 ++-- mROA/Abstract/IEventBinder.cs | 7 +++++++ .../Backend/ContextRepository.cs | 20 +++++++++++++------ .../Backend/MultiClientContextRepository.cs | 8 ++++---- .../Implementation/RemoteContextRepository.cs | 4 ++-- mROA/Implementation/SharedObjectShell.cs | 2 +- 6 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 mROA/Abstract/IEventBinder.cs diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 6307373..0acbb60 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -5,11 +5,11 @@ namespace mROA.Abstract { public interface IContextRepository : IInjectableModule { - int ResisterObject(object o, IEndPointContext context); + int ResisterObject(object o, IEndPointContext context); void ClearObject(int id); T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell); T? GetObject(int id); object GetSingleObject(Type type); - int GetObjectIndex(object o, IEndPointContext context); + int GetObjectIndex(object o, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Abstract/IEventBinder.cs b/mROA/Abstract/IEventBinder.cs new file mode 100644 index 0000000..3527128 --- /dev/null +++ b/mROA/Abstract/IEventBinder.cs @@ -0,0 +1,7 @@ +namespace mROA.Abstract +{ + public interface IEventBinder + { + public void BindEvents(T source, IEndPointContext context); + } +} \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 4351e96..89bacf5 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -10,8 +10,11 @@ namespace mROA.Implementation.Backend { public class ContextRepository : IContextRepository { + public static object[] EventBinders = new object[]{}; private int _debugId = -1; + private static int LastDebugId = -1; + // [CanBeNull] private Dictionary _singletons; private object?[] _storage; @@ -39,13 +42,15 @@ namespace mROA.Implementation.Backend Activator.CreateInstance); } - public int ResisterObject(object o, IEndPointContext context) + public int ResisterObject(object o, IEndPointContext context) { if (!_lastIndexFinder.IsCompleted) _lastIndexFinder.Wait(); _storage[_lastIndexFinder.Result] = o; + EventBinders.OfType>().FirstOrDefault()?.BindEvents((T)o, context); + var last = _lastIndexFinder.Result; _lastIndexFinder = Task.Run(FindLastIndex); @@ -71,18 +76,21 @@ namespace mROA.Implementation.Backend public T GetObject(int id) { - return id == -1 || _storage.Length <= id ? throw new NullReferenceException("Cannot find that object. It is null"): (T)_storage[id]!; + return id == -1 || _storage.Length <= id + ? throw new NullReferenceException("Cannot find that object. It is null") + : (T)_storage[id]!; } public object GetSingleObject(Type type) { - return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); + return _singletons.GetValueOrDefault(type.GetHashCode()) ?? + throw new ArgumentException("Unregistered singleton type"); } - public int GetObjectIndex(object o, IEndPointContext context) + public int GetObjectIndex(object o, IEndPointContext context) { var index = Array.IndexOf(_storage, o); - return index == -1 ? ResisterObject(o, context) : index; + return index == -1 ? ResisterObject(o, context) : index; } private int FindLastIndex() @@ -98,9 +106,9 @@ namespace mROA.Implementation.Backend _storage = nextStorage; return _storage.Length; } + public void Inject(T dependency) { } - } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index e8dbef3..4b4194d 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -27,10 +27,10 @@ namespace mROA.Implementation.Backend { } - public int ResisterObject(object o, IEndPointContext context) + public int ResisterObject(object o, IEndPointContext context) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.ResisterObject(o, context); + return repository.ResisterObject(o, context); } public void ClearObject(int id) @@ -63,10 +63,10 @@ namespace mROA.Implementation.Backend return repository.GetSingleObject(type); } - public int GetObjectIndex(object o, IEndPointContext context) + public int GetObjectIndex(object o, IEndPointContext context) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetObjectIndex(o, context); + return repository.GetObjectIndex(o, context); } public IContextRepository GetRepository(int clientId) diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 4e0f6b6..e86e74f 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation private IRepresentationModuleProducer? _representationProducer; public static Dictionary RemoteTypes = new(); - public int ResisterObject(object o, IEndPointContext context) + public int ResisterObject(object o, IEndPointContext context) { throw new NotSupportedException(); } @@ -58,7 +58,7 @@ namespace mROA.Implementation representationModule)!; } - public int GetObjectIndex(object o, IEndPointContext context) + public int GetObjectIndex(object o, IEndPointContext context) { if (o is RemoteObjectBase remote) { diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 8a2917d..3fba873 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -49,7 +49,7 @@ namespace mROA.Implementation else { _identifier.OwnerId = EndPointContext.HostId; - _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value, EndPointContext); + _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value, EndPointContext); } } } From f4a92e4aac8ecabd1d786f7cc3696e8908d64466 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 16:35:56 +0300 Subject: [PATCH 41/66] =?UTF-8?q?=D0=A2=D0=B5=D0=BE=D1=80=D0=B5=D1=82?= =?UTF-8?q?=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=20=D0=B4=D0=BE=D0=BB=D0=B6?= =?UTF-8?q?=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D1=82=D1=8C?= =?UTF-8?q?!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Program.cs | 12 ++-- mROA.Codegen/mROASourceGenerator.cs | 63 ++++++++++++++++-- mROA/Abstract/IEventBinder.cs | 3 +- .../Backend/ContextRepository.cs | 66 ++++++++++--------- mROA/Implementation/EventBinder.cs | 15 +++++ .../Frontend/RequestExtractor.cs | 16 +++-- 6 files changed, 128 insertions(+), 47 deletions(-) create mode 100644 mROA/Implementation/EventBinder.cs diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 73383be..2885243 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -1,4 +1,5 @@ -using System.Net; +using System.Linq; +using System.Net; using Example.Backend; using mROA.Abstract; using mROA.Cbor; @@ -23,19 +24,20 @@ class Program 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(PrinterFactory).Assembly); + repo.Inject(builder.Modules.OfType().First()); return repo; })); builder.SetupMethodsRepository(new CoCodegenMethodRepository()); - builder.Modules.Add(new CreativeRepresentationModuleProducer( - new IInjectableModule[] { builder.GetModule()! }, - typeof(RepresentationModule))); + builder.Modules.Add(new CancellationRepository()); builder.Build(); diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 8db3063..cc8d06b 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -67,6 +67,7 @@ namespace mROA.Codegen // var reader = new StreamReader(test); // var allText = reader.ReadToEnd(); var frontendContextRepo = new List(); + var eventBinders = new List(); List totalMethods = new List(); @@ -145,7 +146,7 @@ namespace mROA.Codegen } } - GenerateEventImplementation(classSymbol, invokers, declaredMethods, context); + GenerateEventImplementation(classSymbol, invokers, declaredMethods, context, eventBinders); var code = $@"// @@ -222,11 +223,12 @@ namespace mROA.Codegen if (frontendContextRepo.Count != 0) { var fronendRepoCode = @$"// -using mROA.Implementation; -using mROA.Abstract; using System.Collections.Generic; -using System; using System.Reflection; +using System; +using mROA.Abstract; +using mROA.Implementation.Backend; +using mROA.Implementation; namespace mROA.Codegen {{ @@ -235,6 +237,8 @@ namespace mROA.Codegen 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)}}}; }} }} }} @@ -246,7 +250,7 @@ namespace mROA.Codegen } private void GenerateEventImplementation(INamedTypeSymbol classSymbol, List invokers, - List declaredMethods, GeneratorExecutionContext context) + List declaredMethods, GeneratorExecutionContext context, List binders) { var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) .OfType().ToList(); @@ -254,8 +258,7 @@ namespace mROA.Codegen return; var additionalSignatures = new List(events.Count); - var namespaceName = classSymbol.ContainingNamespace.ToDisplayString(); - + var singleEventBinder = new List(events.Count); for (int i = 0; i < events.Count; i++) { var currentEvent = events[i]; @@ -264,6 +267,7 @@ namespace mROA.Codegen declaredMethods.Add(additionalMethod); additionalSignatures.Add(signature); GenerateEventCode(currentEvent, invokers, classSymbol); + GenerateBinderCode(currentEvent, invokers, classSymbol, singleEventBinder); } var partialInterface = $@" @@ -275,6 +279,16 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} }} }} "; + var binder = $@"new EventBinder<{classSymbol.ToDisplayString()}> + {{ + BindAction = (instance, context, representationProducer, index) => + {{ + var module = representationProducer.Produce(context.OwnerId); + +{string.Join("\r\n", singleEventBinder)} + }} +}}"; + binders.Add(binder); #if !DONT_ADD context.AddSource($"{classSymbol.Name}.g.cs", SourceText.From(partialInterface, Encoding.UTF8)); #endif @@ -439,6 +453,41 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} 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(context.OwnerId == p{requestIndex}.OwnerId) return;"; + } + + var eventBinderCode = + $@" (instance as {baseType.ToDisplayString()}).{eventSymbol.Name} += ({parametersDeclaration}) => + {{ {callFilter} + var request = new DefaultCallRequest + {{ + CommandId = {index}, ObjectId = index, 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"; diff --git a/mROA/Abstract/IEventBinder.cs b/mROA/Abstract/IEventBinder.cs index 3527128..737bfd2 100644 --- a/mROA/Abstract/IEventBinder.cs +++ b/mROA/Abstract/IEventBinder.cs @@ -2,6 +2,7 @@ { public interface IEventBinder { - public void BindEvents(T source, IEndPointContext context); + public void BindEvents(T source, IEndPointContext context, + IRepresentationModuleProducer representationModuleProducer, int index); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 89bacf5..d97bdc2 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -10,38 +10,27 @@ namespace mROA.Implementation.Backend { public class ContextRepository : IContextRepository { - public static object[] EventBinders = new object[]{}; - private int _debugId = -1; + private const int StartupSize = 1024; + private const int GrowSize = 128; + public static object[] EventBinders = new object[] { }; private static int LastDebugId = -1; + private int _debugId = -1; + + private Task _lastIndexFinder = Task.FromResult(0); + + private IRepresentationModuleProducer? _representationModuleProducer; // [CanBeNull] private Dictionary _singletons; private object?[] _storage; - private Task _lastIndexFinder = Task.FromResult(0); - - private const int StartupSize = 1024; - private const int GrowSize = 128; - public ContextRepository() { _storage = new object[StartupSize]; } - 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); - } - public int ResisterObject(object o, IEndPointContext context) { if (!_lastIndexFinder.IsCompleted) @@ -49,10 +38,11 @@ namespace mROA.Implementation.Backend _storage[_lastIndexFinder.Result] = o; - EventBinders.OfType>().FirstOrDefault()?.BindEvents((T)o, context); var last = _lastIndexFinder.Result; _lastIndexFinder = Task.Run(FindLastIndex); + EventBinders.OfType>().FirstOrDefault() + ?.BindEvents((T)o, context, _representationModuleProducer!, last); return last; } @@ -68,12 +58,6 @@ namespace mROA.Implementation.Backend return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); } - public object GetObject(int id) - { - // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); - return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); - } - public T GetObject(int id) { return id == -1 || _storage.Length <= id @@ -93,6 +77,32 @@ namespace mROA.Implementation.Backend 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); + } + + public object GetObject(int id) + { + // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); + return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); + } + private int FindLastIndex() { for (var i = 0; i < _storage.Length; i++) @@ -106,9 +116,5 @@ namespace mROA.Implementation.Backend _storage = nextStorage; return _storage.Length; } - - public void Inject(T dependency) - { - } } } \ 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/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index ecda96d..b13a5d1 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -75,8 +75,10 @@ namespace mROA.Implementation.Frontend var cancelRequest = _representationModule!.GetMessageAsync( messageType: MessageType.CancelRequest, token: token); - - Task.WaitAny(defaultRequest, cancelRequest); + var eventRequest = + _representationModule!.GetMessageAsync( + messageType: MessageType.EventRequest, token: token); + Task.WaitAny(defaultRequest, cancelRequest, eventRequest); #if TRACE Console.WriteLine("Request received"); #endif @@ -89,7 +91,7 @@ namespace mROA.Implementation.Frontend tokenSource.Cancel(); _executeModule.Execute(req, _contextRepository, _representationModule); } - else + else if (defaultRequest.IsCompleted) { tokenSource.Cancel(); var request = defaultRequest.Result; @@ -97,7 +99,7 @@ namespace mROA.Implementation.Frontend var result = _executeModule.Execute(request, _contextRepository, _representationModule); var resultType = MessageType.Unknown; - + switch (result) { case FinalCommandExecution: @@ -113,6 +115,12 @@ namespace mROA.Implementation.Frontend _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); } + else + { + tokenSource.Cancel(); + var request = defaultRequest.Result; + _executeModule.Execute(request, _contextRepository, _representationModule); + } } } catch From b430f1c57268d9c7fcf084c736367447e652bcdc Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 17:16:13 +0300 Subject: [PATCH 42/66] =?UTF-8?q?=D0=98=D1=81=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=20=D0=B1=D0=B0=D0=B3=20=D1=81=20=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B9?= =?UTF-8?q?=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D0=B5=D0=B9?= =?UTF-8?q?=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D0=B1=D1=8B=D1=82=D0=B8?= =?UTF-8?q?=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Example.Backend.csproj | 2 +- Example.Backend/Printer.cs | 6 +++--- Example.Frontend/ClientBasedPrinter.cs | 4 ++-- Example.Frontend/Example.Frontend.csproj | 2 +- Example.Frontend/Program.cs | 1 + Example.Shared/IPrinter.cs | 2 +- mROA.Codegen/mROASourceGenerator.cs | 15 +++++++++------ mROA/Implementation/RepresentationModule.cs | 7 ++++++- 8 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Example.Backend/Example.Backend.csproj b/Example.Backend/Example.Backend.csproj index 06f0ed2..95845de 100644 --- a/Example.Backend/Example.Backend.csproj +++ b/Example.Backend/Example.Backend.csproj @@ -15,7 +15,7 @@ - + TRACE; diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index c001071..65125f4 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,7 +10,7 @@ namespace Example.Backend { public string Name; - public void OnPrintExternal(IPage p0, RequestContext p1) + public void OnPrintExternal(IPage p0) { } @@ -27,12 +27,12 @@ namespace Example.Backend // 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); + OnPrint?.Invoke(page); Resource /= 1.5; return page; } - public event Action? OnPrint; + public event Action? OnPrint; public void Dispose() { diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index ed45914..e749687 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,7 +8,7 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { - public void OnPrintExternal(IPage p0, RequestContext p1) + public void OnPrintExternal(IPage p0) { } @@ -29,7 +29,7 @@ namespace Example.Frontend return new ClientBasedPage(); } - public event Action? OnPrint; + public event Action? OnPrint; public void Dispose() { diff --git a/Example.Frontend/Example.Frontend.csproj b/Example.Frontend/Example.Frontend.csproj index 8ad6b28..fdac1b1 100644 --- a/Example.Frontend/Example.Frontend.csproj +++ b/Example.Frontend/Example.Frontend.csproj @@ -10,7 +10,7 @@ - + TRACE; diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 07bd283..077c228 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -48,6 +48,7 @@ class Program //правильный порядок команд 8-5-10-7 using (var disposingPrinter = factory.Create("Test")) { + disposingPrinter.OnPrint += page1 => { Console.WriteLine("New page creater. Called from event!!!"); }; Console.WriteLine("Printer created"); Thread.Sleep(100); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index f5b25f0..3b320fd 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -12,6 +12,6 @@ namespace Example.Shared double Resource { get; set; } string GetName(); Task Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken); - event Action OnPrint; + event Action OnPrint; } } \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index cc8d06b..4a32063 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -463,7 +463,8 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} JoinWithComa(Enumerable.Range(0, parameters.Count).Select(i => "p" + i++))); var transferParameters = - JoinWithComa(parameters.Where(i => ParameterFilterForType(i)).Select(i => "p" + parameters.IndexOf(i))); + JoinWithComa(parameters.Where(i => !ParameterFilterForType(i)) + .Select(i => "p" + parameters.IndexOf(i))); var callFilter = ""; @@ -475,11 +476,13 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} var eventBinderCode = $@" (instance as {baseType.ToDisplayString()}).{eventSymbol.Name} += ({parametersDeclaration}) => - {{ {callFilter} - var request = new DefaultCallRequest - {{ - CommandId = {index}, ObjectId = index, Parameters = new object[] {{ {transferParameters} }} - }}; + {{ + Console.WriteLine(""Sending event...""); +{callFilter} + var request = new DefaultCallRequest + {{ + CommandId = {index}, ObjectId = index, Parameters = new object[] {{ {transferParameters} }} + }}; module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); }}; "; diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 73e2275..c04f160 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -7,8 +7,8 @@ namespace mROA.Implementation { public class RepresentationModule : IRepresentationModule { - private ISerializationToolkit? _serialization; private INextGenerationInteractionModule? _interaction; + private ISerializationToolkit? _serialization; public void Inject(T dependency) { @@ -70,6 +70,11 @@ namespace mROA.Implementation } } + if (fromBuffer == null) + { + return Array.Empty(); + } + _interaction.HandleMessage(fromBuffer); return fromBuffer.Data; } From c33d282a5c8efc15ed1007c240e2d7780cf68b7e Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 17:35:16 +0300 Subject: [PATCH 43/66] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=BA=D1=82=D0=B8?= =?UTF-8?q?=D1=87=D0=B5=D1=81=D0=BA=D0=B8=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Frontend/RequestExtractor.cs | 8 +++---- .../NextGenerationInteractionModule.cs | 22 +++++++++---------- mROA/Implementation/RepresentationModule.cs | 2 +- mROA/mROA.csproj | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index b13a5d1..d8c9e10 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -65,7 +65,7 @@ namespace mROA.Implementation.Frontend while (true) { #if TRACE - Console.WriteLine("Waiting for request..."); + Console.WriteLine("Waiting for request..."); #endif var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; @@ -80,12 +80,12 @@ namespace mROA.Implementation.Frontend messageType: MessageType.EventRequest, token: token); Task.WaitAny(defaultRequest, cancelRequest, eventRequest); #if TRACE - Console.WriteLine("Request received"); + Console.WriteLine("Request received"); #endif if (cancelRequest.IsCompleted) { #if TRACE - Console.WriteLine("Cancelling request"); + Console.WriteLine("Cancelling request"); #endif var req = cancelRequest.Result; tokenSource.Cancel(); @@ -118,7 +118,7 @@ namespace mROA.Implementation.Frontend else { tokenSource.Cancel(); - var request = defaultRequest.Result; + var request = eventRequest.Result; _executeModule.Execute(request, _contextRepository, _representationModule); } } diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 68239ea..5defb89 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -9,13 +9,13 @@ namespace mROA.Implementation { public class NextGenerationInteractionModule : INextGenerationInteractionModule { + 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; private set; } public Stream? BaseStream { get; set; } - private Task? _currentReceiving; - private const int BufferSize = ushort.MaxValue; - private readonly Memory _buffer = new byte[BufferSize]; - private readonly List _messageBuffer = new (128); public void Inject(T dependency) @@ -36,7 +36,6 @@ namespace mROA.Implementation if (_currentReceiving != null) return _currentReceiving; _currentReceiving = Task.Run(async () => await GetNextMessage()); return _currentReceiving; - } public async Task PostMessage(NetworkMessage message) @@ -46,7 +45,7 @@ namespace mROA.Implementation if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); - + // Console.WriteLine("Sending {0}", JsonSerializer.Serialize(message)); @@ -62,6 +61,7 @@ namespace mROA.Implementation } public NetworkMessage[] UnhandledMessages => _messageBuffer.ToArray(); + public NetworkMessage? FirstByFilter(Predicate predicate) { return _messageBuffer.FirstOrDefault(m => predicate(m)); @@ -79,23 +79,23 @@ namespace mROA.Implementation // Console.WriteLine("Receiving message"); var firstBit = (byte)BaseStream.ReadByte(); var secondBit = (byte)BaseStream.ReadByte(); - - var len = BitConverter.ToUInt16(new[] { firstBit, secondBit}); + + var len = BitConverter.ToUInt16(new[] { firstBit, secondBit }); var localSpan = _buffer.Slice(0, len); - + await BaseStream.ReadExactlyAsync(localSpan); // Console.WriteLine("Receiving {0}", Encoding.Default.GetString(_buffer[..len])); var message = _serialization.Deserialize(localSpan.Span); #if TRACE - Console.WriteLine($"Received Message {message.SchemaId} - {message.Id}"); + Console.WriteLine($"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; } } diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index c04f160..58f2ce5 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -91,7 +91,7 @@ namespace mROA.Implementation if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); #if TRACE - Console.WriteLine($"Posting message: {id} - {messageType}"); + Console.WriteLine($"Posting message: {id} - {messageType} to {Id}"); #endif var serialized = _serialization.Serialize(payload, payloadType); diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index e9d980c..8723457 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - + TRACE; From 81a9698de4e9de0733b80331ab8d3132abcb54b5 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 18:26:57 +0300 Subject: [PATCH 44/66] =?UTF-8?q?=D0=98=D0=B4=D0=B5=D0=BD=D1=82=D0=B8?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BE=D0=B1=D1=8A?= =?UTF-8?q?=D0=B5=D0=BA=D1=82=D0=BE=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=20=D0=BF=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D0=B0=D0=BD=D0=B0=20=D0=BD=D0=B0=20UniversalObject?= =?UTF-8?q?Identifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Implementation/Backend/BasicExecutionModule.cs | 8 +++++--- mROA/Implementation/CallRequest.cs | 6 +++--- mROA/mROA.csproj | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index aa5b3ba..28158f9 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -66,8 +66,10 @@ namespace mROA.Implementation.Backend if (invoker == null) throw new Exception($"Command {command.CommandId} not found"); - var context = command.ObjectId != -1 - ? contextRepository.GetObject(command.ObjectId) + IContextRepository repository; + + var context = command.ObjectId.ContextId != -1 + ? contextRepository.GetObject(command.ObjectId.ContextId) : contextRepository.GetSingleObject(invoker.SuitableType); if (context == null) @@ -102,7 +104,7 @@ namespace mROA.Implementation.Backend #if TRACE Console.WriteLine("Disposing object"); #endif - contextRepository.ClearObject(command.ObjectId); + contextRepository.ClearObject(command.ObjectId.ContextId); } return result; diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 0549069..86d234f 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation { Guid Id { get; } int CommandId { get; } - int ObjectId { get; } + UniversalObjectIdentifier ObjectId { get; } object?[]? Parameters { get; } } @@ -17,7 +17,7 @@ namespace mROA.Implementation { public Guid Id { get; set; } = Guid.NewGuid(); public int CommandId { get; set; } - public int ObjectId { get; set; } = -1; + public UniversalObjectIdentifier ObjectId { get; set; } = UniversalObjectIdentifier.Null; public object?[]? Parameters { get; set; } @@ -31,7 +31,7 @@ namespace mROA.Implementation { public Guid Id { get; set; } public int CommandId { get; set; } = -2; - public int ObjectId { get; set; } = -2; + public UniversalObjectIdentifier ObjectId { get; set; } = UniversalObjectIdentifier.Null; public object?[]? Parameters { get; set; } = null; public override string ToString() diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index 8723457..e62894c 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -21,7 +21,7 @@ - TRACE; + From 96aa8288080cec2072a70ca9c945a27cb8515343 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 20:04:00 +0300 Subject: [PATCH 45/66] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20=D0=BD=D0=B0=20UOI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Codegen/mROASourceGenerator.cs | 2 +- mROA/Implementation/RemoteObjectBase.cs | 4 ++-- mROA/Implementation/UniversalObjectIdentifier.cs | 6 ++++++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 4a32063..1fd6df4 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -481,7 +481,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} {callFilter} var request = new DefaultCallRequest {{ - CommandId = {index}, ObjectId = index, Parameters = new object[] {{ {transferParameters} }} + CommandId = {index}, ObjectId = new UniversalObjectIdentifier(index, context.OwnerId), Parameters = new object[] {{ {transferParameters} }} }}; module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); }}; diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index e756d5a..b180099 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -26,7 +26,7 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters + { CommandId = methodId, ObjectId = _identifier, Parameters = parameters }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); @@ -80,7 +80,7 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters + { CommandId = methodId, ObjectId = _identifier, Parameters = parameters }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/UniversalObjectIdentifier.cs index 781567e..cd78859 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/UniversalObjectIdentifier.cs @@ -8,6 +8,12 @@ namespace mROA.Implementation public int ContextId; public int OwnerId; + public UniversalObjectIdentifier(int contextId, int ownerId) + { + ContextId = contextId; + OwnerId = ownerId; + } + public static UniversalObjectIdentifier Null = new UniversalObjectIdentifier { ContextId = -2, OwnerId = -1 }; public static UniversalObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat }; From 5e21d941df38b2e321401b994c211a5544a1cb43 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 21:56:22 +0300 Subject: [PATCH 46/66] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B8=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20UOI=20=D0=B2?= =?UTF-8?q?=20=20COI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Cbor/CborSerializationToolkit.cs | 90 +++++++++---------- mROA.Cbor/PreParsedValue.cs | 18 ++-- mROA.Test/UnSOization.cs | 10 +-- mROA/Abstract/IContextRepository.cs | 2 +- .../Backend/ContextRepository.cs | 2 +- .../Backend/MultiClientContextRepository.cs | 35 ++++---- mROA/Implementation/CallRequest.cs | 6 +- ...entifier.cs => ComplexObjectIdentifier.cs} | 12 +-- .../Implementation/RemoteContextRepository.cs | 20 +++-- mROA/Implementation/RemoteObjectBase.cs | 35 ++++---- mROA/Implementation/SharedObjectShell.cs | 8 +- 11 files changed, 123 insertions(+), 115 deletions(-) rename mROA/Implementation/{UniversalObjectIdentifier.cs => ComplexObjectIdentifier.cs} (66%) diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 12016df..341b49d 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -65,6 +65,50 @@ namespace mROA.Cbor 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) @@ -322,7 +366,7 @@ namespace mROA.Cbor var identifier = reader.ReadUInt64(); reader.ReadEndArray(); - so.Identifier = UniversalObjectIdentifier.FromFlat(identifier); + so.Identifier = ComplexObjectIdentifier.FromFlat(identifier); return so.UniversalValue; } @@ -387,49 +431,5 @@ namespace mROA.Cbor return finalProperties; } - - 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); - } } } \ No newline at end of file diff --git a/mROA.Cbor/PreParsedValue.cs b/mROA.Cbor/PreParsedValue.cs index 8140f47..9737b7e 100644 --- a/mROA.Cbor/PreParsedValue.cs +++ b/mROA.Cbor/PreParsedValue.cs @@ -12,16 +12,15 @@ namespace mROA.Cbor public class PreParsedValue : IPreParsedValue { - private List _properties { get; set; } - public PreParsedValue(List properties) { _properties = properties; } + private List _properties { get; set; } + public object? ToObject(Type type, IEndPointContext? context) { - if (type.IsInterface) { var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type); @@ -31,10 +30,10 @@ namespace mROA.Cbor if (context != null) so.EndPointContext = context; - so.Identifier = UniversalObjectIdentifier.FromFlat((ulong)_properties[0]); + so.Identifier = ComplexObjectIdentifier.FromFlat((ulong)_properties[0]); return so.UniversalValue; } - + var instance = Activator.CreateInstance(type); if (instance == null) return null; @@ -48,7 +47,10 @@ namespace mROA.Cbor for (var index = 0; index < properties.Count; index++) { var property = properties[index]; - property.SetValue(instance, _properties[index] is IPreParsedValue ppv ? ppv.ToObject(property.PropertyType, context) : _properties[index]); + property.SetValue(instance, + _properties[index] is IPreParsedValue ppv + ? ppv.ToObject(property.PropertyType, context) + : _properties[index]); } return instance; @@ -57,13 +59,13 @@ namespace mROA.Cbor public class ParsedValue : IPreParsedValue { + private object? _value; + public ParsedValue(object? value) { _value = value; } - private object? _value; - public object? ToObject(Type type, IEndPointContext? context) { diff --git a/mROA.Test/UnSOization.cs b/mROA.Test/UnSOization.cs index afdcb9e..d30c025 100644 --- a/mROA.Test/UnSOization.cs +++ b/mROA.Test/UnSOization.cs @@ -4,12 +4,12 @@ namespace mROA.Test; public class UnSOization { - private UniversalObjectIdentifier _uoi; - + private ComplexObjectIdentifier _uoi; + [SetUp] public void Setup() { - _uoi = new UniversalObjectIdentifier + _uoi = new ComplexObjectIdentifier { ContextId = -123, OwnerId = 123 }; @@ -19,8 +19,8 @@ public class UnSOization public void FlatTest() { var flat = _uoi.Flat; - var next = new UniversalObjectIdentifier { Flat = flat }; - + var next = new ComplexObjectIdentifier { Flat = flat }; + Assert.That(_uoi, Is.EqualTo(next)); } } \ No newline at end of file diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 0acbb60..75668c9 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -7,7 +7,7 @@ namespace mROA.Abstract { int ResisterObject(object o, IEndPointContext context); void ClearObject(int id); - T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell); + T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell); T? GetObject(int id); object GetSingleObject(Type type); int GetObjectIndex(object o, IEndPointContext context); diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index d97bdc2..d00fd4c 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -53,7 +53,7 @@ namespace mROA.Implementation.Backend _lastIndexFinder = Task.FromResult(id); } - public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) + public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) { return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 4b4194d..5a5ac0e 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -6,23 +6,14 @@ namespace mROA.Implementation.Backend { public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub { - private Dictionary _repositories = new(); private readonly Func _produceRepository; + private Dictionary _repositories = new(); public MultiClientContextRepository(Func produceRepository) { _produceRepository = produceRepository; } - private IContextRepository GetRepositoryByClientId(int clientId) - { - if (_repositories.TryGetValue(clientId, out var repository)) - return repository; - - var created = _produceRepository(clientId); - _repositories.Add(clientId, created); - return created; - } public void Inject(T dependency) { } @@ -39,18 +30,12 @@ namespace mROA.Implementation.Backend repository.ClearObject(id); } - public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) + public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) { var repository = GetRepository(sharedObjectShellShell.Identifier.OwnerId); return repository.GetObject(sharedObjectShellShell.Identifier.ContextId); } - public object GetObject(int id) - { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetObject(id); - } - public T? GetObject(int id) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); @@ -74,5 +59,21 @@ namespace mROA.Implementation.Backend var repository = GetRepositoryByClientId(clientId); return repository; } + + private IContextRepository GetRepositoryByClientId(int clientId) + { + if (_repositories.TryGetValue(clientId, out var repository)) + return repository; + + var created = _produceRepository(clientId); + _repositories.Add(clientId, created); + return created; + } + + public object GetObject(int id) + { + var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + return repository.GetObject(id); + } } } \ No newline at end of file diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs index 86d234f..6a909b0 100644 --- a/mROA/Implementation/CallRequest.cs +++ b/mROA/Implementation/CallRequest.cs @@ -9,7 +9,7 @@ namespace mROA.Implementation { Guid Id { get; } int CommandId { get; } - UniversalObjectIdentifier ObjectId { get; } + ComplexObjectIdentifier ObjectId { get; } object?[]? Parameters { get; } } @@ -17,7 +17,7 @@ namespace mROA.Implementation { public Guid Id { get; set; } = Guid.NewGuid(); public int CommandId { get; set; } - public UniversalObjectIdentifier ObjectId { get; set; } = UniversalObjectIdentifier.Null; + public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null; public object?[]? Parameters { get; set; } @@ -31,7 +31,7 @@ namespace mROA.Implementation { public Guid Id { get; set; } public int CommandId { get; set; } = -2; - public UniversalObjectIdentifier ObjectId { get; set; } = UniversalObjectIdentifier.Null; + public ComplexObjectIdentifier ObjectId { get; set; } = ComplexObjectIdentifier.Null; public object?[]? Parameters { get; set; } = null; public override string ToString() diff --git a/mROA/Implementation/UniversalObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs similarity index 66% rename from mROA/Implementation/UniversalObjectIdentifier.cs rename to mROA/Implementation/ComplexObjectIdentifier.cs index cd78859..a1004d3 100644 --- a/mROA/Implementation/UniversalObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -3,19 +3,19 @@ using System; namespace mROA.Implementation { #pragma warning disable CS8618, CS9264 - public struct UniversalObjectIdentifier : IEquatable + public struct ComplexObjectIdentifier : IEquatable { public int ContextId; public int OwnerId; - public UniversalObjectIdentifier(int contextId, int ownerId) + public ComplexObjectIdentifier(int contextId, int ownerId) { ContextId = contextId; OwnerId = ownerId; } - public static UniversalObjectIdentifier Null = new UniversalObjectIdentifier { ContextId = -2, OwnerId = -1 }; - public static UniversalObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat }; + public static ComplexObjectIdentifier Null = new ComplexObjectIdentifier { ContextId = -2, OwnerId = -1 }; + public static ComplexObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat }; public override string ToString() { @@ -34,14 +34,14 @@ namespace mROA.Implementation } } - public bool Equals(UniversalObjectIdentifier other) + public bool Equals(ComplexObjectIdentifier other) { return ContextId == other.ContextId && OwnerId == other.OwnerId; } public override bool Equals(object? obj) { - return obj is UniversalObjectIdentifier other && Equals(other); + return obj is ComplexObjectIdentifier other && Equals(other); } public override int GetHashCode() diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index e86e74f..9f34c1d 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -6,8 +6,8 @@ namespace mROA.Implementation { public class RemoteContextRepository : IContextRepository { - private IRepresentationModuleProducer? _representationProducer; public static Dictionary RemoteTypes = new(); + private IRepresentationModuleProducer? _representationProducer; public int ResisterObject(object o, IEndPointContext context) { @@ -19,7 +19,7 @@ namespace mROA.Implementation throw new NotSupportedException(); } - public T GetObjectBySharedObject(SharedObjectShellShell sharedObjectShellShell) + public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); @@ -31,18 +31,14 @@ namespace mROA.Implementation return remote; } - 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 representationModule = _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + var representationModule = + _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var remote = (T)Activator.CreateInstance(remoteType, id, representationModule)!; return remote; @@ -53,7 +49,8 @@ namespace mROA.Implementation if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); - var representationModule = _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); + var representationModule = + _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); return Activator.CreateInstance(RemoteTypes[type], -1, representationModule)!; } @@ -73,5 +70,10 @@ namespace mROA.Implementation if (dependency is IRepresentationModuleProducer serialisationModule) _representationProducer = serialisationModule; } + + public object GetObject(int id) + { + throw new NotSupportedException(); + } } } \ No newline at end of file diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index b180099..3ee8774 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -10,25 +10,34 @@ namespace mROA.Implementation { public abstract class RemoteObjectBase : IDisposable { - private readonly UniversalObjectIdentifier _identifier; + private readonly ComplexObjectIdentifier _identifier; private readonly IRepresentationModule _representationModule; protected RemoteObjectBase(int id, IRepresentationModule representationModule) { - _identifier = new UniversalObjectIdentifier { ContextId = id, OwnerId = representationModule.Id }; + _identifier = new ComplexObjectIdentifier { ContextId = id, OwnerId = representationModule.Id }; _representationModule = representationModule; } public int Id => _identifier.ContextId; public int OwnerId => _identifier.OwnerId; - public UniversalObjectIdentifier Identifier => _identifier; + public ComplexObjectIdentifier Identifier => _identifier; + + 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 - }; - + { + CommandId = methodId, ObjectId = _identifier, Parameters = parameters + }; + await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); var localTokenSource = new CancellationTokenSource(); @@ -53,7 +62,7 @@ namespace mROA.Implementation }); localTokenSource.Cancel(); }); - + Task.WaitAny(new Task[] { successResponse, errorResponse @@ -80,8 +89,9 @@ namespace mROA.Implementation CancellationToken cancellationToken = default) { var request = new DefaultCallRequest - { CommandId = methodId, ObjectId = _identifier, Parameters = parameters - }; + { + CommandId = methodId, ObjectId = _identifier, Parameters = parameters + }; await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); var localTokenSource = new CancellationTokenSource(); @@ -122,13 +132,6 @@ namespace mROA.Implementation throw errorResponse.Result.GetException(); } - public void Dispose() - { - if (_identifier.IsStatic) - return; - CallAsync(-1).Wait(); - } - public override string ToString() { return _identifier.ToString(); diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 3fba873..6073d66 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -11,13 +11,13 @@ namespace mROA.Implementation public interface ISharedObjectShell { IEndPointContext EndPointContext { get; set; } - UniversalObjectIdentifier Identifier { get; set; } + ComplexObjectIdentifier Identifier { get; set; } object UniversalValue { get; set; } } public class SharedObjectShellShell : ISharedObjectShell where T : notnull { - private UniversalObjectIdentifier _identifier = UniversalObjectIdentifier.Null; + private ComplexObjectIdentifier _identifier = ComplexObjectIdentifier.Null; private T _value; @@ -64,7 +64,7 @@ namespace mROA.Implementation OwnerFunc = TransmissionConfig.OwnershipRepository.GetOwnershipId }; - public UniversalObjectIdentifier Identifier + public ComplexObjectIdentifier Identifier { get { @@ -74,7 +74,7 @@ namespace mROA.Implementation set { _identifier = value; - Value = GetDefaultContextRepository().GetObjectBySharedObject(this); + Value = GetDefaultContextRepository().GetObjectByShell(this); } } From d6423136d21aee762bcc5499867f9803e0d5acbd Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 23:28:41 +0300 Subject: [PATCH 47/66] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D0=BE=D0=B2=D0=B0=D0=BD=D0=BE=20=D1=83=D0=BD=D0=B8=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D1=81=D0=B0=D0=BB=D1=8C=D0=BD=D0=BE=D0=B5=20=D1=85=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=BB=D0=B8=D1=89=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA.Codegen/mROASourceGenerator.cs | 2 +- mROA/Abstract/IContextRepository.cs | 5 +- mROA/Abstract/IStorage.cs | 10 ++++ .../Backend/BasicExecutionModule.cs | 4 +- .../Backend/ContextRepository.cs | 14 +++-- .../Backend/MultiClientContextRepository.cs | 14 ++--- mROA/Implementation/ComplexRepository.cs | 44 +++++++++++++++ mROA/Implementation/ExtensibleStorage.cs | 55 +++++++++++++++++++ .../Implementation/RemoteContextRepository.cs | 6 +- 9 files changed, 132 insertions(+), 22 deletions(-) create mode 100644 mROA/Abstract/IStorage.cs create mode 100644 mROA/Implementation/ComplexRepository.cs create mode 100644 mROA/Implementation/ExtensibleStorage.cs diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 1fd6df4..ed5abd2 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -481,7 +481,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} {callFilter} var request = new DefaultCallRequest {{ - CommandId = {index}, ObjectId = new UniversalObjectIdentifier(index, context.OwnerId), Parameters = new object[] {{ {transferParameters} }} + CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, context.OwnerId), Parameters = new object[] {{ {transferParameters} }} }}; module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); }}; diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 75668c9..9f064e1 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -5,10 +5,11 @@ namespace mROA.Abstract { public interface IContextRepository : IInjectableModule { + int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); - void ClearObject(int id); + void ClearObject(ComplexObjectIdentifier id); T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell); - T? GetObject(int id); + T? GetObject(ComplexObjectIdentifier id); object GetSingleObject(Type type); int GetObjectIndex(object o, IEndPointContext context); } diff --git a/mROA/Abstract/IStorage.cs b/mROA/Abstract/IStorage.cs new file mode 100644 index 0000000..1ba6de3 --- /dev/null +++ b/mROA/Abstract/IStorage.cs @@ -0,0 +1,10 @@ +namespace mROA.Abstract +{ + public interface IStorage + { + 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/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 28158f9..d5ec4ab 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -69,7 +69,7 @@ namespace mROA.Implementation.Backend IContextRepository repository; var context = command.ObjectId.ContextId != -1 - ? contextRepository.GetObject(command.ObjectId.ContextId) + ? contextRepository.GetObject(command.ObjectId) : contextRepository.GetSingleObject(invoker.SuitableType); if (context == null) @@ -104,7 +104,7 @@ namespace mROA.Implementation.Backend #if TRACE Console.WriteLine("Disposing object"); #endif - contextRepository.ClearObject(command.ObjectId.ContextId); + contextRepository.ClearObject(command.ObjectId); } return result; diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index d00fd4c..fe1a780 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -31,6 +31,8 @@ namespace mROA.Implementation.Backend _storage = new object[StartupSize]; } + public int HostId { get; set; } + public int ResisterObject(object o, IEndPointContext context) { if (!_lastIndexFinder.IsCompleted) @@ -47,10 +49,10 @@ namespace mROA.Implementation.Backend return last; } - public void ClearObject(int id) + public void ClearObject(ComplexObjectIdentifier id) { - _storage[id] = null; - _lastIndexFinder = Task.FromResult(id); + _storage[id.ContextId] = null; + _lastIndexFinder = Task.FromResult(id.ContextId); } public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) @@ -58,11 +60,11 @@ namespace mROA.Implementation.Backend return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); } - public T GetObject(int id) + public T? GetObject(ComplexObjectIdentifier id) { - return id == -1 || _storage.Length <= id + return id.ContextId == -1 || _storage.Length <= id.ContextId ? throw new NullReferenceException("Cannot find that object. It is null") - : (T)_storage[id]!; + : (T)_storage[id.ContextId]!; } public object GetSingleObject(Type type) diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 5a5ac0e..1647dbc 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -18,13 +18,15 @@ namespace mROA.Implementation.Backend { } + 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(int id) + public void ClearObject(ComplexObjectIdentifier id) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); repository.ClearObject(id); @@ -33,10 +35,10 @@ namespace mROA.Implementation.Backend public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) { var repository = GetRepository(sharedObjectShellShell.Identifier.OwnerId); - return repository.GetObject(sharedObjectShellShell.Identifier.ContextId); + return repository.GetObject(sharedObjectShellShell.Identifier)!; } - public T? GetObject(int id) + public T? GetObject(ComplexObjectIdentifier id) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); return repository.GetObject(id); @@ -69,11 +71,5 @@ namespace mROA.Implementation.Backend _repositories.Add(clientId, created); return created; } - - public object GetObject(int id) - { - var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetObject(id); - } } } \ No newline at end of file diff --git a/mROA/Implementation/ComplexRepository.cs b/mROA/Implementation/ComplexRepository.cs new file mode 100644 index 0000000..756969c --- /dev/null +++ b/mROA/Implementation/ComplexRepository.cs @@ -0,0 +1,44 @@ +using System; +using mROA.Abstract; + +namespace mROA.Implementation +{ + public class ComplexRepository : IContextRepository + { + public void Inject(T dependency) + { + throw new NotImplementedException(); + } + + public int HostId { get; set; } + public int ResisterObject(object o, IEndPointContext context) + { + throw new NotImplementedException(); + } + + public void ClearObject(ComplexObjectIdentifier id) + { + throw new NotImplementedException(); + } + + public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) + { + throw new NotImplementedException(); + } + + public T? GetObject(ComplexObjectIdentifier id) + { + throw new NotImplementedException(); + } + + public object GetSingleObject(Type type) + { + throw new NotImplementedException(); + } + + public int GetObjectIndex(object o, IEndPointContext context) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/ExtensibleStorage.cs b/mROA/Implementation/ExtensibleStorage.cs new file mode 100644 index 0000000..02d12a4 --- /dev/null +++ b/mROA/Implementation/ExtensibleStorage.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using mROA.Abstract; + +namespace mROA.Implementation +{ + public class ExtensibleStorage : IStorage + { + 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) + { + 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; + + _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/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 9f34c1d..71097ed 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -9,12 +9,14 @@ namespace mROA.Implementation public static Dictionary RemoteTypes = new(); private IRepresentationModuleProducer? _representationProducer; + public int HostId { get; set; } + public int ResisterObject(object o, IEndPointContext context) { throw new NotSupportedException(); } - public void ClearObject(int id) + public void ClearObject(ComplexObjectIdentifier id) { throw new NotSupportedException(); } @@ -31,7 +33,7 @@ namespace mROA.Implementation return remote; } - public T GetObject(int id) + public T? GetObject(ComplexObjectIdentifier id) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); From 22016f1c81fba1512e87be5de182a7b15fea84b5 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Mon, 10 Mar 2025 23:53:36 +0300 Subject: [PATCH 48/66] =?UTF-8?q?=D0=A3=D0=BF=D1=80=D0=BE=D1=89=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=B8=D0=BD=D1=82=D0=B5=D1=80=D1=84=D0=B5=D0=B9=D1=81?= =?UTF-8?q?=20=D1=80=D0=B5=D0=BF=D0=BE=D0=B7=D0=B8=D1=82=D0=BE=D1=80=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B5=D0=BA=D1=81=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/IContextRepository.cs | 3 +-- .../Backend/MultiClientContextRepository.cs | 12 +++--------- mROA/Implementation/ComplexObjectIdentifier.cs | 1 + mROA/Implementation/ComplexRepository.cs | 7 +------ mROA/Implementation/RemoteContextRepository.cs | 16 ++-------------- mROA/Implementation/RemoteObjectBase.cs | 18 ++++++++++++++++++ mROA/Implementation/SharedObjectShell.cs | 4 +++- 7 files changed, 29 insertions(+), 32 deletions(-) diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 9f064e1..7a3366e 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -8,8 +8,7 @@ namespace mROA.Abstract int HostId { get; set; } int ResisterObject(object o, IEndPointContext context); void ClearObject(ComplexObjectIdentifier id); - T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell); - T? GetObject(ComplexObjectIdentifier id); + T GetObject(ComplexObjectIdentifier id); object GetSingleObject(Type type); int GetObjectIndex(object o, IEndPointContext context); } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 1647dbc..94af7d0 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -7,7 +7,7 @@ namespace mROA.Implementation.Backend public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub { private readonly Func _produceRepository; - private Dictionary _repositories = new(); + private readonly Dictionary _repositories = new(); public MultiClientContextRepository(Func produceRepository) { @@ -31,14 +31,8 @@ namespace mROA.Implementation.Backend var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); repository.ClearObject(id); } - - public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) - { - var repository = GetRepository(sharedObjectShellShell.Identifier.OwnerId); - return repository.GetObject(sharedObjectShellShell.Identifier)!; - } - - public T? GetObject(ComplexObjectIdentifier id) + + public T GetObject(ComplexObjectIdentifier id) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); return repository.GetObject(id); diff --git a/mROA/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs index a1004d3..35652ee 100644 --- a/mROA/Implementation/ComplexObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -12,6 +12,7 @@ namespace mROA.Implementation { ContextId = contextId; OwnerId = ownerId; + } public static ComplexObjectIdentifier Null = new ComplexObjectIdentifier { ContextId = -2, OwnerId = -1 }; diff --git a/mROA/Implementation/ComplexRepository.cs b/mROA/Implementation/ComplexRepository.cs index 756969c..a46ae58 100644 --- a/mROA/Implementation/ComplexRepository.cs +++ b/mROA/Implementation/ComplexRepository.cs @@ -21,12 +21,7 @@ namespace mROA.Implementation throw new NotImplementedException(); } - public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) - { - throw new NotImplementedException(); - } - - public T? GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id) { throw new NotImplementedException(); } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 71097ed..e31ff0a 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -21,19 +21,7 @@ namespace mROA.Implementation throw new NotSupportedException(); } - public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) - { - 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(sharedObjectShellShell.Identifier.OwnerId); - var remote = (T)Activator.CreateInstance(remoteType, sharedObjectShellShell.Identifier.ContextId, - representationModule)!; - return remote; - } - - public T? GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id) { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); @@ -41,7 +29,7 @@ namespace mROA.Implementation 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, + var remote = (T)Activator.CreateInstance(remoteType, id.ContextId, representationModule)!; return remote; } diff --git a/mROA/Implementation/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 3ee8774..225a010 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -10,6 +10,24 @@ namespace mROA.Implementation { public abstract class RemoteObjectBase : IDisposable { + protected bool Equals(RemoteObjectBase other) + { + return _identifier.Equals(other._identifier); + } + + 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); + } + + public override int GetHashCode() + { + return HashCode.Combine(_identifier.GetHashCode(), _identifier.ContextId); + } + private readonly ComplexObjectIdentifier _identifier; private readonly IRepresentationModule _representationModule; diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 6073d66..6abd096 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -28,6 +28,7 @@ namespace mROA.Implementation } // ReSharper disable once UnusedMember.Global + // ReSharper disable once MemberCanBePrivate.Global public SharedObjectShellShell(T value) { Value = value; @@ -35,6 +36,7 @@ namespace mROA.Implementation [JsonIgnore] [SerializationIgnore] + // ReSharper disable once MemberCanBePrivate.Global public T Value { get => _value; @@ -74,7 +76,7 @@ namespace mROA.Implementation set { _identifier = value; - Value = GetDefaultContextRepository().GetObjectByShell(this); + Value = GetDefaultContextRepository().GetObject(Identifier); } } From 8beca7f8d71ab6354e2cdc28de7e16576d8b5977 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 11 Mar 2025 14:43:16 +0300 Subject: [PATCH 49/66] =?UTF-8?q?=D0=9E=D1=87=D0=B8=D1=81=D1=82=D0=BA?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=82=20=D1=83=D1=81=D1=82=D0=B0=D1=80=D0=B5?= =?UTF-8?q?=D0=B2=D1=88=D0=B5=D0=B3=D0=BE=20=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/ISerialisationModule.cs | 28 ++++++---------- .../Backend/BasicExecutionModule.cs | 32 ++++++++++--------- .../Backend/ContextRepository.cs | 15 ++------- .../Backend/NetworkGatewayModule.cs | 32 +++++++++++-------- mROA/Implementation/EndPointContext.cs | 1 + .../Frontend/RequestExtractor.cs | 19 ++++------- .../NextGenerationInteractionModule.cs | 2 +- .../Implementation/RemoteContextRepository.cs | 5 --- mROA/Implementation/SharedObjectShell.cs | 1 + 9 files changed, 56 insertions(+), 79 deletions(-) diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/ISerialisationModule.cs index a297fd8..17e7911 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/ISerialisationModule.cs @@ -2,34 +2,24 @@ using System; using System.Threading; using System.Threading.Tasks; using mROA.Implementation; -using mROA.Implementation.CommandExecution; namespace mROA.Abstract { - public interface ISerialisationModule : IInjectableModule - { - void HandleIncomingRequest(int clientId, byte[] message); - void PostResponse(NetworkMessage message, int clientId); - void SendWelcomeMessage(int clientId); - public interface IFrontendSerialisationModule : IInjectableModule - { - int ClientId { get; } - Task GetNextCommandExecution(Guid requestId) where T : ICommandExecution; - Task> GetFinalCommandExecution(Guid requestId); - void PostCallRequest(ICallRequest callRequest); - } - } - public interface IRepresentationModule : IInjectableModule { int Id { get; } - Task GetMessageAsync(Guid? requestId = null, MessageType? messageType = null, CancellationToken token = default); + + 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 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); + void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType); } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index d5ec4ab..0924999 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -81,7 +81,7 @@ namespace mROA.Implementation.Backend if (invoker.ParameterTypes.Length != 0) { castedParams = new object[invoker.ParameterTypes.Length]; - for (int i = 0; i < castedParams.Length; i++) + for (var i = 0; i < castedParams.Length; i++) { castedParams[i] = _serialization.Cast(command.Parameters![i], invoker.ParameterTypes[i]); } @@ -89,25 +89,27 @@ namespace mROA.Implementation.Backend var execContext = new RequestContext(command.Id, representationModule.Id); - if (invoker is AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker) - return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command, - _cancellationRepo, - representationModule, execContext); - - if (invoker is AsyncMethodInvoker asyncMethodInvoker) - return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo, - representationModule, execContext); - - var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); - if (command.CommandId == -1) + 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); - } + contextRepository.ClearObject(command.ObjectId); + } - return result; + return result; + } } catch (Exception e) { diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index fe1a780..55b8169 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -12,7 +12,7 @@ namespace mROA.Implementation.Backend { private const int StartupSize = 1024; private const int GrowSize = 128; - public static object[] EventBinders = new object[] { }; + public static object[] EventBinders = { }; private static int LastDebugId = -1; private int _debugId = -1; @@ -55,12 +55,7 @@ namespace mROA.Implementation.Backend _lastIndexFinder = Task.FromResult(id.ContextId); } - public T GetObjectByShell(SharedObjectShellShell sharedObjectShellShell) - { - return (T)GetObject(sharedObjectShellShell.Identifier.ContextId); - } - - public T? GetObject(ComplexObjectIdentifier id) + public T GetObject(ComplexObjectIdentifier id) { return id.ContextId == -1 || _storage.Length <= id.ContextId ? throw new NullReferenceException("Cannot find that object. It is null") @@ -99,12 +94,6 @@ namespace mROA.Implementation.Backend Activator.CreateInstance); } - public object GetObject(int id) - { - // Debug.Log($"Reading object {id} from repository with debug ID {_debugId}"); - return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException(); - } - private int FindLastIndex() { for (var i = 0; i < _storage.Length; i++) diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index aeba65c..81d6266 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -8,13 +8,14 @@ namespace mROA.Implementation.Backend { public class NetworkGatewayModule : IGatewayModule { - private readonly Type? _interactionModuleType; private readonly IInjectableModule[]? _injectableModules; + private readonly Type? _interactionModuleType; private readonly TcpListener _tcpListener; private IConnectionHub? _hub; private ISerializationToolkit? _serialization; - public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules) + public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, + IInjectableModule[] injectableModules) { _tcpListener = new(endpoint); _interactionModuleType = interactionModuleType; @@ -44,6 +45,19 @@ namespace mROA.Implementation.Backend _tcpListener.Stop(); } + public void Inject(T dependency) + { + switch (dependency) + { + case IConnectionHub interactionModule: + _hub = interactionModule; + break; + case ISerializationToolkit serializationToolkit: + _serialization = serializationToolkit; + break; + } + } + private void HandleIncomingConnections() { if (_hub is null) @@ -56,7 +70,7 @@ namespace mROA.Implementation.Backend throw new NullReferenceException("InteractionModuleType is null"); if (_serialization is null) throw new NullReferenceException("Serialization is null"); - + while (true) { var client = _tcpListener.AcceptTcpClient(); @@ -67,9 +81,9 @@ namespace mROA.Implementation.Backend interaction!.Inject(injectableModule); interaction!.Inject(_serialization); - + interaction.BaseStream = client.GetStream(); - + interaction.PostMessage(new NetworkMessage { Id = Guid.NewGuid(), SchemaId = MessageType.IdAssigning, @@ -79,13 +93,5 @@ namespace mROA.Implementation.Backend Console.WriteLine("Client registered"); } } - - public void Inject(T dependency) - { - if (dependency is IConnectionHub interactionModule) - _hub = interactionModule; - if (dependency is ISerializationToolkit serializationToolkit) - _serialization = serializationToolkit; - } } } \ No newline at end of file diff --git a/mROA/Implementation/EndPointContext.cs b/mROA/Implementation/EndPointContext.cs index 1d80548..e6351e9 100644 --- a/mROA/Implementation/EndPointContext.cs +++ b/mROA/Implementation/EndPointContext.cs @@ -13,6 +13,7 @@ namespace mROA.Implementation public int OwnerId { get => OwnerFunc(); + // ReSharper disable once UnusedMember.Global set { OwnerFunc = () => value; } } } diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index d8c9e10..978a4ab 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -98,20 +98,13 @@ namespace mROA.Implementation.Frontend var result = _executeModule.Execute(request, _contextRepository, _representationModule); - var resultType = MessageType.Unknown; - - switch (result) + var resultType = result switch { - case FinalCommandExecution: - resultType = MessageType.FinishedCommandExecution; - break; - case AsyncCommandExecution: - resultType = MessageType.AsyncCommandExecution; - break; - case ExceptionCommandExecution: - resultType = MessageType.ExceptionCommandExecution; - break; - } + FinalCommandExecution => MessageType.FinishedCommandExecution, + AsyncCommandExecution => MessageType.AsyncCommandExecution, + ExceptionCommandExecution => MessageType.ExceptionCommandExecution, + _ => MessageType.Unknown + }; _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); } diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 5defb89..7ae9170 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -81,7 +81,7 @@ namespace mROA.Implementation var secondBit = (byte)BaseStream.ReadByte(); var len = BitConverter.ToUInt16(new[] { firstBit, secondBit }); - var localSpan = _buffer.Slice(0, len); + var localSpan = _buffer[..len]; await BaseStream.ReadExactlyAsync(localSpan); diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index e31ff0a..535db4e 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -60,10 +60,5 @@ namespace mROA.Implementation if (dependency is IRepresentationModuleProducer serialisationModule) _representationProducer = serialisationModule; } - - public object GetObject(int id) - { - throw new NotSupportedException(); - } } } \ No newline at end of file diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 6abd096..14ee815 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -10,6 +10,7 @@ namespace mROA.Implementation { public interface ISharedObjectShell { + // ReSharper disable once UnusedMemberInSuper.Global IEndPointContext EndPointContext { get; set; } ComplexObjectIdentifier Identifier { get; set; } object UniversalValue { get; set; } From 76f395dce53f83255675aaf9e8b02eae48a39d84 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 11 Mar 2025 15:02:36 +0300 Subject: [PATCH 50/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=BF=D1=80=D0=BE=D1=81=D1=82=D0=B0=D1=8F?= =?UTF-8?q?=20=D0=B0=D0=B1=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=86=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=81=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=20=D1=83=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Abstract/IRemoteObjectFactory.cs | 9 ++++++ .../Implementation/ComplexObjectIdentifier.cs | 3 +- mROA/Implementation/RemoteObjectFactory.cs | 31 +++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 mROA/Abstract/IRemoteObjectFactory.cs create mode 100644 mROA/Implementation/RemoteObjectFactory.cs 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/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs index 35652ee..15ede59 100644 --- a/mROA/Implementation/ComplexObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -12,9 +12,10 @@ namespace mROA.Implementation { ContextId = contextId; OwnerId = ownerId; - } + public static ComplexObjectIdentifier Singleton(int ownerId) => new() { ContextId = -1, OwnerId = ownerId }; + public static ComplexObjectIdentifier Null = new ComplexObjectIdentifier { ContextId = -2, OwnerId = -1 }; public static ComplexObjectIdentifier FromFlat(ulong flat) => new() { Flat = flat }; 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 From 4033ae53ebc6c4466dd984b5be079221d53d266e Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 11 Mar 2025 19:42:10 +0300 Subject: [PATCH 51/66] =?UTF-8?q?=D0=9A=D0=B0=D0=BA=20=D1=82=D0=BE=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82,=20=D0=BD?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=BB=D0=BE=D1=85=D0=BE...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 6 +- Example.Frontend/ClientBasedPrinter.cs | 4 +- Example.Frontend/Program.cs | 6 +- Example.Shared/IPrinter.cs | 2 +- mROA.Codegen/mROASourceGenerator.cs | 4 +- mROA/Abstract/IContextRepository.cs | 2 +- mROA/Abstract/IStorage.cs | 4 +- .../Backend/BasicExecutionModule.cs | 2 +- .../Backend/ContextRepository.cs | 44 ++++------- .../Backend/HubRequestExtractor.cs | 10 ++- .../Backend/MultiClientContextRepository.cs | 4 +- .../ComplexContextRepository.cs | 74 +++++++++++++++++++ mROA/Implementation/ComplexRepository.cs | 39 ---------- mROA/Implementation/ExtensibleStorage.cs | 11 ++- .../Frontend/RequestExtractor.cs | 19 +++-- .../Implementation/RemoteContextRepository.cs | 19 ++++- 16 files changed, 148 insertions(+), 102 deletions(-) create mode 100644 mROA/Implementation/ComplexContextRepository.cs delete mode 100644 mROA/Implementation/ComplexRepository.cs diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 65125f4..2bfc5a1 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -10,7 +10,7 @@ namespace Example.Backend { public string Name; - public void OnPrintExternal(IPage p0) + public void OnPrintExternal(IPage p0, RequestContext ro) { } @@ -27,12 +27,12 @@ namespace Example.Backend // 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); + OnPrint?.Invoke(page, new RequestContext(context.RequestId, -1000)); Resource /= 1.5; return page; } - public event Action? OnPrint; + public event Action? OnPrint; public void Dispose() { diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index e749687..0686390 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -8,7 +8,7 @@ namespace Example.Frontend { public class ClientBasedPrinter : IPrinter { - public void OnPrintExternal(IPage p0) + public void OnPrintExternal(IPage p0, RequestContext ro) { } @@ -29,7 +29,7 @@ namespace Example.Frontend return new ClientBasedPage(); } - public event Action? OnPrint; + public event Action? OnPrint; public void Dispose() { diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 077c228..c47bec3 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -43,12 +43,12 @@ class Program Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var context = builder.GetModule(); - var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory; + var factory = context.GetSingleObject(typeof(IPrinterFactory), 0) as IPrinterFactory; //правильный порядок команд 8-5-10-7 using (var disposingPrinter = factory.Create("Test")) { - disposingPrinter.OnPrint += page1 => { Console.WriteLine("New page creater. Called from event!!!"); }; + disposingPrinter.OnPrint += (_, _) => { Console.WriteLine("New page creater. Called from event!!!"); }; Console.WriteLine("Printer created"); Thread.Sleep(100); @@ -90,7 +90,7 @@ class Program } - var loadSingleton = context.GetSingleObject(typeof(ILoadTest)) as ILoadTest; + var loadSingleton = context.GetSingleObject(typeof(ILoadTest), 0) as ILoadTest; var cts = new CancellationTokenSource(); diff --git a/Example.Shared/IPrinter.cs b/Example.Shared/IPrinter.cs index 3b320fd..f5b25f0 100644 --- a/Example.Shared/IPrinter.cs +++ b/Example.Shared/IPrinter.cs @@ -12,6 +12,6 @@ namespace Example.Shared double Resource { get; set; } string GetName(); Task Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken); - event Action OnPrint; + event Action OnPrint; } } \ No newline at end of file diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index ed5abd2..651dd1b 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -481,7 +481,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} {callFilter} var request = new DefaultCallRequest {{ - CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, context.OwnerId), Parameters = new object[] {{ {transferParameters} }} + CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, context.HostId), Parameters = new object[] {{ {transferParameters} }} }}; module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); }}; @@ -511,7 +511,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} parametersInsertList.Add("(CancellationToken)special[1]"); break; case "RequestContext": - parametersInsertList.Add("special[1] as RequestContext"); + parametersInsertList.Add("special[0] as RequestContext"); break; default: parametersInsertList.Add(Caster(parameter, diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs index 7a3366e..920a317 100644 --- a/mROA/Abstract/IContextRepository.cs +++ b/mROA/Abstract/IContextRepository.cs @@ -9,7 +9,7 @@ namespace mROA.Abstract int ResisterObject(object o, IEndPointContext context); void ClearObject(ComplexObjectIdentifier id); T GetObject(ComplexObjectIdentifier id); - object GetSingleObject(Type type); + object GetSingleObject(Type type, int ownerId); int GetObjectIndex(object o, IEndPointContext context); } } \ No newline at end of file diff --git a/mROA/Abstract/IStorage.cs b/mROA/Abstract/IStorage.cs index 1ba6de3..88432a8 100644 --- a/mROA/Abstract/IStorage.cs +++ b/mROA/Abstract/IStorage.cs @@ -1,8 +1,8 @@ namespace mROA.Abstract { - public interface IStorage + public interface IStorage where T : class { - T GetValue(int index); + T? GetValue(int index); int GetIndex(T value); int Place(T value); void Free(int index); diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 0924999..8b056ba 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -70,7 +70,7 @@ namespace mROA.Implementation.Backend var context = command.ObjectId.ContextId != -1 ? contextRepository.GetObject(command.ObjectId) - : contextRepository.GetSingleObject(invoker.SuitableType); + : contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId); if (context == null) throw new NullReferenceException("Instance can't be null"); diff --git a/mROA/Implementation/Backend/ContextRepository.cs b/mROA/Implementation/Backend/ContextRepository.cs index 55b8169..cbc1220 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -23,26 +23,20 @@ namespace mROA.Implementation.Backend // [CanBeNull] private Dictionary _singletons; - private object?[] _storage; + private IStorage _storage; public ContextRepository() { - _storage = new object[StartupSize]; + _storage = new ExtensibleStorage(); } public int HostId { get; set; } public int ResisterObject(object o, IEndPointContext context) { - if (!_lastIndexFinder.IsCompleted) - _lastIndexFinder.Wait(); + var last = _storage.Place(o); - _storage[_lastIndexFinder.Result] = o; - - - var last = _lastIndexFinder.Result; - _lastIndexFinder = Task.Run(FindLastIndex); EventBinders.OfType>().FirstOrDefault() ?.BindEvents((T)o, context, _representationModuleProducer!, last); @@ -51,18 +45,22 @@ namespace mROA.Implementation.Backend public void ClearObject(ComplexObjectIdentifier id) { - _storage[id.ContextId] = null; - _lastIndexFinder = Task.FromResult(id.ContextId); + _storage.Free(id.ContextId); } public T GetObject(ComplexObjectIdentifier id) { - return id.ContextId == -1 || _storage.Length <= id.ContextId - ? throw new NullReferenceException("Cannot find that object. It is null") - : (T)_storage[id.ContextId]!; + 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) + public object GetSingleObject(Type type, int ownerId) { return _singletons.GetValueOrDefault(type.GetHashCode()) ?? throw new ArgumentException("Unregistered singleton type"); @@ -70,7 +68,7 @@ namespace mROA.Implementation.Backend public int GetObjectIndex(object o, IEndPointContext context) { - var index = Array.IndexOf(_storage, o); + var index = _storage.GetIndex(o); return index == -1 ? ResisterObject(o, context) : index; } @@ -93,19 +91,5 @@ namespace mROA.Implementation.Backend i.GetCustomAttributes(typeof(SharedObjectInterfaceAttribute), true).Length > 0)!.GetHashCode(), Activator.CreateInstance); } - - private int FindLastIndex() - { - for (var i = 0; i < _storage.Length; i++) - { - if (_storage[i] is null) - return i; - } - - var nextStorage = new object[_storage.Length + GrowSize]; - Array.Copy(_storage, nextStorage, _storage.Length); - _storage = nextStorage; - return _storage.Length; - } } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 3bad121..4754761 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -8,6 +8,7 @@ namespace mROA.Implementation.Backend private IConnectionHub? _hub; private IContextRepository? _contextRepository; + private IContextRepository? _remoteContextRepository; private IMethodRepository? _methodRepository; private ISerializationToolkit? _serializationToolkit; private IExecuteModule? _executeModule; @@ -26,8 +27,12 @@ namespace mROA.Implementation.Backend _hub = connectionHub; _hub.OnConnected += HubOnOnConnected; break; - case IContextRepository contextRepository: - _contextRepository = contextRepository; + case MultiClientContextRepository: + case ContextRepository: + _contextRepository = dependency as IContextRepository; + break; + case RemoteContextRepository remoteContextRepository: + _remoteContextRepository = remoteContextRepository; break; case IMethodRepository methodRepository: _methodRepository = methodRepository; @@ -52,6 +57,7 @@ namespace mROA.Implementation.Backend extractor.Inject(_methodRepository); extractor.Inject(_serializationToolkit); extractor.Inject(_executeModule); + extractor.Inject(_remoteContextRepository); _ = extractor.StartExtraction(); } } diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 94af7d0..9078788 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -38,10 +38,10 @@ namespace mROA.Implementation.Backend return repository.GetObject(id); } - public object GetSingleObject(Type type) + public object GetSingleObject(Type type, int ownerId) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); - return repository.GetSingleObject(type); + return repository.GetSingleObject(type, ownerId); } public int GetObjectIndex(object o, IEndPointContext context) diff --git a/mROA/Implementation/ComplexContextRepository.cs b/mROA/Implementation/ComplexContextRepository.cs new file mode 100644 index 0000000..536a36c --- /dev/null +++ b/mROA/Implementation/ComplexContextRepository.cs @@ -0,0 +1,74 @@ +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 object GetSingleObject(Type type, int ownerId) + // { + // } + + public int GetObjectIndex(object o, IEndPointContext context) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/mROA/Implementation/ComplexRepository.cs b/mROA/Implementation/ComplexRepository.cs deleted file mode 100644 index a46ae58..0000000 --- a/mROA/Implementation/ComplexRepository.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System; -using mROA.Abstract; - -namespace mROA.Implementation -{ - public class ComplexRepository : IContextRepository - { - public void Inject(T dependency) - { - throw new NotImplementedException(); - } - - public int HostId { get; set; } - public int ResisterObject(object o, IEndPointContext context) - { - throw new NotImplementedException(); - } - - public void ClearObject(ComplexObjectIdentifier id) - { - throw new NotImplementedException(); - } - - public T GetObject(ComplexObjectIdentifier id) - { - throw new NotImplementedException(); - } - - public object GetSingleObject(Type type) - { - throw new NotImplementedException(); - } - - public int GetObjectIndex(object o, IEndPointContext context) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/mROA/Implementation/ExtensibleStorage.cs b/mROA/Implementation/ExtensibleStorage.cs index 02d12a4..a9c6d18 100644 --- a/mROA/Implementation/ExtensibleStorage.cs +++ b/mROA/Implementation/ExtensibleStorage.cs @@ -5,16 +5,20 @@ using mROA.Abstract; namespace mROA.Implementation { - public class ExtensibleStorage : IStorage + 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) + public T? GetValue(int index) { - return _array[index]!; + if (index < 0 || index >= _array.Length) + { + return null; + } + return _array[index]; } public int GetIndex(T value) @@ -31,6 +35,7 @@ namespace mROA.Implementation var index = _freePlaces.First.Value; + _freePlaces.RemoveFirst(); _array[index] = value; return index; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 978a4ab..7db7a73 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -11,7 +11,8 @@ namespace mROA.Implementation.Frontend { public class RequestExtractor : IRequestExtractor { - private IContextRepository? _contextRepository; + private IContextRepository? _realContextRepository; + private IContextRepository? _remoteContextRepository; private IExecuteModule? _executeModule; private IMethodRepository? _methodRepository; private IRepresentationModule? _representationModule; @@ -24,8 +25,12 @@ namespace mROA.Implementation.Frontend case IExecuteModule executeModule: _executeModule = executeModule; break; - case IContextRepository contextRepository: - _contextRepository = contextRepository; + case MultiClientContextRepository : + case ContextRepository: + _realContextRepository = dependency as IContextRepository; + break; + case RemoteContextRepository remoteContextRepository: + _remoteContextRepository = remoteContextRepository; break; case IMethodRepository methodRepository: _methodRepository = methodRepository; @@ -47,7 +52,7 @@ namespace mROA.Implementation.Frontend throw new NullReferenceException("Serializing toolkit is null."); if (_executeModule == null) throw new NullReferenceException("Execute module is null."); - if (_contextRepository == null) + if (_realContextRepository == null) throw new NullReferenceException("Context repository is null."); if (_representationModule == null) throw new NullReferenceException("Representation module is null."); @@ -89,14 +94,14 @@ namespace mROA.Implementation.Frontend #endif var req = cancelRequest.Result; tokenSource.Cancel(); - _executeModule.Execute(req, _contextRepository, _representationModule); + _executeModule.Execute(req, _realContextRepository, _representationModule); } else if (defaultRequest.IsCompleted) { tokenSource.Cancel(); var request = defaultRequest.Result; - var result = _executeModule.Execute(request, _contextRepository, _representationModule); + var result = _executeModule.Execute(request, _realContextRepository, _representationModule); var resultType = result switch { @@ -112,7 +117,7 @@ namespace mROA.Implementation.Frontend { tokenSource.Cancel(); var request = eventRequest.Result; - _executeModule.Execute(request, _contextRepository, _representationModule); + _executeModule.Execute(request, _remoteContextRepository!, _representationModule); } } } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index 535db4e..f5d734d 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -1,11 +1,13 @@ using System; using System.Collections.Generic; +using System.Linq; using mROA.Abstract; namespace mROA.Implementation { public class RemoteContextRepository : IContextRepository { + private List _producedRemoteEndpoints = new(); public static Dictionary RemoteTypes = new(); private IRepresentationModuleProducer? _representationProducer; @@ -23,6 +25,9 @@ namespace mROA.Implementation 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"); @@ -31,18 +36,24 @@ namespace mROA.Implementation _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) + 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()); - return Activator.CreateInstance(RemoteTypes[type], -1, - representationModule)!; + + _producedRemoteEndpoints.Add((Activator.CreateInstance(RemoteTypes[type], -1, + representationModule) as RemoteObjectBase)!); + + return _producedRemoteEndpoints.Last(); } public int GetObjectIndex(object o, IEndPointContext context) From 22cf8ede0ae801b8fa2786aca196efcb32d9bb0c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Wed, 12 Mar 2025 10:28:05 +0300 Subject: [PATCH 52/66] =?UTF-8?q?=D0=97=D0=B0=D0=B4=D1=83=D0=BC=D0=BA?= =?UTF-8?q?=D0=B0=20=D1=81=20=D0=BE=D1=82=D1=80=D0=B8=D1=86=D0=B0=D1=82?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=BC=20=D0=B0=D0=B9=D0=B4=D0=B8?= =?UTF-8?q?=D1=88=D0=BD=D0=B8=D0=BA=D0=BE=D0=BC=20=D1=81=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=B0=D0=BB=D0=B0=20=D0=B3=D0=BB=D0=BE=D0=B1=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D0=BE=20=D0=B8=20=D0=BA=D0=B0=D0=B6=D0=B5?= =?UTF-8?q?=D1=82=D1=81=D1=8F=20=D0=BE=D0=BD=D0=B0=20=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BE=D1=81=D0=BF=D0=BE=D1=81=D0=BE=D0=B1=D0=BD?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/ClientBasedPrinter.cs | 1 + Example.Frontend/DemoCheck.cs | 37 +++++++++++++++++++ Example.Frontend/Program.cs | 20 ++++++++-- .../Backend/NetworkGatewayModule.cs | 2 +- .../Implementation/ComplexObjectIdentifier.cs | 7 ++-- .../Frontend/NetworkFrontendBridge.cs | 2 +- .../{IdAssingnment.cs => IdAssignment.cs} | 2 +- mROA/Implementation/SharedObjectShell.cs | 4 +- 8 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 Example.Frontend/DemoCheck.cs rename mROA/Implementation/{IdAssingnment.cs => IdAssignment.cs} (72%) diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs index 0686390..6afc7a3 100644 --- a/Example.Frontend/ClientBasedPrinter.cs +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -17,6 +17,7 @@ namespace Example.Frontend public string GetName() { Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); + DemoCheck.BackwardCall = true; return "ClientBasedPrinter from mroa"; } 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/Program.cs b/Example.Frontend/Program.cs index c47bec3..156026d 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -48,25 +48,32 @@ class Program //правильный порядок команд 8-5-10-7 using (var disposingPrinter = factory.Create("Test")) { - disposingPrinter.OnPrint += (_, _) => { Console.WriteLine("New page creater. Called from event!!!"); }; + 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 = disposingPrinter.GetName(); + DemoCheck.BasicNonParamsCall = true; Console.WriteLine("Printer name : {0}", name); Thread.Sleep(100); factory.Register(new ClientBasedPrinter()); + DemoCheck.ClientBasedImplementation = true; Console.WriteLine("Registered printer"); Thread.Sleep(100); - var registred = factory.GetFirstPrinter(); + var registered = factory.GetFirstPrinter(); Console.WriteLine("First printer"); Thread.Sleep(100); - Console.WriteLine(registred); + Console.WriteLine(registered); Console.WriteLine("Collecting all printers"); var names = factory.CollectAllNames(); Thread.Sleep(100); @@ -76,11 +83,15 @@ class Program var page = disposingPrinter.Print("Test Page", false, default, CancellationToken.None).GetAwaiter() .GetResult(); Console.WriteLine("Page printed"); + DemoCheck.TaskExecution = true; Console.WriteLine(page.ToString()); Console.WriteLine($"Printer resource : {disposingPrinter.Resource}"); + DemoCheck.PropertyGet = true; + Console.WriteLine("Restoring resource"); disposingPrinter.Resource = 100; + DemoCheck.PropertySet = true; Console.WriteLine($"Printer resource again : {disposingPrinter.Resource}"); var data = page.GetData(); @@ -88,6 +99,7 @@ class Program Console.WriteLine("Dispose printer"); } + DemoCheck.Dispose = true; var loadSingleton = context.GetSingleObject(typeof(ILoadTest), 0) as ILoadTest; @@ -100,6 +112,8 @@ class Program Thread.Sleep(5000); cts.Cancel(); Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}"); + DemoCheck.TaskCancelation = true; + DemoCheck.Show(); Console.ReadKey(); // // const int iterations = 10000; diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 81d6266..61e19c7 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -87,7 +87,7 @@ namespace mROA.Implementation.Backend interaction.PostMessage(new NetworkMessage { Id = Guid.NewGuid(), SchemaId = MessageType.IdAssigning, - Data = _serialization.Serialize(new IdAssingnment { Id = interaction.ConnectionId }) + Data = _serialization.Serialize(new IdAssignment { Id = -interaction.ConnectionId }) }); _hub.RegisterInteraction(interaction); Console.WriteLine("Client registered"); diff --git a/mROA/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs index 15ede59..37d87a2 100644 --- a/mROA/Implementation/ComplexObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -7,18 +7,19 @@ namespace mROA.Implementation { 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 = -1 }; + 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} }}"; diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 5616e5b..2bff07f 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -46,7 +46,7 @@ namespace mROA.Implementation.Frontend } - var assignment = _serialization.Deserialize(welcomeMessage.Data)!; + var assignment = _serialization.Deserialize(welcomeMessage.Data)!; TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); } } diff --git a/mROA/Implementation/IdAssingnment.cs b/mROA/Implementation/IdAssignment.cs similarity index 72% rename from mROA/Implementation/IdAssingnment.cs rename to mROA/Implementation/IdAssignment.cs index dfb634b..427124b 100644 --- a/mROA/Implementation/IdAssingnment.cs +++ b/mROA/Implementation/IdAssignment.cs @@ -1,6 +1,6 @@ namespace mROA.Implementation { - public class IdAssingnment + public class IdAssignment { public int Id { get; set; } } diff --git a/mROA/Implementation/SharedObjectShell.cs b/mROA/Implementation/SharedObjectShell.cs index 14ee815..0fe0450 100644 --- a/mROA/Implementation/SharedObjectShell.cs +++ b/mROA/Implementation/SharedObjectShell.cs @@ -51,7 +51,7 @@ namespace mROA.Implementation } else { - _identifier.OwnerId = EndPointContext.HostId; + _identifier.OwnerId = EndPointContext.OwnerId; _identifier.ContextId = EndPointContext.RealRepository.GetObjectIndex(Value, EndPointContext); } } @@ -71,7 +71,7 @@ namespace mROA.Implementation { get { - _identifier.OwnerId = _identifier.OwnerId == -1 ? EndPointContext.OwnerId : _identifier.OwnerId; + _identifier.OwnerId = _identifier.OwnerId == 0 ? EndPointContext.OwnerId : _identifier.OwnerId; return _identifier; } set From 6d9607081c412ddf0785536631ac5c038cfdb850 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 08:43:48 +0300 Subject: [PATCH 53/66] =?UTF-8?q?=D0=94=D0=B5=D0=BC=D0=BA=D0=B0=20=D1=81?= =?UTF-8?q?=20=D1=87=D0=B0=D1=82=D0=BE=D0=BC=20=D1=80=D0=B0=D0=B1=D0=BE?= =?UTF-8?q?=D1=82=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 2 +- Example.Events.Backend/Chat.cs | 18 +++++++++++++++ Example.Events.Backend/ChatFactory.cs | 22 ++++++++++++++++++ Example.Events.Shared/IChat.cs | 13 +++++++++++ Example.Events.Shared/IChatFactory.cs | 12 ++++++++++ Example.Shared/Example.Shared.csproj | 6 ++--- Example.Shared/ILoadTest.cs | 3 +-- Example.Shared/IPrinterFactory.cs | 2 +- mROA.Cbor/CborSerializationToolkit.cs | 7 ++++++ mROA.Codegen/mROASourceGenerator.cs | 9 ++++---- mROA.sln | 33 ++++++++++++++++++++++++--- 11 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 Example.Events.Backend/Chat.cs create mode 100644 Example.Events.Backend/ChatFactory.cs create mode 100644 Example.Events.Shared/IChat.cs create mode 100644 Example.Events.Shared/IChatFactory.cs diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index 2bfc5a1..f4073bf 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -27,7 +27,7 @@ namespace Example.Backend // 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, new RequestContext(context.RequestId, -1000)); + OnPrint?.Invoke(page, context); Resource /= 1.5; return page; } 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.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.Shared/Example.Shared.csproj b/Example.Shared/Example.Shared.csproj index f2050a6..98d21fd 100644 --- a/Example.Shared/Example.Shared.csproj +++ b/Example.Shared/Example.Shared.csproj @@ -2,17 +2,15 @@ net9.0 - enable - 9 - + - + diff --git a/Example.Shared/ILoadTest.cs b/Example.Shared/ILoadTest.cs index 8234f1f..227af99 100644 --- a/Example.Shared/ILoadTest.cs +++ b/Example.Shared/ILoadTest.cs @@ -15,5 +15,4 @@ namespace Example.Shared Task AsyncTest(CancellationToken token = default); } -} - +} \ No newline at end of file diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs index 884293d..60d4d0e 100644 --- a/Example.Shared/IPrinterFactory.cs +++ b/Example.Shared/IPrinterFactory.cs @@ -4,7 +4,7 @@ using mROA.Implementation.Attributes; namespace Example.Shared { [SharedObjectInterface] - public interface IPrinterFactory : IShared + public interface IPrinterFactory : IShared { IPrinter Create(string printerName); void Register(IPrinter printer); diff --git a/mROA.Cbor/CborSerializationToolkit.cs b/mROA.Cbor/CborSerializationToolkit.cs index 341b49d..47d1fc0 100644 --- a/mROA.Cbor/CborSerializationToolkit.cs +++ b/mROA.Cbor/CborSerializationToolkit.cs @@ -62,6 +62,13 @@ namespace mROA.Cbor if (nonCasted is PreParsedValue preParsed) return preParsed.ToObject(type, context); + + + if (type == typeof(Guid)) + { + return new Guid((byte[])nonCasted); + } + return Convert.ChangeType(nonCasted, type); } diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index 651dd1b..b58c2de 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -283,8 +283,8 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} {{ BindAction = (instance, context, representationProducer, index) => {{ - var module = representationProducer.Produce(context.OwnerId); - + var ownerId = context.OwnerId; + var module = representationProducer.Produce(ownerId); {string.Join("\r\n", singleEventBinder)} }} }}"; @@ -471,14 +471,15 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} var requestIndex = parameters.FindIndex(i => i.Name == "RequestContext"); if (requestIndex != -1) { - callFilter = $"\n\r\t\t\tif(context.OwnerId == p{requestIndex}.OwnerId) return;"; + 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...""); -{callFilter} var request = new DefaultCallRequest {{ CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, context.HostId), Parameters = new object[] {{ {transferParameters} }} diff --git a/mROA.sln b/mROA.sln index 6899901..1cfa5fa 100644 --- a/mROA.sln +++ b/mROA.sln @@ -21,6 +21,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benc 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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -59,13 +69,30 @@ Global {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 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 From 997a35159afe88e0c15fd053f38823beb991bc17 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 15:10:36 +0300 Subject: [PATCH 54/66] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Example.Events.Backend.csproj | 14 ++++ Example.Events.Backend/Program.cs | 54 ++++++++++++++++ .../Example.Events.Client.csproj | 14 ++++ Example.Events.Client/Program.cs | 64 +++++++++++++++++++ .../Example.Events.Shared.csproj | 16 +++++ 5 files changed, 162 insertions(+) create mode 100644 Example.Events.Backend/Example.Events.Backend.csproj create mode 100644 Example.Events.Backend/Program.cs create mode 100644 Example.Events.Client/Example.Events.Client.csproj create mode 100644 Example.Events.Client/Program.cs create mode 100644 Example.Events.Shared/Example.Events.Shared.csproj diff --git a/Example.Events.Backend/Example.Events.Backend.csproj b/Example.Events.Backend/Example.Events.Backend.csproj new file mode 100644 index 0000000..2c675f7 --- /dev/null +++ b/Example.Events.Backend/Example.Events.Backend.csproj @@ -0,0 +1,14 @@ + + + + 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..b5c9964 --- /dev/null +++ b/Example.Events.Backend/Program.cs @@ -0,0 +1,54 @@ +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.UseJsonSerialisation(); + builder.Modules.Add(new CborSerializationToolkit()); + 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 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..2c675f7 --- /dev/null +++ b/Example.Events.Client/Example.Events.Client.csproj @@ -0,0 +1,14 @@ + + + + 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..6d45ec6 --- /dev/null +++ b/Example.Events.Client/Program.cs @@ -0,0 +1,64 @@ +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.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(); + + 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(); + + Console.Write(symb); + chat.PostSymbol(symb); + } + } +} \ 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 + + + + + + + + + + From 41cea56995838c19ba92e8dabd4d590ee546dcf2 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 15:25:52 +0300 Subject: [PATCH 55/66] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D1=81=D0=B5=D1=82=D0=B5=D0=B2=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Events.Backend/Program.cs | 2 +- Example.Events.Client/Program.cs | 2 +- Example.Frontend/Program.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Example.Events.Backend/Program.cs b/Example.Events.Backend/Program.cs index b5c9964..3bd1f89 100644 --- a/Example.Events.Backend/Program.cs +++ b/Example.Events.Backend/Program.cs @@ -17,7 +17,7 @@ class Program // builder.UseJsonSerialisation(); builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new BackendIdentityGenerator()); - builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule), + builder.UseNetworkGateway(IPEndPoint.Parse("192.168.1.101:6000"), typeof(NextGenerationInteractionModule), builder.GetModule()!); builder.Modules.Add(new ConnectionHub()); diff --git a/Example.Events.Client/Program.cs b/Example.Events.Client/Program.cs index 6d45ec6..2a3e14c 100644 --- a/Example.Events.Client/Program.cs +++ b/Example.Events.Client/Program.cs @@ -21,7 +21,7 @@ class Program 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 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()); diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 156026d..c4fb975 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -24,7 +24,7 @@ class Program 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 NetworkFrontendBridge(new IPEndPoint(IPAddress.Parse("95.105.78.72"), 4567))); builder.Modules.Add(new StaticRepresentationModuleProducer()); builder.Modules.Add(new RequestExtractor()); builder.Modules.Add(new BasicExecutionModule()); From 7e040892cc4e58492b793fe496bd2065077e02fd Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 15:55:07 +0300 Subject: [PATCH 56/66] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D1=80=D0=BE=D1=8F?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B7=D0=B0=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Program.cs | 2 ++ .../Example.Events.Backend.csproj | 4 ++++ Example.Events.Client/Example.Events.Client.csproj | 4 ++++ Example.Events.Client/Program.cs | 12 ++++++++++-- mROA/Implementation/Frontend/RequestExtractor.cs | 14 ++++++++++++-- .../NextGenerationInteractionModule.cs | 3 ++- mROA/Implementation/RepresentationModule.cs | 2 +- 7 files changed, 35 insertions(+), 6 deletions(-) diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 2885243..1e12d48 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -17,6 +17,8 @@ class Program // 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()!); diff --git a/Example.Events.Backend/Example.Events.Backend.csproj b/Example.Events.Backend/Example.Events.Backend.csproj index 2c675f7..4e79fe1 100644 --- a/Example.Events.Backend/Example.Events.Backend.csproj +++ b/Example.Events.Backend/Example.Events.Backend.csproj @@ -7,6 +7,10 @@ enable + + + + diff --git a/Example.Events.Client/Example.Events.Client.csproj b/Example.Events.Client/Example.Events.Client.csproj index 2c675f7..4e79fe1 100644 --- a/Example.Events.Client/Example.Events.Client.csproj +++ b/Example.Events.Client/Example.Events.Client.csproj @@ -7,6 +7,10 @@ enable + + + + diff --git a/Example.Events.Client/Program.cs b/Example.Events.Client/Program.cs index 2a3e14c..155e969 100644 --- a/Example.Events.Client/Program.cs +++ b/Example.Events.Client/Program.cs @@ -1,4 +1,5 @@ -using System.Net; +using System.Diagnostics; +using System.Net; using Example.Events.Shared; using mROA.Cbor; using mROA.Codegen; @@ -56,9 +57,16 @@ class Program } 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/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 7db7a73..cb87c79 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -25,7 +26,7 @@ namespace mROA.Implementation.Frontend case IExecuteModule executeModule: _executeModule = executeModule; break; - case MultiClientContextRepository : + case MultiClientContextRepository: case ContextRepository: _realContextRepository = dependency as IContextRepository; break; @@ -67,10 +68,18 @@ namespace mROA.Implementation.Frontend 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 {sw.ElapsedMilliseconds} milliseconds."); + } #endif var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; @@ -86,6 +95,7 @@ namespace mROA.Implementation.Frontend Task.WaitAny(defaultRequest, cancelRequest, eventRequest); #if TRACE Console.WriteLine("Request received"); + sw.Restart(); #endif if (cancelRequest.IsCompleted) { @@ -128,4 +138,4 @@ namespace mROA.Implementation.Frontend }); } } -} \ No newline at end of file +} diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 7ae9170..733c921 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -51,6 +51,7 @@ namespace mROA.Implementation var rawMessage = _serialization.Serialize(message); var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); + await BaseStream.WriteAsync(header); await BaseStream.WriteAsync(rawMessage); } @@ -89,7 +90,7 @@ namespace mROA.Implementation var message = _serialization.Deserialize(localSpan.Span); #if TRACE - Console.WriteLine($"Received Message {message.Id} - {message.SchemaId}"); + Console.WriteLine($"{DateTime.Now.TimeOfDay} Received Message {message.Id} - {message.SchemaId}"); TransmissionConfig.TotalTransmittedBytes += len; Console.WriteLine($"Total recieced bytes are {TransmissionConfig.TotalTransmittedBytes}"); #endif diff --git a/mROA/Implementation/RepresentationModule.cs b/mROA/Implementation/RepresentationModule.cs index 58f2ce5..ffd1b87 100644 --- a/mROA/Implementation/RepresentationModule.cs +++ b/mROA/Implementation/RepresentationModule.cs @@ -91,7 +91,7 @@ namespace mROA.Implementation if (_serialization == null) throw new NullReferenceException("Serialization toolkit is not initialized"); #if TRACE - Console.WriteLine($"Posting message: {id} - {messageType} to {Id}"); + Console.WriteLine($"{DateTime.Now.TimeOfDay} Posting message: {id} - {messageType} to {Id}"); #endif var serialized = _serialization.Serialize(payload, payloadType); From 1ff521c6144cae24e2f30ceab6adf693f470f43c Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 19:58:25 +0300 Subject: [PATCH 57/66] =?UTF-8?q?=D0=A7=D0=B8=D1=81=D1=82=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BE=D1=82=20=D1=81=D1=82=D0=B0=D1=80=D0=BE=D0=B3=D0=BE=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Events.Backend/Program.cs | 1 - .../Backend/BasicExecutionModule.cs | 37 -------- .../Backend/JsonSerialisationModule.cs | 80 ---------------- .../Backend/StreamBasedInteractionModule.cs | 66 ------------- .../ComplexContextRepository.cs | 4 - .../JsonFrontendSerialisationModule.cs | 94 ------------------- .../Frontend/RemoteException.cs | 17 ++++ .../Frontend/RequestExtractor.cs | 6 +- .../StreamBasedFrontendInteractionModule.cs | 49 ---------- mROA/Implementation/RemoteObjectBase.cs | 7 -- 10 files changed, 18 insertions(+), 343 deletions(-) delete mode 100644 mROA/Implementation/Backend/JsonSerialisationModule.cs delete mode 100644 mROA/Implementation/Backend/StreamBasedInteractionModule.cs delete mode 100644 mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs create mode 100644 mROA/Implementation/Frontend/RemoteException.cs delete mode 100644 mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs diff --git a/Example.Events.Backend/Program.cs b/Example.Events.Backend/Program.cs index 3bd1f89..d42eb89 100644 --- a/Example.Events.Backend/Program.cs +++ b/Example.Events.Backend/Program.cs @@ -14,7 +14,6 @@ class Program static void Main(string[] args) { var builder = new FullMixBuilder(); - // builder.UseJsonSerialisation(); builder.Modules.Add(new CborSerializationToolkit()); builder.Modules.Add(new BackendIdentityGenerator()); builder.UseNetworkGateway(IPEndPoint.Parse("192.168.1.101:6000"), typeof(NextGenerationInteractionModule), diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 8b056ba..e36ac30 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -183,25 +183,6 @@ namespace mROA.Implementation.Backend multiClientOwnershipRepository?.FreeOwnership(); }); - // result.ContinueWith(_ => - // { - // 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(); - // }, token); - return new AsyncCommandExecution { Id = command.Id @@ -245,24 +226,6 @@ namespace mROA.Implementation.Backend multiClientOwnershipRepository?.FreeOwnership(); }); - - // result.ContinueWith(t => - // { - // var finalResult = t.GetType().GetProperty("Result")?.GetValue(t); - // 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(); - // }, token); - return new AsyncCommandExecution { Id = command.Id 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/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/ComplexContextRepository.cs b/mROA/Implementation/ComplexContextRepository.cs index 536a36c..8f44c78 100644 --- a/mROA/Implementation/ComplexContextRepository.cs +++ b/mROA/Implementation/ComplexContextRepository.cs @@ -62,10 +62,6 @@ namespace mROA.Implementation throw new NotImplementedException(); } - // public object GetSingleObject(Type type, int ownerId) - // { - // } - public int GetObjectIndex(object o, IEndPointContext context) { throw new NotImplementedException(); diff --git a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs deleted file mode 100644 index 98bae9a..0000000 --- a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; - -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 : 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/RemoteException.cs b/mROA/Implementation/Frontend/RemoteException.cs new file mode 100644 index 0000000..093d9c1 --- /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 cb87c79..0788ba9 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,5 +1,4 @@ using System; -using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; @@ -59,9 +58,7 @@ namespace mROA.Implementation.Frontend 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); @@ -120,7 +117,6 @@ namespace mROA.Implementation.Frontend ExceptionCommandExecution => MessageType.ExceptionCommandExecution, _ => MessageType.Unknown }; - _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); } else 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/RemoteObjectBase.cs b/mROA/Implementation/RemoteObjectBase.cs index 225a010..a35e734 100644 --- a/mROA/Implementation/RemoteObjectBase.cs +++ b/mROA/Implementation/RemoteObjectBase.cs @@ -86,13 +86,6 @@ namespace mROA.Implementation successResponse, errorResponse }, cancellationToken); - // if (cancellationToken.IsCancellationRequested) - // { - // await _representationModule.PostCallMessageAsync(request.Id, MessageType.CancelRequest, request.Id); - // localTokenSource.Cancel(); - // cancellationToken.ThrowIfCancellationRequested(); - // } - if (successResponse.IsCompletedSuccessfully) { localTokenSource.Cancel(); From 40a7f86dcfd2a927c227abd90ec6218532292f82 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 20:01:17 +0300 Subject: [PATCH 58/66] =?UTF-8?q?=D0=90=D0=B2=D1=82=D0=BE=D0=BC=D0=B0?= =?UTF-8?q?=D1=82=D0=B8=D1=87=D0=B5=D1=81=D0=BA=D0=B8=D0=B9=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B8=D0=BD=D0=B0=D0=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Frontend/Program.cs | 2 +- mROA/Abstract/IConnectionHub.cs | 1 + mROA/Abstract/IEndPointContext.cs | 2 +- mROA/Abstract/IExecuteModule.cs | 3 ++- mROA/Abstract/IFrontendBridge.cs | 1 - mROA/Abstract/IGatewayModule.cs | 2 +- mROA/Abstract/IMethodInvoker.cs | 4 ++-- mROA/Abstract/IRequestExtractor.cs | 2 +- mROA/Abstract/ISerializationToolkit.cs | 1 - .../Attributes/SerializationIgnoreAttribute.cs | 1 - .../Attributes/SharedObjectInterfaceAttribute.cs | 4 +++- .../Attributes/SharedObjectSingletonAttribute.cs | 4 +++- .../Backend/BackendIdentityGenerator.cs | 2 +- .../Backend/BasicConfigurationExtensions.cs | 5 +++-- mROA/Implementation/Backend/ConnectionHub.cs | 8 ++++---- mROA/Implementation/Backend/ContextRepository.cs | 2 +- .../Backend/MultiClientContextRepository.cs | 2 +- mROA/Implementation/CancellationRepository.cs | 4 ++-- mROA/Implementation/ComplexObjectIdentifier.cs | 3 +++ .../CreativeRepresentationModuleProducer.cs | 2 +- mROA/Implementation/ExtensibleStorage.cs | 1 + mROA/Implementation/Frontend/NetworkFrontendBridge.cs | 5 +++-- mROA/Implementation/Frontend/RemoteException.cs | 2 +- mROA/Implementation/Frontend/RequestExtractor.cs | 4 ++-- mROA/Implementation/NetworkMessage.cs | 11 ++++++++++- .../Implementation/NextGenerationInteractionModule.cs | 2 +- mROA/Implementation/RemoteContextRepository.cs | 2 +- .../StaticRepresentationModuleProducer.cs | 4 ++-- mROA/LegacyExtentions.cs | 1 + mROA/mROA.csproj | 4 ++-- 30 files changed, 55 insertions(+), 36 deletions(-) diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index c4fb975..156026d 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -24,7 +24,7 @@ class Program 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"), 4567))); + 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()); diff --git a/mROA/Abstract/IConnectionHub.cs b/mROA/Abstract/IConnectionHub.cs index 43dc945..34106f3 100644 --- a/mROA/Abstract/IConnectionHub.cs +++ b/mROA/Abstract/IConnectionHub.cs @@ -1,6 +1,7 @@ namespace mROA.Abstract { public delegate void ConnectionHandler(IRepresentationModule representationModule); + public delegate void DisconnectionHandler(IRepresentationModule representationModule); public interface IConnectionHub : IInjectableModule diff --git a/mROA/Abstract/IEndPointContext.cs b/mROA/Abstract/IEndPointContext.cs index 5d6e4c6..0267321 100644 --- a/mROA/Abstract/IEndPointContext.cs +++ b/mROA/Abstract/IEndPointContext.cs @@ -4,7 +4,7 @@ { IContextRepository RealRepository { get; } IContextRepository RemoteRepository { get; } - int HostId { get; } + int HostId { get; } int OwnerId { get; } } } \ No newline at end of file diff --git a/mROA/Abstract/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs index 29f5211..3ae2d13 100644 --- a/mROA/Abstract/IExecuteModule.cs +++ b/mROA/Abstract/IExecuteModule.cs @@ -4,6 +4,7 @@ namespace mROA.Abstract { public interface IExecuteModule : IInjectableModule { - ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository, IRepresentationModule representationModule); + 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 7d4eb3f..909f486 100644 --- a/mROA/Abstract/IFrontendBridge.cs +++ b/mROA/Abstract/IFrontendBridge.cs @@ -2,6 +2,5 @@ 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 46d96bd..77c869f 100644 --- a/mROA/Abstract/IGatewayModule.cs +++ b/mROA/Abstract/IGatewayModule.cs @@ -3,7 +3,7 @@ using System; namespace mROA.Abstract { public interface IGatewayModule : IDisposable, IInjectableModule - { + { void Run(); } } \ No newline at end of file diff --git a/mROA/Abstract/IMethodInvoker.cs b/mROA/Abstract/IMethodInvoker.cs index eb5e182..dcb04db 100644 --- a/mROA/Abstract/IMethodInvoker.cs +++ b/mROA/Abstract/IMethodInvoker.cs @@ -3,10 +3,10 @@ using System; namespace mROA.Abstract { public interface IMethodInvoker - { + { bool IsVoid { get; } Type[] ParameterTypes { get; } Type? ReturnType { get; } - Type SuitableType { get; } + Type SuitableType { get; } } } \ No newline at end of file diff --git a/mROA/Abstract/IRequestExtractor.cs b/mROA/Abstract/IRequestExtractor.cs index 30711fc..d49194b 100644 --- a/mROA/Abstract/IRequestExtractor.cs +++ b/mROA/Abstract/IRequestExtractor.cs @@ -4,6 +4,6 @@ namespace mROA.Abstract { public interface IRequestExtractor : IInjectableModule { - Task StartExtraction(); + Task StartExtraction(); } } \ No newline at end of file diff --git a/mROA/Abstract/ISerializationToolkit.cs b/mROA/Abstract/ISerializationToolkit.cs index c7ce9f4..497c953 100644 --- a/mROA/Abstract/ISerializationToolkit.cs +++ b/mROA/Abstract/ISerializationToolkit.cs @@ -12,6 +12,5 @@ namespace mROA.Abstract 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/Implementation/Attributes/SerializationIgnoreAttribute.cs b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs index b63d4d3..cd32ca7 100644 --- a/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs +++ b/mROA/Implementation/Attributes/SerializationIgnoreAttribute.cs @@ -4,6 +4,5 @@ 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 c187036..adcc66e 100644 --- a/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs +++ b/mROA/Implementation/Attributes/SharedObjectInterfaceAttribute.cs @@ -2,5 +2,7 @@ namespace mROA.Implementation.Attributes { - public class SharedObjectInterfaceAttribute : Attribute { } + 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 84002ac..ec2f228 100644 --- a/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs +++ b/mROA/Implementation/Attributes/SharedObjectSingletonAttribute.cs @@ -2,5 +2,7 @@ namespace mROA.Implementation.Attributes { - public class SharedObjectSingletonAttribute : Attribute { } + 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 ae49490..dce88be 100644 --- a/mROA/Implementation/Backend/BackendIdentityGenerator.cs +++ b/mROA/Implementation/Backend/BackendIdentityGenerator.cs @@ -7,7 +7,7 @@ namespace mROA.Implementation.Backend private int _currentId; public int GetNextIdentity() - { + { return ++_currentId; } diff --git a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs index b7f2460..b8e0f7c 100644 --- a/mROA/Implementation/Backend/BasicConfigurationExtensions.cs +++ b/mROA/Implementation/Backend/BasicConfigurationExtensions.cs @@ -8,11 +8,12 @@ namespace mROA.Implementation.Backend { public static class BasicConfigurationExtensions { - public static void UseNetworkGateway(this FullMixBuilder builder, IPEndPoint endPoint, Type interactionModuleType, params IInjectableModule[] 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()); diff --git a/mROA/Implementation/Backend/ConnectionHub.cs b/mROA/Implementation/Backend/ConnectionHub.cs index 61fa56c..f26a304 100644 --- a/mROA/Implementation/Backend/ConnectionHub.cs +++ b/mROA/Implementation/Backend/ConnectionHub.cs @@ -8,12 +8,12 @@ namespace mROA.Implementation.Backend { private readonly Dictionary _connections = new(); private ISerializationToolkit? _serializationToolkit; - + public void RegisterInteraction(INextGenerationInteractionModule interaction) { if (_serializationToolkit is null) throw new NullReferenceException("Serialization toolkit is null"); - + _connections.Add(interaction.ConnectionId, interaction); var module = new RepresentationModule(); module.Inject(_serializationToolkit); @@ -28,11 +28,11 @@ namespace mROA.Implementation.Backend public event ConnectionHandler? OnConnected; public event DisconnectionHandler? OnDisconnected; + public void Inject(T dependency) { - if (dependency is ISerializationToolkit serializationToolkit) + 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 cbc1220..71ee389 100644 --- a/mROA/Implementation/Backend/ContextRepository.cs +++ b/mROA/Implementation/Backend/ContextRepository.cs @@ -51,7 +51,7 @@ namespace mROA.Implementation.Backend public T GetObject(ComplexObjectIdentifier id) { var value = _storage.GetValue(id.ContextId); - + if (value == null) { throw new NullReferenceException("Cannot find that object. It is null"); diff --git a/mROA/Implementation/Backend/MultiClientContextRepository.cs b/mROA/Implementation/Backend/MultiClientContextRepository.cs index 9078788..065c746 100644 --- a/mROA/Implementation/Backend/MultiClientContextRepository.cs +++ b/mROA/Implementation/Backend/MultiClientContextRepository.cs @@ -31,7 +31,7 @@ namespace mROA.Implementation.Backend var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); repository.ClearObject(id); } - + public T GetObject(ComplexObjectIdentifier id) { var repository = GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()); diff --git a/mROA/Implementation/CancellationRepository.cs b/mROA/Implementation/CancellationRepository.cs index 3c5659e..d6543aa 100644 --- a/mROA/Implementation/CancellationRepository.cs +++ b/mROA/Implementation/CancellationRepository.cs @@ -7,7 +7,8 @@ namespace mROA.Implementation { public class CancellationRepository : ICancellationRepository { - private Dictionary _cancellations = new(); + private Dictionary _cancellations = new(); + public void RegisterCancellation(Guid id, CancellationTokenSource cts) { _cancellations.TryAdd(id, cts); @@ -25,7 +26,6 @@ namespace mROA.Implementation public void Inject(T dependency) { - } } } \ No newline at end of file diff --git a/mROA/Implementation/ComplexObjectIdentifier.cs b/mROA/Implementation/ComplexObjectIdentifier.cs index 37d87a2..d95d378 100644 --- a/mROA/Implementation/ComplexObjectIdentifier.cs +++ b/mROA/Implementation/ComplexObjectIdentifier.cs @@ -7,11 +7,13 @@ namespace mROA.Implementation { 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 }; @@ -20,6 +22,7 @@ namespace mROA.Implementation 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} }}"; diff --git a/mROA/Implementation/CreativeRepresentationModuleProducer.cs b/mROA/Implementation/CreativeRepresentationModuleProducer.cs index 5ac35cc..0e21899 100644 --- a/mROA/Implementation/CreativeRepresentationModuleProducer.cs +++ b/mROA/Implementation/CreativeRepresentationModuleProducer.cs @@ -36,7 +36,7 @@ namespace mROA.Implementation var interaction = _hub.GetInteracion(id); produced.Inject(interaction); - + return produced; } } diff --git a/mROA/Implementation/ExtensibleStorage.cs b/mROA/Implementation/ExtensibleStorage.cs index a9c6d18..6543519 100644 --- a/mROA/Implementation/ExtensibleStorage.cs +++ b/mROA/Implementation/ExtensibleStorage.cs @@ -18,6 +18,7 @@ namespace mROA.Implementation { return null; } + return _array[index]; } diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 2bff07f..4efe1fd 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -36,13 +36,14 @@ namespace mROA.Implementation.Frontend 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()}"); + throw new Exception( + $"Incorrect message type. Must be IdAssigning, current : {welcomeMessage.SchemaId.ToString()}"); } diff --git a/mROA/Implementation/Frontend/RemoteException.cs b/mROA/Implementation/Frontend/RemoteException.cs index 093d9c1..e63e8b3 100644 --- a/mROA/Implementation/Frontend/RemoteException.cs +++ b/mROA/Implementation/Frontend/RemoteException.cs @@ -2,7 +2,7 @@ namespace mROA.Implementation.Frontend { - public class RemoteException : Exception + public class RemoteException : Exception { public Guid CallRequestId; private readonly string _error; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 0788ba9..baf6be3 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -58,7 +58,7 @@ namespace mROA.Implementation.Frontend throw new NullReferenceException("Representation module is null."); if (_methodRepository == null) throw new NullReferenceException("Method repository is null."); - + var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); @@ -134,4 +134,4 @@ namespace mROA.Implementation.Frontend }); } } -} +} \ No newline at end of file diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index dd71589..9522bea 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json.Serialization; + // ReSharper disable UnusedMember.Global namespace mROA.Implementation @@ -7,6 +8,7 @@ namespace mROA.Implementation public class NetworkMessage { public Guid Id { get; set; } + [JsonConverter(typeof(JsonStringEnumConverter))] public MessageType SchemaId { get; set; } @@ -15,6 +17,13 @@ namespace mROA.Implementation public enum MessageType { - Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCommandExecution, CallRequest, IdAssigning, CancelRequest, EventRequest + Unknown, + FinishedCommandExecution, + ExceptionCommandExecution, + AsyncCommandExecution, + CallRequest, + IdAssigning, + CancelRequest, + EventRequest } } \ No newline at end of file diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index 733c921..f7ece15 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -51,7 +51,7 @@ namespace mROA.Implementation var rawMessage = _serialization.Serialize(message); var header = BitConverter.GetBytes((ushort)rawMessage.Length).AsMemory(0, sizeof(ushort)); - + await BaseStream.WriteAsync(header); await BaseStream.WriteAsync(rawMessage); } diff --git a/mROA/Implementation/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index f5d734d..8c8ded5 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -46,7 +46,7 @@ namespace mROA.Implementation { if (_representationProducer == null) throw new NullReferenceException("representation producer is not initialized"); - + var representationModule = _representationProducer.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()); diff --git a/mROA/Implementation/StaticRepresentationModuleProducer.cs b/mROA/Implementation/StaticRepresentationModuleProducer.cs index 188bfec..8aeabd4 100644 --- a/mROA/Implementation/StaticRepresentationModuleProducer.cs +++ b/mROA/Implementation/StaticRepresentationModuleProducer.cs @@ -6,14 +6,14 @@ namespace mROA.Implementation public class StaticRepresentationModuleProducer : IRepresentationModuleProducer { private IRepresentationModule? _representationModule; - + public IRepresentationModule Produce(int ownership) { if (_representationModule == null) throw new NullReferenceException("The representation module is not initialized."); return _representationModule; } - + public void Inject(T dependency) { if (dependency is IRepresentationModule serialisationModule) diff --git a/mROA/LegacyExtentions.cs b/mROA/LegacyExtentions.cs index d0a3b29..ed05e04 100644 --- a/mROA/LegacyExtentions.cs +++ b/mROA/LegacyExtentions.cs @@ -36,6 +36,7 @@ namespace mROA return totalRead; } } + return totalRead; } } diff --git a/mROA/mROA.csproj b/mROA/mROA.csproj index e62894c..5c9aea9 100644 --- a/mROA/mROA.csproj +++ b/mROA/mROA.csproj @@ -17,7 +17,7 @@ - + @@ -25,7 +25,7 @@ - + From 2dbfdce254f10df65103f1dddd33c9081ba385eb Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 20:30:02 +0300 Subject: [PATCH 59/66] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=20=D1=8D=D0=BA=D1=81=D1=82=D1=80=D0=B0=D0=BA?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B0=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Backend/BasicExecutionModule.cs | 57 ++++++++------ .../Frontend/RequestExtractor.cs | 77 +++++++++++-------- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index e36ac30..21e4663 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -36,38 +36,19 @@ namespace mROA.Implementation.Backend try { - 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"); - + ThrowIfNotInjected(contextRepository); if (command is CancelRequest) { #if TRACE Console.WriteLine("Final cancelling request"); #endif - 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 - }; + CancelExecution(command); } - var invoker = _methodRepo.GetMethod(command.CommandId); + var invoker = _methodRepo!.GetMethod(command.CommandId); if (invoker == null) throw new Exception($"Command {command.CommandId} not found"); - IContextRepository repository; - var context = command.ObjectId.ContextId != -1 ? contextRepository.GetObject(command.ObjectId) : contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId); @@ -83,7 +64,7 @@ namespace mROA.Implementation.Backend castedParams = new object[invoker.ParameterTypes.Length]; for (var i = 0; i < castedParams.Length; i++) { - castedParams[i] = _serialization.Cast(command.Parameters![i], invoker.ParameterTypes[i]); + castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i]); } } @@ -93,10 +74,10 @@ namespace mROA.Implementation.Backend { case AsyncMethodInvoker { IsVoid: false } asyncNonVoidMethodInvoker: return TypedExecuteAsync(asyncNonVoidMethodInvoker, context, castedParams, command, - _cancellationRepo, + _cancellationRepo!, representationModule, execContext); case AsyncMethodInvoker asyncMethodInvoker: - return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo, + return ExecuteAsync(asyncMethodInvoker, context, castedParams, command, _cancellationRepo!, representationModule, execContext); default: var result = Execute((invoker as MethodInvoker)!, context, castedParams!, command, execContext); @@ -121,6 +102,32 @@ namespace mROA.Implementation.Backend } } + 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 + }; + } + private static ICommandExecution Execute(MethodInvoker invoker, object instance, object?[] parameter, ICallRequest command, RequestContext executionContext) { diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index baf6be3..83aecb1 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -48,17 +48,7 @@ namespace mROA.Implementation.Frontend { return Task.Run(() => { - 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."); - + ThrowIfNotInjected(); var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository; multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id); @@ -99,31 +89,15 @@ namespace mROA.Implementation.Frontend #if TRACE Console.WriteLine("Cancelling request"); #endif - var req = cancelRequest.Result; - tokenSource.Cancel(); - _executeModule.Execute(req, _realContextRepository, _representationModule); + HandleCancelRequest(tokenSource, cancelRequest.Result); } else if (defaultRequest.IsCompleted) { - tokenSource.Cancel(); - var request = defaultRequest.Result; - - var result = _executeModule.Execute(request, _realContextRepository, _representationModule); - - var resultType = result switch - { - FinalCommandExecution => MessageType.FinishedCommandExecution, - AsyncCommandExecution => MessageType.AsyncCommandExecution, - ExceptionCommandExecution => MessageType.ExceptionCommandExecution, - _ => MessageType.Unknown - }; - _representationModule.PostCallMessage(request.Id, resultType, result, result.GetType()); + HandleCallRequest(tokenSource, defaultRequest.Result); } else { - tokenSource.Cancel(); - var request = eventRequest.Result; - _executeModule.Execute(request, _remoteContextRepository!, _representationModule); + HandleEventRequest(tokenSource, eventRequest.Result); } } } @@ -133,5 +107,48 @@ namespace mROA.Implementation.Frontend } }); } + + 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, + AsyncCommandExecution => MessageType.AsyncCommandExecution, + ExceptionCommandExecution => MessageType.ExceptionCommandExecution, + _ => MessageType.Unknown + }; + + _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 From b366ca26ccbd534328d1f26204febfa1b8b590c7 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 20:36:05 +0300 Subject: [PATCH 60/66] =?UTF-8?q?=D0=94=D0=BE=D0=BF=D0=BE=D0=BB=D0=BD?= =?UTF-8?q?=D0=B8=D1=82=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D1=80=D0=B5?= =?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BC?= =?UTF-8?q?=D0=BE=D0=B4=D1=83=D0=BB=D1=8F=20=D0=B2=D1=8B=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Backend/BasicExecutionModule.cs | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/mROA/Implementation/Backend/BasicExecutionModule.cs b/mROA/Implementation/Backend/BasicExecutionModule.cs index 21e4663..25b96c1 100644 --- a/mROA/Implementation/Backend/BasicExecutionModule.cs +++ b/mROA/Implementation/Backend/BasicExecutionModule.cs @@ -42,16 +42,14 @@ namespace mROA.Implementation.Backend #if TRACE Console.WriteLine("Final cancelling request"); #endif - CancelExecution(command); + return CancelExecution(command); } var invoker = _methodRepo!.GetMethod(command.CommandId); if (invoker == null) throw new Exception($"Command {command.CommandId} not found"); - var context = command.ObjectId.ContextId != -1 - ? contextRepository.GetObject(command.ObjectId) - : contextRepository.GetSingleObject(invoker.SuitableType, command.ObjectId.OwnerId); + var context = GetContext(command, contextRepository, invoker); if (context == null) throw new NullReferenceException("Instance can't be null"); @@ -60,13 +58,8 @@ namespace mROA.Implementation.Backend object?[]? castedParams = null; if (invoker.ParameterTypes.Length != 0) - { - castedParams = new object[invoker.ParameterTypes.Length]; - for (var i = 0; i < castedParams.Length; i++) - { - castedParams[i] = _serialization!.Cast(command.Parameters![i], invoker.ParameterTypes[i]); - } - } + castedParams = CastedParams(command, invoker); + var execContext = new RequestContext(command.Id, representationModule.Id); @@ -102,6 +95,25 @@ namespace mROA.Implementation.Backend } } + 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) @@ -127,7 +139,7 @@ namespace mROA.Implementation.Backend Id = command.Id }; } - + private static ICommandExecution Execute(MethodInvoker invoker, object instance, object?[] parameter, ICallRequest command, RequestContext executionContext) { From 3af2e66c837c3ae263bb4838a4930bf6c62717f5 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Mar 2025 21:35:37 +0300 Subject: [PATCH 61/66] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82?= =?UTF-8?q?=D0=BE=D1=80=D0=B8=D0=BD=D0=B3=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?= =?UTF-8?q?=D0=B5=D0=B9=20=D1=81=D0=B5=D1=82=D0=B5=D0=B2=D0=BE=D0=B3=D0=BE?= =?UTF-8?q?=20=D1=88=D0=BB=D1=8E=D0=B7=D0=B0=20=D0=B8=20=D1=85=D0=B0=D0=B1?= =?UTF-8?q?=D0=B0=20=D1=8D=D0=BA=D1=81=D1=82=D1=80=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Backend/HubRequestExtractor.cs | 8 ++- .../Backend/NetworkGatewayModule.cs | 49 ++++++++++--------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/mROA/Implementation/Backend/HubRequestExtractor.cs b/mROA/Implementation/Backend/HubRequestExtractor.cs index 4754761..6529c6c 100644 --- a/mROA/Implementation/Backend/HubRequestExtractor.cs +++ b/mROA/Implementation/Backend/HubRequestExtractor.cs @@ -47,6 +47,12 @@ namespace mROA.Implementation.Backend } 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); @@ -58,7 +64,7 @@ namespace mROA.Implementation.Backend extractor.Inject(_serializationToolkit); extractor.Inject(_executeModule); extractor.Inject(_remoteContextRepository); - _ = extractor.StartExtraction(); + return extractor; } } } \ No newline at end of file diff --git a/mROA/Implementation/Backend/NetworkGatewayModule.cs b/mROA/Implementation/Backend/NetworkGatewayModule.cs index 61e19c7..d7bf45d 100644 --- a/mROA/Implementation/Backend/NetworkGatewayModule.cs +++ b/mROA/Implementation/Backend/NetworkGatewayModule.cs @@ -59,6 +59,33 @@ namespace mROA.Implementation.Backend } 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"); @@ -70,28 +97,6 @@ namespace mROA.Implementation.Backend throw new NullReferenceException("InteractionModuleType is null"); if (_serialization is null) throw new NullReferenceException("Serialization is null"); - - 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"); - } } } } \ No newline at end of file From b7c611a76e4bf619d28f85f46c9fad1bc3255e8a Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 14 Mar 2025 13:15:04 +0300 Subject: [PATCH 62/66] =?UTF-8?q?=D0=A4=D0=B8=D0=BA=D1=81=20=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B0=D0=B2=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=20=D0=BD=D0=B0=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=D0=B4=D0=B5=D0=BD=D1=82=D0=B8=D1=84=D0=B8=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D0=B0=20=D0=BC=D0=BE=D0=B4=D1=83=D0=BB?= =?UTF-8?q?=D1=8F=20=D0=B2=D0=B7=D0=B0=D0=B8=D0=BC=D0=BE=D0=B4=D0=B5=D0=B9?= =?UTF-8?q?=D1=81=D1=82=D0=B2=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Implementation/Frontend/NetworkFrontendBridge.cs | 3 ++- mROA/Implementation/NextGenerationInteractionModule.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs index 4efe1fd..8bd0aba 100644 --- a/mROA/Implementation/Frontend/NetworkFrontendBridge.cs +++ b/mROA/Implementation/Frontend/NetworkFrontendBridge.cs @@ -7,10 +7,10 @@ namespace mROA.Implementation.Frontend { public class NetworkFrontendBridge : IFrontendBridge { + private readonly IPEndPoint _ipEndPoint; private readonly TcpClient _tcpClient = new(); private NextGenerationInteractionModule? _interactionModule; private ISerializationToolkit? _serialization; - private readonly IPEndPoint _ipEndPoint; public NetworkFrontendBridge(IPEndPoint ipEndPoint) { @@ -48,6 +48,7 @@ namespace mROA.Implementation.Frontend var assignment = _serialization.Deserialize(welcomeMessage.Data)!; + _interactionModule.ConnectionId = -assignment.Id; TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(assignment.Id); } } diff --git a/mROA/Implementation/NextGenerationInteractionModule.cs b/mROA/Implementation/NextGenerationInteractionModule.cs index f7ece15..2aa7163 100644 --- a/mROA/Implementation/NextGenerationInteractionModule.cs +++ b/mROA/Implementation/NextGenerationInteractionModule.cs @@ -14,7 +14,7 @@ namespace mROA.Implementation private readonly List _messageBuffer = new(128); private Task? _currentReceiving; private ISerializationToolkit? _serialization; - public int ConnectionId { get; private set; } + public int ConnectionId { get; set; } public Stream? BaseStream { get; set; } From eca927eb214de812cee0c91aa38dfe1e23b5e922 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 14 Mar 2025 13:29:28 +0300 Subject: [PATCH 63/66] =?UTF-8?q?=D0=91=D0=BE=D0=BB=D0=B5=D0=B5=20=D1=82?= =?UTF-8?q?=D0=BE=D1=87=D0=BD=D0=BE=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D1=80?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D1=80=D0=B5=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=20=D0=BE=D0=B1=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Implementation/Frontend/RequestExtractor.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 83aecb1..032a682 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -11,10 +11,10 @@ namespace mROA.Implementation.Frontend { public class RequestExtractor : IRequestExtractor { - private IContextRepository? _realContextRepository; - private IContextRepository? _remoteContextRepository; private IExecuteModule? _executeModule; private IMethodRepository? _methodRepository; + private IContextRepository? _realContextRepository; + private IContextRepository? _remoteContextRepository; private IRepresentationModule? _representationModule; private ISerializationToolkit? _serializationToolkit; @@ -65,7 +65,7 @@ namespace mROA.Implementation.Frontend if (sw.IsRunning) { sw.Stop(); - Console.WriteLine($"Request handling took {sw.ElapsedMilliseconds} milliseconds."); + Console.WriteLine($"Request handling took {Math.Round(sw.Elapsed.TotalMilliseconds * 1000.0)} microseconds."); } #endif var tokenSource = new CancellationTokenSource(); @@ -121,7 +121,7 @@ namespace mROA.Implementation.Frontend if (_methodRepository == null) throw new NullReferenceException("Method repository is null."); } - + private void HandleCancelRequest(CancellationTokenSource tokenSource, CancelRequest req) { tokenSource.Cancel(); @@ -141,7 +141,7 @@ namespace mROA.Implementation.Frontend ExceptionCommandExecution => MessageType.ExceptionCommandExecution, _ => MessageType.Unknown }; - + _representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType()); } From 481afd1c4d06864c3133e1093cd4784147e81423 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 14 Mar 2025 13:36:49 +0300 Subject: [PATCH 64/66] =?UTF-8?q?=D0=A3=D0=B4=D0=B0=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B0=D1=81=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD?= =?UTF-8?q?=D0=BD=D0=BE=D0=B3=D0=BE=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C?= =?UTF-8?q?=D1=82=D0=B0=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mROA/Implementation/Frontend/RequestExtractor.cs | 5 ++++- mROA/Implementation/NetworkMessage.cs | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index 032a682..c810cb1 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -137,10 +137,13 @@ namespace mROA.Implementation.Frontend var resultType = result switch { FinalCommandExecution => MessageType.FinishedCommandExecution, - AsyncCommandExecution => MessageType.AsyncCommandExecution, ExceptionCommandExecution => MessageType.ExceptionCommandExecution, _ => MessageType.Unknown }; + if (resultType == MessageType.Unknown) + { + return; + } _representationModule!.PostCallMessage(request.Id, resultType, result, result.GetType()); } diff --git a/mROA/Implementation/NetworkMessage.cs b/mROA/Implementation/NetworkMessage.cs index 9522bea..e610586 100644 --- a/mROA/Implementation/NetworkMessage.cs +++ b/mROA/Implementation/NetworkMessage.cs @@ -20,7 +20,6 @@ namespace mROA.Implementation Unknown, FinishedCommandExecution, ExceptionCommandExecution, - AsyncCommandExecution, CallRequest, IdAssigning, CancelRequest, From f1f5007ae63b025eaa307ec1b7413616a72e8025 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Fri, 14 Mar 2025 21:21:57 +0300 Subject: [PATCH 65/66] =?UTF-8?q?=D0=9A=D1=80=D0=B8=D1=82=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=BE=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=20=D0=BA=D0=BE=D0=B4=D0=B3?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/CsTest.cs | 17 ----------------- Example.Backend/Printer.cs | 2 +- mROA.Codegen/mROASourceGenerator.cs | 2 +- .../Implementation/Frontend/RequestExtractor.cs | 1 + 4 files changed, 3 insertions(+), 19 deletions(-) delete mode 100644 Example.Backend/CsTest.cs diff --git a/Example.Backend/CsTest.cs b/Example.Backend/CsTest.cs deleted file mode 100644 index ac30cb4..0000000 --- a/Example.Backend/CsTest.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Example.Shared; - -namespace Example.Backend -{ - public class CsTest - { - public T FinalCasted(IDataList list, int index) - { - return list.Get(index); - } - - public object NonCasted(object list, int index) - { - return FinalCasted(list as IDataList, index); - } - } -} \ No newline at end of file diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index f4073bf..eba0d19 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -27,7 +27,7 @@ namespace Example.Backend // 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); + OnPrint?.Invoke(page, new RequestContext(Guid.NewGuid(), 132)); Resource /= 1.5; return page; } diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index b58c2de..25609fb 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -482,7 +482,7 @@ namespace {classSymbol.ContainingNamespace.ToDisplayString()} Console.WriteLine(""Sending event...""); var request = new DefaultCallRequest {{ - CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, context.HostId), Parameters = new object[] {{ {transferParameters} }} + CommandId = {index}, ObjectId = new ComplexObjectIdentifier(index, ownerId), Parameters = new object[] {{ {transferParameters} }} }}; module.PostCallMessageAsync(request.Id, MessageType.EventRequest, request); }}; diff --git a/mROA/Implementation/Frontend/RequestExtractor.cs b/mROA/Implementation/Frontend/RequestExtractor.cs index c810cb1..0cc961a 100644 --- a/mROA/Implementation/Frontend/RequestExtractor.cs +++ b/mROA/Implementation/Frontend/RequestExtractor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading; using System.Threading.Tasks; using mROA.Abstract; From a6c743c78b8c44845f3bd6078d5d4b70fcc03a55 Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Tue, 18 Mar 2025 23:08:14 +0300 Subject: [PATCH 66/66] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D1=8B=D0=B9=20=D0=BF?= =?UTF-8?q?=D1=80=D0=BE=D0=B5=D0=BA=D1=82=20=D0=B4=D0=BB=D1=8F=20codegen-t?= =?UTF-8?q?ools?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/Printer.cs | 3 ++- mROA.CodegenTools/mROA.CodegenTools.csproj | 7 +++++++ mROA.sln | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 mROA.CodegenTools/mROA.CodegenTools.csproj diff --git a/Example.Backend/Printer.cs b/Example.Backend/Printer.cs index eba0d19..87958c9 100644 --- a/Example.Backend/Printer.cs +++ b/Example.Backend/Printer.cs @@ -12,6 +12,7 @@ namespace Example.Backend public void OnPrintExternal(IPage p0, RequestContext ro) { + OnPrint?.Invoke(p0, ro); } public double Resource { get; set; } = 100d; @@ -27,7 +28,7 @@ namespace Example.Backend // 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, new RequestContext(Guid.NewGuid(), 132)); + OnPrint?.Invoke(page, context); Resource /= 1.5; return page; } 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.sln b/mROA.sln index 1cfa5fa..6ca35dc 100644 --- a/mROA.sln +++ b/mROA.sln @@ -31,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Events.Backend", "E 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 @@ -81,6 +83,10 @@ Global {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