From e5253138dbe2dbd53aba689647f7c6cc9573e6bf Mon Sep 17 00:00:00 2001 From: Mikhail Mitrofanov Date: Thu, 13 Feb 2025 19:38:54 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B5=D1=89=D0=B5=20=D0=BE=D0=B4=D0=B8=D0=BD?= =?UTF-8?q?=20=D1=88=D0=B0=D0=B3=20=D0=B4=D0=BE=20=D0=BF=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=D0=B4=D0=BD=D0=B5=D0=B3=D0=BE=20=D1=88=D0=B0=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Example.Backend/PrinterFactory.cs | 14 +++++++++- Example.Backend/Program.cs | 20 +++++++------- Example.Frontend/ClientBasedPrinter.cs | 27 +++++++++++++++++++ Example.Frontend/Program.cs | 15 ++++++++--- Example.Shared/IPrinterFactory.cs | 2 ++ mROA.Codegen/mROASourceGenerator.cs | 1 + mROA/Abstract/IInteractionModule.cs | 1 + mROA/Abstract/IRemoteObject.cs | 1 + mROA/Abstract/ISerialisationModule.cs | 1 + mROA/Abstract/ISerialisationModuleProducer.cs | 8 ++++++ .../Backend/MultiClientOwnershipRepository.cs | 2 +- .../Backend/StreamBasedInteractionModule.cs | 1 + .../JsonFrontendSerialisationModule.cs | 2 ++ .../StreamBasedFrontendInteractionModule.cs | 8 +++--- .../Implementation/RemoteContextRepository.cs | 9 ++++--- mROA/Implementation/SharedObject.cs | 25 ++++++++++------- .../StaticSerialisationModuleProducer.cs | 19 +++++++++++++ 17 files changed, 125 insertions(+), 31 deletions(-) create mode 100644 Example.Frontend/ClientBasedPrinter.cs create mode 100644 mROA/Abstract/ISerialisationModuleProducer.cs create mode 100644 mROA/Implementation/StaticSerialisationModuleProducer.cs diff --git a/Example.Backend/PrinterFactory.cs b/Example.Backend/PrinterFactory.cs index 99d8150..be94843 100644 --- a/Example.Backend/PrinterFactory.cs +++ b/Example.Backend/PrinterFactory.cs @@ -8,8 +8,20 @@ namespace Example.Backend; [SharedObjectSingleton] public class PrinterFactory : IPrinterFactory { + private List _printers = new(); + public SharedObject Create(string printerName) { - return new Printer {Name = printerName}; + return new Printer { Name = printerName }; + } + + public void Register(SharedObject printer) + { + _printers.Add(printer.Value); + } + + public SharedObject GetPrinterByName(string printerName) + { + return new SharedObject(_printers.Find(i => i.GetName() == printerName)!); } } \ No newline at end of file diff --git a/Example.Backend/Program.cs b/Example.Backend/Program.cs index 79c299c..0d019ca 100644 --- a/Example.Backend/Program.cs +++ b/Example.Backend/Program.cs @@ -7,16 +7,18 @@ using mROA.Implementation.Backend; using mROA.Implementation.Bootstrap; -var bootstrap = new FullMixBuilder(); -bootstrap.UseJsonSerialisation(); -bootstrap.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567)); -bootstrap.UseStreamInteraction(); -bootstrap.UseBasicExecution(); -bootstrap.UseCollectableContextRepository(typeof(PrinterFactory).Assembly); -bootstrap.SetupMethodsRepository(new CoCodegenMethodRepository()); -bootstrap.Build(); +var builder = new FullMixBuilder(); +builder.UseJsonSerialisation(); +builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567)); +builder.UseStreamInteraction(); +builder.UseBasicExecution(); +builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly); +builder.SetupMethodsRepository(new CoCodegenMethodRepository()); +builder.Modules.Add(new StaticSerialisationModuleProducer()); + +builder.Build(); -var gateway = bootstrap.GetModule() ; +var gateway = builder.GetModule() ; gateway.Run(); \ No newline at end of file diff --git a/Example.Frontend/ClientBasedPrinter.cs b/Example.Frontend/ClientBasedPrinter.cs new file mode 100644 index 0000000..18daf1a --- /dev/null +++ b/Example.Frontend/ClientBasedPrinter.cs @@ -0,0 +1,27 @@ +using Example.Shared; +using mROA.Implementation; + +namespace Example.Frontend; + +public class ClientBasedPrinter : IPrinter +{ + public string GetName() + { + return "ClientBasedPrinter"; + } + + public async Task> Print(string text, CancellationToken cancellationToken) + { + Console.WriteLine($"Printed: {text}"); + await Task.Yield(); + return new ClientBasedPage(); + } +} + +public class ClientBasedPage : IPage +{ + public byte[] GetData() + { + return [1, 2, 3]; + } +} \ No newline at end of file diff --git a/Example.Frontend/Program.cs b/Example.Frontend/Program.cs index 48d04c0..670e075 100644 --- a/Example.Frontend/Program.cs +++ b/Example.Frontend/Program.cs @@ -4,9 +4,11 @@ using System.Diagnostics; using System.Net; using System.Text; +using Example.Frontend; using Example.Shared; using mROA.Codegen; using mROA.Implementation; +using mROA.Implementation.Backend; using mROA.Implementation.Bootstrap; using mROA.Implementation.Frontend; @@ -17,22 +19,26 @@ mixer.Modules.Add(new RemoteContextRepository()); mixer.Modules.Add(new JsonFrontendSerialisationModule()); mixer.Modules.Add(new StreamBasedFrontendInteractionModule()); mixer.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567))); +mixer.Modules.Add(new StaticSerialisationModuleProducer()); +mixer.UseCollectableContextRepository(); mixer.Build(); -Thread.CurrentThread.ManagedThreadId -TransmissionConfig.RealContextRepository = mixer.GetModule(); + +TransmissionConfig.RealContextRepository = mixer.GetModule(); TransmissionConfig.RemoteEndpointContextRepository = mixer.GetModule(); mixer.GetModule().Connect(); -Console.WriteLine(TransmissionConfig.ProcessOwnerId); +Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); var context = mixer.GetModule(); var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory; - var printer = factory.Create("Test"); var name = printer.Value.GetName(); Console.WriteLine("Printer name : {0}", name); + +factory.Register(new SharedObject(new ClientBasedPrinter())); + var page = await printer.Value.Print("Test Page", new CancellationToken()); var data = page.Value.GetData(); Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); @@ -46,6 +52,7 @@ 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); \ No newline at end of file diff --git a/Example.Shared/IPrinterFactory.cs b/Example.Shared/IPrinterFactory.cs index 73a4e93..c937ed9 100644 --- a/Example.Shared/IPrinterFactory.cs +++ b/Example.Shared/IPrinterFactory.cs @@ -8,5 +8,7 @@ namespace Example.Shared; public interface IPrinterFactory { SharedObject Create(string printerName); + void Register(SharedObject printer); + SharedObject GetPrinterByName(string printerName); } diff --git a/mROA.Codegen/mROASourceGenerator.cs b/mROA.Codegen/mROASourceGenerator.cs index f9cbd4d..0d7fe19 100644 --- a/mROA.Codegen/mROASourceGenerator.cs +++ b/mROA.Codegen/mROASourceGenerator.cs @@ -187,6 +187,7 @@ namespace {namespaceName}; partial class {className} (int id, ISerialisationModule.IFrontendSerialisationModule serialisationModule) : {originalName}, IRemoteObject {{ public int Id => id; + public int OwnerId => serialisationModule.ClientId; {string.Join("\r\n\t", methodsText)} }} diff --git a/mROA/Abstract/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs index 635f20d..127ab65 100644 --- a/mROA/Abstract/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -6,6 +6,7 @@ public interface IInteractionModule : IInjectableModule void RegisterSource(Stream stream); public interface IFrontendInteractionModule : IInjectableModule { + int ClientId { get; } public Task ReceiveMessage(); public void PostMessage(byte[] message); } diff --git a/mROA/Abstract/IRemoteObject.cs b/mROA/Abstract/IRemoteObject.cs index 9dc28ce..1c1d0f1 100644 --- a/mROA/Abstract/IRemoteObject.cs +++ b/mROA/Abstract/IRemoteObject.cs @@ -3,4 +3,5 @@ public interface IRemoteObject { public int Id { get; } + public int OwnerId { get; } } \ No newline at end of file diff --git a/mROA/Abstract/ISerialisationModule.cs b/mROA/Abstract/ISerialisationModule.cs index fa3f26f..7ce2124 100644 --- a/mROA/Abstract/ISerialisationModule.cs +++ b/mROA/Abstract/ISerialisationModule.cs @@ -9,6 +9,7 @@ public interface ISerialisationModule : IInjectableModule void SendWelcomeMessage(int clientId); public interface IFrontendSerialisationModule : IInjectableModule { + int ClientId { get; } Task GetNextCommandExecution(Guid requestId) where T : ICommandExecution; Task> GetFinalCommandExecution(Guid requestId); diff --git a/mROA/Abstract/ISerialisationModuleProducer.cs b/mROA/Abstract/ISerialisationModuleProducer.cs new file mode 100644 index 0000000..71a7d34 --- /dev/null +++ b/mROA/Abstract/ISerialisationModuleProducer.cs @@ -0,0 +1,8 @@ +using mROA.Abstract; + +namespace mROA.Implementation; + +interface ISerialisationModuleProducer : IInjectableModule +{ + ISerialisationModule.IFrontendSerialisationModule Produce(int ownership); +} \ No newline at end of file diff --git a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs index aea7194..170cc3c 100644 --- a/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs +++ b/mROA/Implementation/Backend/MultiClientOwnershipRepository.cs @@ -8,7 +8,7 @@ public class MultiClientOwnershipRepository : IOwnershipRepository public int GetOwnershipId() { - return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, -1); + return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0); } public void RegisterOwnership(int ownershipId, int threadId) diff --git a/mROA/Implementation/Backend/StreamBasedInteractionModule.cs b/mROA/Implementation/Backend/StreamBasedInteractionModule.cs index faf3a11..04a2e7f 100644 --- a/mROA/Implementation/Backend/StreamBasedInteractionModule.cs +++ b/mROA/Implementation/Backend/StreamBasedInteractionModule.cs @@ -29,6 +29,7 @@ public class StreamBasedInteractionModule : IInteractionModule private async Task ListenTo((int id, Stream stream) client, Action action) { + TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository(); const int bufferSize = ushort.MaxValue; try { diff --git a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs index ea3f9d8..efc057c 100644 --- a/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs +++ b/mROA/Implementation/Frontend/JsonFrontendSerialisationModule.cs @@ -9,6 +9,8 @@ public class JsonFrontendSerialisationModule { private IInteractionModule.IFrontendInteractionModule? _interactionModule; + public int ClientId => _interactionModule!.ClientId; + public async Task GetNextCommandExecution(Guid requestId) where T : ICommandExecution { if (_interactionModule is null) diff --git a/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs b/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs index 6b63246..0426264 100644 --- a/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs +++ b/mROA/Implementation/Frontend/StreamBasedFrontendInteractionModule.cs @@ -6,11 +6,13 @@ public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontend { public Stream? ServerStream { get; set; } + public int ClientId { get; set; } + 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]; @@ -27,12 +29,12 @@ public class StreamBasedFrontendInteractionModule : IInteractionModule.IFrontend { 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/RemoteContextRepository.cs b/mROA/Implementation/RemoteContextRepository.cs index e29672e..670a565 100644 --- a/mROA/Implementation/RemoteContextRepository.cs +++ b/mROA/Implementation/RemoteContextRepository.cs @@ -6,7 +6,8 @@ namespace mROA.Implementation; public class RemoteContextRepository : IContextRepository { - private ISerialisationModule.IFrontendSerialisationModule _serialisationModule; + private ISerialisationModuleProducer _serialisationModule; + private ISerialisationModuleProducer _producer; public static FrozenDictionary RemoteTypes; public int ResisterObject(object o) { @@ -27,7 +28,7 @@ public class RemoteContextRepository : IContextRepository { if (RemoteTypes.TryGetValue(typeof(T), out var remoteType)) { - var remote = (T)Activator.CreateInstance(remoteType, id, _serialisationModule)!; + var remote = (T)Activator.CreateInstance(remoteType, id, _serialisationModule.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; return remote; } throw new NotSupportedException(); @@ -35,7 +36,7 @@ public class RemoteContextRepository : IContextRepository public object GetSingleObject(Type type) { - return Activator.CreateInstance(RemoteTypes[type], -1, _serialisationModule)!; + return Activator.CreateInstance(RemoteTypes[type], -1, _serialisationModule.Produce(TransmissionConfig.OwnershipRepository.GetOwnershipId()))!; } public int GetObjectIndex(object o) @@ -49,7 +50,7 @@ public class RemoteContextRepository : IContextRepository public void Inject(T dependency) { - if (dependency is ISerialisationModule.IFrontendSerialisationModule serialisationModule) + if (dependency is ISerialisationModuleProducer serialisationModule) _serialisationModule = serialisationModule; } } \ No newline at end of file diff --git a/mROA/Implementation/SharedObject.cs b/mROA/Implementation/SharedObject.cs index d26e22c..a8378e4 100644 --- a/mROA/Implementation/SharedObject.cs +++ b/mROA/Implementation/SharedObject.cs @@ -8,7 +8,6 @@ public static class TransmissionConfig public static IContextRepository? RealContextRepository { get; set; } public static IContextRepository? RemoteEndpointContextRepository { get; set; } public static IOwnershipRepository? OwnershipRepository { get; set; } - public static Dictionary ThreadsOwners { get; } = new(); } public class SharedObject where T : notnull @@ -41,7 +40,8 @@ public class SharedObject where T : notnull } } - [JsonIgnore] public T Value { get; private set; } + [JsonIgnore] + public T Value { get; private set; } // ReSharper disable once MemberCanBePrivate.Global public SharedObject() @@ -52,16 +52,23 @@ public class SharedObject where T : notnull public SharedObject(T value) { Value = value; - _contextId = GetDefaultContextRepository().GetObjectIndex(value); + + if (value is IRemoteObject ro) + { + _ownerId = ro.OwnerId; + _contextId = ro.Id; + } + else + { + _contextId = TransmissionConfig.RealContextRepository!.GetObjectIndex(value); + _ownerId = TransmissionConfig.OwnershipRepository!.GetOwnershipId(); + } + + } public static implicit operator T(SharedObject value) => value.Value; public static implicit operator SharedObject(T value) => - new() - { - ContextId = value is IRemoteObject ro - ? TransmissionConfig.RemoteEndpointContextRepository!.GetObjectIndex(ro) - : TransmissionConfig.RealContextRepository!.GetObjectIndex(value) - }; + new(value); } \ No newline at end of file diff --git a/mROA/Implementation/StaticSerialisationModuleProducer.cs b/mROA/Implementation/StaticSerialisationModuleProducer.cs new file mode 100644 index 0000000..64ebe63 --- /dev/null +++ b/mROA/Implementation/StaticSerialisationModuleProducer.cs @@ -0,0 +1,19 @@ +using mROA.Abstract; + +namespace mROA.Implementation; + +public class StaticSerialisationModuleProducer : ISerialisationModuleProducer +{ + private ISerialisationModule.IFrontendSerialisationModule _serialisationModule; + + public ISerialisationModule.IFrontendSerialisationModule Produce(int ownership) + { + return _serialisationModule; + } + + public void Inject(T dependency) + { + if (dependency is ISerialisationModule.IFrontendSerialisationModule serialisationModule) + _serialisationModule = serialisationModule; + } +} \ No newline at end of file