билдится на старом дотнете

This commit is contained in:
2025-02-20 16:10:09 +03:00
parent 5af9408a9a
commit 50fd3e7b73
69 changed files with 1990 additions and 1675 deletions
+4 -2
View File
@@ -2,9 +2,11 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+21 -19
View File
@@ -1,28 +1,30 @@
using Example.Shared; using System;
using Example.Shared;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Backend; namespace Example.Backend
[SharedObjectSingleton]
public class LoadTestImp : ILoadTest
{ {
public int Next(int last) [SharedObjectSingleton]
public class LoadTestImp : ILoadTest
{ {
return last + 1; public int Next(int last)
} {
return last + 1;
}
public int Last(int next) public int Last(int next)
{ {
return next - 1; return next - 1;
} }
public void C() public void C()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void A() public void A()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
}
} }
} }
+7 -6
View File
@@ -1,13 +1,14 @@
using System.Text; using System.Text;
using Example.Shared; using Example.Shared;
namespace Example.Backend; namespace Example.Backend
public class Page : IPage
{ {
public string Text; public class Page : IPage
public byte[] GetData()
{ {
return Encoding.UTF8.GetBytes(Text); public string Text;
public byte[] GetData()
{
return Encoding.UTF8.GetBytes(Text);
}
} }
} }
+14 -12
View File
@@ -1,20 +1,22 @@
using System.Threading;
using System.Threading.Tasks;
using Example.Shared; using Example.Shared;
using mROA.Implementation; using mROA.Implementation;
namespace Example.Backend; namespace Example.Backend
public class Printer : IPrinter
{ {
public string Name; public class Printer : IPrinter
public string GetName()
{ {
return Name; public string Name;
} public string GetName()
{
return Name;
}
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken = default) public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken = default)
{ {
// throw new Exception("The method or operation is not implemented."); // throw new Exception("The method or operation is not implemented.");
return new Page {Text = text}; return new Page {Text = text};
}
} }
} }
+32 -28
View File
@@ -1,40 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Example.Shared; using Example.Shared;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Backend; namespace Example.Backend
[SharedObjectSingleton]
public class PrinterFactory : IPrinterFactory
{ {
private List<IPrinter> _printers = new(); [SharedObjectSingleton]
public class PrinterFactory : IPrinterFactory
public SharedObject<IPrinter> Create(string printerName)
{ {
Console.WriteLine("Creating printer"); private List<IPrinter> _printers = new List<IPrinter>();
return new Printer { Name = printerName };
}
public void Register(SharedObject<IPrinter> printer) public SharedObject<IPrinter> Create(string printerName)
{ {
_printers.Add(printer.Value); Console.WriteLine("Creating printer");
Console.WriteLine("Registered printer"); return new Printer { Name = printerName };
} }
public SharedObject<IPrinter> GetPrinterByName(string printerName) public void Register(SharedObject<IPrinter> printer)
{ {
Console.WriteLine("Getting printer"); _printers.Add(printer.Value);
return new SharedObject<IPrinter>(_printers.Find(i => i.GetName() == printerName)!); Console.WriteLine("Registered printer");
} }
public SharedObject<IPrinter> GetFirstPrinter() public SharedObject<IPrinter> GetPrinterByName(string printerName)
{ {
return new SharedObject<IPrinter>(_printers.First()); Console.WriteLine("Getting printer");
} return new SharedObject<IPrinter>(_printers.Find(i => i.GetName() == printerName)!);
}
public string[] CollectAllNames() public SharedObject<IPrinter> GetFirstPrinter()
{ {
Console.WriteLine("Collecting all printers"); return new SharedObject<IPrinter>(_printers.First());
return _printers.Select(i => i.GetName()).ToArray(); }
public string[] CollectAllNames()
{
Console.WriteLine("Collecting all printers");
return _printers.Select(i => i.GetName()).ToArray();
}
} }
} }
+35 -29
View File
@@ -7,37 +7,43 @@ using mROA.Implementation.Backend;
using mROA.Implementation.Bootstrap; using mROA.Implementation.Bootstrap;
using mROA.Implementation.Frontend; using mROA.Implementation.Frontend;
class Program
var builder = new FullMixBuilder();
builder.UseJsonSerialisation();
builder.Modules.Add(new BackendIdentityGenerator());
builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
builder.GetModule<IIdentityGenerator>()!);
builder.Modules.Add(new ConnectionHub());
builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
builder.UseBasicExecution();
builder.Modules.Add(new RemoteContextRepository());
// builder.UseCollectableContextRepository(typeof(PrinterFactory).Assembly);
builder.Modules.Add(new MultiClientContextRepository(i =>
{ {
var repo = new ContextRepository(); public static void Main(string[] args)
repo.FillSingletons(typeof(PrinterFactory).Assembly); {
return repo; var builder = new FullMixBuilder();
})); builder.UseJsonSerialisation();
builder.SetupMethodsRepository(new CoCodegenMethodRepository()); builder.Modules.Add(new BackendIdentityGenerator());
builder.Modules.Add(new CreativeRepresentationModuleProducer([builder.GetModule<JsonSerializationToolkit>()!], builder.UseNetworkGateway(new IPEndPoint(IPAddress.Loopback, 4567), typeof(NextGenerationInteractionModule),
typeof(RepresentationModule))); builder.GetModule<IIdentityGenerator>()!);
builder.Build(); builder.Modules.Add(new ConnectionHub());
new RemoteTypeBinder(); builder.Modules.Add(new HubRequestExtractor(typeof(RequestExtractor)));
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>(); builder.UseBasicExecution();
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
var gateway = builder.GetModule<IGatewayModule>(); 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<JsonSerializationToolkit>()! },
typeof(RepresentationModule)));
gateway.Run(); builder.Build();
new RemoteTypeBinder();
TransmissionConfig.RealContextRepository = builder.GetModule<MultiClientContextRepository>();
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
TransmissionConfig.OwnershipRepository = new MultiClientOwnershipRepository();
var gateway = builder.GetModule<IGatewayModule>();
gateway.Run();
}
}
+23 -19
View File
@@ -1,28 +1,32 @@
using Example.Shared; using System;
using System.Threading;
using System.Threading.Tasks;
using Example.Shared;
using mROA.Implementation; using mROA.Implementation;
namespace Example.Frontend; namespace Example.Frontend
public class ClientBasedPrinter : IPrinter
{ {
public string GetName() public class ClientBasedPrinter : IPrinter
{ {
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); public string GetName()
return "ClientBasedPrinter from mroa"; {
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)");
return "ClientBasedPrinter from mroa";
}
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken)
{
Console.WriteLine($"Printed: {text}");
await Task.Yield();
return new ClientBasedPage();
}
} }
public async Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken) public class ClientBasedPage : IPage
{ {
Console.WriteLine($"Printed: {text}"); public byte[] GetData()
await Task.Yield(); {
return new ClientBasedPage(); return new byte[] { 1, 2, 3 };
} }
}
public class ClientBasedPage : IPage
{
public byte[] GetData()
{
return [1, 2, 3];
} }
} }
+4 -2
View File
@@ -2,9 +2,11 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+61 -53
View File
@@ -1,6 +1,8 @@
using System.Diagnostics; using System;
using System.Diagnostics;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Threading;
using Example.Frontend; using Example.Frontend;
using Example.Shared; using Example.Shared;
using mROA.Codegen; using mROA.Codegen;
@@ -9,71 +11,77 @@ using mROA.Implementation.Backend;
using mROA.Implementation.Bootstrap; using mROA.Implementation.Bootstrap;
using mROA.Implementation.Frontend; using mROA.Implementation.Frontend;
var builder = new FullMixBuilder(); class Program
new RemoteTypeBinder(); {
builder.Modules.Add(new JsonSerializationToolkit()); public static void Main(string[] args)
builder.Modules.Add(new RemoteContextRepository()); {
builder.Modules.Add(new NextGenerationInteractionModule()); var builder = new FullMixBuilder();
builder.Modules.Add(new RepresentationModule()); new RemoteTypeBinder();
builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567))); builder.Modules.Add(new JsonSerializationToolkit());
builder.Modules.Add(new StaticRepresentationModuleProducer()); builder.Modules.Add(new RemoteContextRepository());
builder.Modules.Add(new RequestExtractor()); builder.Modules.Add(new NextGenerationInteractionModule());
builder.Modules.Add(new BasicExecutionModule()); builder.Modules.Add(new RepresentationModule());
builder.Modules.Add(new CoCodegenMethodRepository()); builder.Modules.Add(new NetworkFrontendBridge(new IPEndPoint(IPAddress.Loopback, 4567)));
builder.UseCollectableContextRepository(); builder.Modules.Add(new StaticRepresentationModuleProducer());
builder.Build(); builder.Modules.Add(new RequestExtractor());
builder.Modules.Add(new BasicExecutionModule());
builder.Modules.Add(new CoCodegenMethodRepository());
builder.UseCollectableContextRepository();
builder.Build();
TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>(); TransmissionConfig.RealContextRepository = builder.GetModule<ContextRepository>();
TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>(); TransmissionConfig.RemoteEndpointContextRepository = builder.GetModule<RemoteContextRepository>();
builder.GetModule<NetworkFrontendBridge>()!.Connect(); builder.GetModule<NetworkFrontendBridge>()!.Connect();
_ = builder.GetModule<RequestExtractor>()!.StartExtraction(); _ = builder.GetModule<RequestExtractor>()!.StartExtraction();
Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId()); Console.WriteLine(TransmissionConfig.OwnershipRepository.GetOwnershipId());
var context = builder.GetModule<RemoteContextRepository>(); var context = builder.GetModule<RemoteContextRepository>();
var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory; var factory = context.GetSingleObject(typeof(IPrinterFactory)) as IPrinterFactory;
//правильный порядок команд 8-5-10-7 //правильный порядок команд 8-5-10-7
var printer = factory.Create("Test"); var printer = factory.Create("Test");
Console.WriteLine("Printer created"); Console.WriteLine("Printer created");
Thread.Sleep(100); Thread.Sleep(100);
var name = printer.Value.GetName(); var name = printer.Value.GetName();
Console.WriteLine("Printer name : {0}", name); Console.WriteLine("Printer name : {0}", name);
Thread.Sleep(100); Thread.Sleep(100);
factory.Register(new SharedObject<IPrinter>(new ClientBasedPrinter())); factory.Register(new SharedObject<IPrinter>(new ClientBasedPrinter()));
Console.WriteLine("Registered printer"); Console.WriteLine("Registered printer");
Thread.Sleep(100); Thread.Sleep(100);
var registred = factory.GetFirstPrinter(); var registred = factory.GetFirstPrinter();
Console.WriteLine("First printer"); Console.WriteLine("First printer");
Thread.Sleep(100); Thread.Sleep(100);
Console.WriteLine(registred.Value); Console.WriteLine(registred.Value);
Console.WriteLine("Collecting all printers"); Console.WriteLine("Collecting all printers");
var names = factory.CollectAllNames(); var names = factory.CollectAllNames();
Thread.Sleep(100); Thread.Sleep(100);
Console.WriteLine(string.Join(", ", names)); Console.WriteLine(string.Join(", ", names));
var page = printer.Value.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult(); var page = printer.Value.Print("Test Page", new CancellationToken()).GetAwaiter().GetResult();
var data = page.Value.GetData(); var data = page.Value.GetData();
Console.WriteLine("Data : {0}", Encoding.UTF8.GetString(data)); 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; const int iterations = 10000;
var timer = Stopwatch.StartNew(); var timer = Stopwatch.StartNew();
var x = 0; var x = 0;
for (int i = 0; i < iterations; i++) for (int i = 0; i < iterations; i++)
{ {
x = loadSingleton.Next(x); x = loadSingleton.Next(x);
} }
timer.Stop(); timer.Stop();
Console.WriteLine("X is {0}", x); Console.WriteLine("X is {0}", x);
Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds); Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms"); Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
}
}
+4 -2
View File
@@ -1,9 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+9 -8
View File
@@ -1,13 +1,14 @@
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Shared; namespace Example.Shared
[SharedObjectInterface]
public interface ILoadTest
{ {
int Next(int last); [SharedObjectInterface]
int Last(int next); public interface ILoadTest
void C(); {
void A(); int Next(int last);
int Last(int next);
void C();
void A();
}
} }
+6 -5
View File
@@ -1,9 +1,10 @@
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Shared; namespace Example.Shared
[SharedObjectInterface]
public interface IPage
{ {
byte[] GetData(); [SharedObjectInterface]
public interface IPage
{
byte[] GetData();
}
} }
+9 -6
View File
@@ -1,12 +1,15 @@
using System.Threading;
using System.Threading.Tasks;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Shared; namespace Example.Shared
[SharedObjectInterface]
public interface IPrinter
{ {
string GetName(); [SharedObjectInterface]
Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken); public interface IPrinter
{
string GetName();
Task<SharedObject<IPage>> Print(string text, CancellationToken cancellationToken);
}
} }
+10 -9
View File
@@ -1,15 +1,16 @@
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace Example.Shared; namespace Example.Shared
[SharedObjectInterface]
public interface IPrinterFactory
{ {
SharedObject<IPrinter> Create(string printerName); [SharedObjectInterface]
void Register(SharedObject<IPrinter> printer); public interface IPrinterFactory
SharedObject<IPrinter> GetPrinterByName(string printerName); {
SharedObject<IPrinter> GetFirstPrinter(); SharedObject<IPrinter> Create(string printerName);
string[] CollectAllNames(); void Register(SharedObject<IPrinter> printer);
SharedObject<IPrinter> GetPrinterByName(string printerName);
SharedObject<IPrinter> GetFirstPrinter();
string[] CollectAllNames();
}
} }
+42 -38
View File
@@ -1,50 +1,54 @@
using BenchmarkDotNet.Attributes; using System;
using System.Collections.Generic;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running; using BenchmarkDotNet.Running;
namespace mROA.Benchmark; namespace mROA.Benchmark
class Program
{ {
static void Main(string[] args) class Program
{ {
Console.WriteLine("Hello, World!"); static void Main(string[] args)
var summary = BenchmarkRunner.Run<CollectionsSpeed>();
}
}
public class CollectionsSpeed
{
private const int N = 1000;
private readonly List<int> _immutable;
private readonly int[] _array;
public CollectionsSpeed()
{
_array = Enumerable.Range(0, N).ToArray();
_immutable = [.._array];
}
[Benchmark]
public int DefaultArray()
{
var sum = 0;
for (int i = 0; i < N; i++)
{ {
sum += _array[i]; Console.WriteLine("Hello, World!");
var summary = BenchmarkRunner.Run<CollectionsSpeed>();
} }
return sum;
} }
[Benchmark] public class CollectionsSpeed
public int ImmutableArray()
{ {
var sum = 0; private const int N = 1000;
for (int i = 0; i < N; i++)
private readonly List<int> _immutable;
private readonly int[] _array;
public CollectionsSpeed()
{ {
sum += _immutable[i]; _array = Enumerable.Range(0, N).ToArray();
_immutable = [.._array];
}
[Benchmark]
public int DefaultArray()
{
var sum = 0;
for (int i = 0; i < N; i++)
{
sum += _array[i];
}
return sum;
}
[Benchmark]
public int ImmutableArray()
{
var sum = 0;
for (int i = 0; i < N; i++)
{
sum += _immutable[i];
}
return sum;
} }
return sum;
} }
} }
+2 -2
View File
@@ -2,8 +2,8 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
+1 -2
View File
@@ -25,8 +25,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.3.0" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
+275 -213
View File
@@ -7,19 +7,19 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text;
namespace mROA.Codegen; namespace mROA.Codegen
/// <summary>
/// A sample source generator that creates a custom report based on class properties. The target class should be annotated with the 'Generators.ReportAttribute' attribute.
/// When using the source code as a baseline, an incremental source generator is preferable because it reduces the performance overhead.
/// </summary>
[Generator]
public class mROASourceGenerator : IIncrementalGenerator
{ {
private const string Namespace = "mROA.Implementation"; /// <summary>
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.
/// </summary>
[Generator]
public class mROASourceGenerator : ISourceGenerator
{
private const string Namespace = "mROA.Implementation";
private const string AttributeName = "SharedObjectInterafceAttribute";
private const string AttributeSourceCode = $@"// <auto-generated/> private const string AttributeSourceCode = $@"// <auto-generated/>
namespace {Namespace} namespace {Namespace}
{{ {{
@@ -29,151 +29,151 @@ namespace {Namespace}
}} }}
}}"; }}";
public void Initialize(IncrementalGeneratorInitializationContext context) // public void Initialize(IncrementalGeneratorInitializationContext context)
{ // {
// Filter classes annotated with the [Report] attribute. Only filtered Syntax Nodes can trigger code generation. // // Filter classes annotated with the [Report] attribute. Only filtered Syntax Nodes can trigger code generation.
var provider = context.SyntaxProvider // var provider = context.SyntaxProvider
.CreateSyntaxProvider( // .CreateSyntaxProvider(
(s, _) => s is InterfaceDeclarationSyntax, // (s, _) => s is InterfaceDeclarationSyntax,
(ctx, _) => GetClassDeclarationForSourceGen(ctx)) // (ctx, _) => GetClassDeclarationForSourceGen(ctx))
.Where(t => t.reportAttributeFound) // .Where(t => t.reportAttributeFound)
.Select((t, _) => t.Item1); // .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. /// <summary>
context.RegisterSourceOutput(context.CompilationProvider.Combine(provider.Collect()), /// Checks whether the Node is annotated with the [Report] attribute and maps syntax context to the specific node type (ClassDeclarationSyntax).
((ctx, t) => GenerateCode(ctx, t.Left, t.Right))); /// </summary>
} /// <param name="context">Syntax context, based on CreateSyntaxProvider predicate</param>
/// <returns>The specific cast and whether the attribute was found.</returns>
// private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen(
// GeneratorSyntaxContext context)
// {
// 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);
// }
/// <summary> /// <summary>
/// Checks whether the Node is annotated with the [Report] attribute and maps syntax context to the specific node type (ClassDeclarationSyntax). /// Generate code action.
/// </summary> /// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
/// <param name="context">Syntax context, based on CreateSyntaxProvider predicate</param> /// </summary>
/// <returns>The specific cast and whether the attribute was found.</returns> /// <param name="context">Source generation context used to add source files.</param>
private static (InterfaceDeclarationSyntax, bool reportAttributeFound) GetClassDeclarationForSourceGen( /// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
GeneratorSyntaxContext context) /// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
{ private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
var classDeclarationSyntax = (InterfaceDeclarationSyntax)context.Node; ImmutableArray<InterfaceDeclarationSyntax> classes)
// 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) var methods = new List<(string, IMethodSymbol)>();
continue; // if we can't get the symbol, ignore it var frontendContextRepo = new List<string>();
// Go through all filtered class declarations.
string attributeName = attributeSymbol.ContainingType.ToDisplayString(); var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
foreach (var classDeclarationSyntax in declarations)
// Check the full name of the [Report] attribute.
if (attributeName == "mROA.Implementation.Attributes.SharedObjectInterfaceAttribute")
return (classDeclarationSyntax, true);
}
return (classDeclarationSyntax, false);
}
/// <summary>
/// Generate code action.
/// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
/// </summary>
/// <param name="context">Source generation context used to add source files.</param>
/// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
/// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
private void GenerateCode(SourceProductionContext context, Compilation compilation,
ImmutableArray<InterfaceDeclarationSyntax> classes)
{
var methods = new List<(string, IMethodSymbol)>();
var frontendContextRepo = new List<string>();
// Go through all filtered class declarations.
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
foreach (var classDeclarationSyntax in declarations)
{
// 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<IMethodSymbol>().OrderBy(i => i.Name);
var originalName = className;
// Build up the source code
className = className.TrimStart('I') + "RemoteEndpoint";
var methodsText = new List<string>();
foreach (var method in methodBody)
{ {
var index = methods.Count; // We need to get semantic model of the class to retrieve metadata.
methods.Add((namespaceName + "." + originalName, method)); var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
var sb = new StringBuilder();
bool isAsync = method.ReturnType.Name == "Task"; // Symbols allow us to get the compile-time information.
bool isVoid = method.ReturnType.Name == "Void" || method.ReturnType.ToString() == "Task"; if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
bool isParametrized = method.Parameters.Length == 1 && !isAsync || continue;
method.Parameters.Length == 2 && isAsync;
//Creating signature var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
sb.AppendLine("public" + (isAsync
? " async " // 'Identifier' means the token of the node. Get class name from the syntax node.
: " ") + var className = classDeclarationSyntax.Identifier.Text;
$"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
// Go through all class members with a particular type (property) to generate method lines.
var methodBody = classSymbol.GetMembers()
.OfType<IMethodSymbol>().OrderBy(i => i.Name);
var originalName = className;
// Build up the source code
className = className.TrimStart('I') + "RemoteEndpoint";
var prefix = isAsync ? "await " : ""; var methodsText = new List<string>();
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) foreach (var method in methodBody)
prefix = "return " + prefix; {
var index = methods.Count;
// if (method.ReturnType.OriginalDefinition.ToString() == "System.Threading.Tasks.Task<TResult>") methods.Add((namespaceName + "." + originalName, method));
// { var sb = new StringBuilder();
// var type = method.ReturnType.ToString();
// type = type.Substring(type.IndexOf('<') + 1);
// type = type.Substring(0, type.Length - 1);
// sb.AppendLine(
// $"\t\tvar response = await serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId);");
// sb.AppendLine($"\t\treturn ({type})response.Result;");
// }
// else if (!isAsync && method.ReturnType.ToDisplayString() != "void")
// {
// var type = method.ReturnType.ToDisplayString();
// sb.AppendLine(
// $"\t\tvar response = serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId).GetAwaiter().GetResult();");
// sb.AppendLine($"\t\treturn ({type})response.Result;");
// }
// else
// {
// sb.AppendLine(
// "\t\tserialisationModule.GetNextCommandExecution<FinalCommandExecution>(defaultCallRequestCodegen.CallRequestId).Wait();");
// }
//
// sb.AppendLine("\t}");
sb.AppendLine("\t\t" + prefix + caller + postfix+ ";");
sb.AppendLine("\t}");
methodsText.Add(sb.ToString()); 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 = $@"// <auto-generated/>
//Creating signature
sb.AppendLine("public" + (isAsync
? " async "
: " ") +
$"{method.ReturnType.ToDisplayString()} {method.Name}({string.Join(", ", method.Parameters.Select(ToFullString))}){{");
var prefix = isAsync ? "await " : "";
var postfix = !isAsync ? (isVoid ? ".Wait()" : ".GetAwaiter().GetResult()") : "";
var parameterLink = isParametrized ? ", " + method.Parameters.First().Name : string.Empty;
var caller = isVoid ? $"CallAsync({index}{parameterLink})" :
isAsync ? $"GetResultAsync<{ExtractTaskType(method.ReturnType)}>({index}{parameterLink})" :
$"GetResultAsync<{ToFullString(method.ReturnType)}>({index}{parameterLink})";
if (!isVoid)
prefix = "return " + prefix;
// if (method.ReturnType.OriginalDefinition.ToString() == "System.Threading.Tasks.Task<TResult>")
// {
// var type = method.ReturnType.ToString();
// type = type.Substring(type.IndexOf('<') + 1);
// type = type.Substring(0, type.Length - 1);
// sb.AppendLine(
// $"\t\tvar response = await serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId);");
// sb.AppendLine($"\t\treturn ({type})response.Result;");
// }
// else if (!isAsync && method.ReturnType.ToDisplayString() != "void")
// {
// var type = method.ReturnType.ToDisplayString();
// sb.AppendLine(
// $"\t\tvar response = serialisationModule.GetFinalCommandExecution<{type}>(defaultCallRequestCodegen.CallRequestId).GetAwaiter().GetResult();");
// sb.AppendLine($"\t\treturn ({type})response.Result;");
// }
// else
// {
// sb.AppendLine(
// "\t\tserialisationModule.GetNextCommandExecution<FinalCommandExecution>(defaultCallRequestCodegen.CallRequestId).Wait();");
// }
//
// sb.AppendLine("\t}");
sb.AppendLine("\t\t\t" + prefix + caller + postfix + ";");
sb.AppendLine("\t\t}");
methodsText.Add(sb.ToString());
}
var code = $@"// <auto-generated/>
using mROA; using mROA;
using System; using System;
@@ -181,106 +181,168 @@ using mROA.Implementation;
using System.Collections.Generic; using System.Collections.Generic;
using mROA.Abstract; using mROA.Abstract;
namespace {namespaceName}; namespace {namespaceName}
partial class {className} : RemoteObjectBase, {originalName}
{{ {{
public {className}(int id, IRepresentationModule representationModule) : base(id, representationModule) partial class {className} : RemoteObjectBase, {originalName}
{{ {{
}} public {className}(int id, IRepresentationModule representationModule) : base(id, representationModule)
{{
}}
{string.Join("\r\n\t", methodsText)} {string.Join("\r\n\t", methodsText)}
}}
}} }}
"; ";
// Add the source code to the compilation.
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
frontendContextRepo.Add( // Add the source code to the compilation.
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}"); context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
}
if (methods.Count != 0) frontendContextRepo.Add(
{ $"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
var methodsStringed = methods.Select(i => }
$"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", [{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}])")
.ToList();
var coCodegenRepoCode = @$"// <auto-generated/> 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 = @$"// <auto-generated/>
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using mROA.Abstract; using mROA.Abstract;
using System;
namespace mROA.Codegen; namespace mROA.Codegen
public class CoCodegenMethodRepository : IMethodRepository
{{ {{
private readonly List<MethodInfo> _methods = [ public class CoCodegenMethodRepository : IMethodRepository
{string.Join(", // test comment\r\n\t\t", methodsStringed)}
];
public MethodInfo GetMethod(int id)
{{ {{
if (_methods.Count <= id) private readonly List<MethodInfo> _methods = new () {{
return null; {string.Join(",\r\n\t\t\t", methodsStringed)}
}};
return _methods[id];
}}
public int RegisterMethod(MethodInfo method) public MethodInfo GetMethod(int id)
{{ {{
_methods.Add(method); if (_methods.Count <= id)
return _methods.Count - 1; return null;
}}
return _methods[id];
}}
public IEnumerable<MethodInfo> GetMethods() public int RegisterMethod(MethodInfo method)
{{ {{
return _methods; _methods.Add(method);
}} return _methods.Count - 1;
}}
public void Inject<T>(T dependency) public IEnumerable<MethodInfo> GetMethods()
{{ {{
return _methods;
}}
public void Inject<T>(T dependency)
{{
}}
}} }}
}} }}
"; ";
context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8)); context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
} }
if (frontendContextRepo.Count != 0) if (frontendContextRepo.Count != 0)
{ {
var fronendRepoCode = @$"// <auto-generated/> var fronendRepoCode = @$"// <auto-generated/>
using System.Collections.Frozen;
using mROA.Implementation; using mROA.Implementation;
using mROA.Abstract; using mROA.Abstract;
using System.Collections.Generic;
using System;
using System.Reflection;
namespace mROA.Codegen; namespace mROA.Codegen
public sealed class RemoteTypeBinder
{{ {{
static RemoteTypeBinder(){{ public sealed class RemoteTypeBinder
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {{ {{
{string.Join(", \r\n\t\t", frontendContextRepo)}}}.ToFrozenDictionary(); static RemoteTypeBinder(){{
RemoteContextRepository.RemoteTypes = new Dictionary<Type, Type> {{
{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<InterfaceDeclarationSyntax>();
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<AttributeListSyntax> 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);
}
} }
+62 -58
View File
@@ -1,72 +1,76 @@
using System.Net; using System;
using System.Linq;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text; using System.Text;
using System.Threading.Tasks;
using mROA.Implementation; using mROA.Implementation;
namespace mROA.Test; namespace mROA.Test
public class NextGenTest
{ {
private TcpListener _listener; public class NextGenTest
private NextGenerationInteractionModule _interactionModuleA;
private NextGenerationInteractionModule _interactionModuleB;
private Guid[] guids = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()];
[SetUp]
public void Setup()
{ {
_listener = new TcpListener(IPAddress.Loopback, 4567); private TcpListener _listener;
_interactionModuleA = new NextGenerationInteractionModule(); private NextGenerationInteractionModule _interactionModuleA;
_interactionModuleA.Inject(new JsonSerializationToolkit()); private NextGenerationInteractionModule _interactionModuleB;
_interactionModuleB = new NextGenerationInteractionModule(); private Guid[] guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
_interactionModuleB.Inject(new JsonSerializationToolkit());
} [SetUp]
public void Setup()
[Test]
public void MultithreadedTest()
{
Task.Run(() =>
{ {
_listener.Start(); _listener = new TcpListener(IPAddress.Loopback, 4567);
_interactionModuleB.BaseStream = _listener.AcceptTcpClient().GetStream(); _interactionModuleA = new NextGenerationInteractionModule();
_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] foreach (var guid in guids)
public void TearDown() {
{ _interactionModuleB.PostMessage(new NetworkMessage { Id = guid, Data = "Hello user"u8.ToArray() });
_listener.Dispose(); }
});
var client = new TcpClient();
client.Connect(IPAddress.Loopback, 4567);
_interactionModuleA.BaseStream = client.GetStream();
var tasks = guids.Select(ReadStream);
Task.WaitAll(tasks.ToArray());
Assert.Pass();
}
private async Task ReadStream(Guid current)
{
var msg = await _interactionModuleA.GetNextMessageReceiving();
Console.WriteLine(
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
while (msg.Id != current)
{
msg = await _interactionModuleA.GetNextMessageReceiving();
Console.WriteLine(
$"{Environment.CurrentManagedThreadId} Received message: {Encoding.Default.GetString(new JsonSerializationToolkit().Serialize(msg))}");
}
Console.WriteLine($"{Environment.CurrentManagedThreadId} Good message received");
}
[TearDown]
public void TearDown()
{
_listener.Dispose();
}
} }
} }
+2 -2
View File
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
+8 -5
View File
@@ -1,8 +1,11 @@
namespace mROA.Abstract; using System;
public interface ICommandExecution namespace mROA.Abstract
{ {
Guid Id { get; init; } public interface ICommandExecution
int ClientId { get; set; } {
int CommandId { get; } Guid Id { get; set; }
int ClientId { get; set; }
int CommandId { get; }
}
} }
+11 -10
View File
@@ -1,12 +1,13 @@
namespace mROA.Abstract; namespace mROA.Abstract
public delegate void ConnectionHandler(IRepresentationModule representationModule);
public delegate void DisconnectionHandler(IRepresentationModule representationModule);
public interface IConnectionHub : IInjectableModule
{ {
void RegisterInteraction(INextGenerationInteractionModule interaction); public delegate void ConnectionHandler(IRepresentationModule representationModule);
INextGenerationInteractionModule GetInteracion(int id); public delegate void DisconnectionHandler(IRepresentationModule representationModule);
event ConnectionHandler? OnConnected;
event DisconnectionHandler? OnDisconnected; public interface IConnectionHub : IInjectableModule
{
void RegisterInteraction(INextGenerationInteractionModule interaction);
INextGenerationInteractionModule GetInteracion(int id);
event ConnectionHandler? OnConnected;
event DisconnectionHandler? OnDisconnected;
}
} }
+11 -8
View File
@@ -1,11 +1,14 @@
namespace mROA.Abstract; using System;
public interface IContextRepository : IInjectableModule namespace mROA.Abstract
{ {
int ResisterObject(object o); public interface IContextRepository : IInjectableModule
void ClearObject(int id); {
object GetObject(int id); int ResisterObject(object o);
T? GetObject<T>(int id); void ClearObject(int id);
object GetSingleObject(Type type); object GetObject(int id);
int GetObjectIndex(object o); T? GetObject<T>(int id);
object GetSingleObject(Type type);
int GetObjectIndex(object o);
}
} }
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract; namespace mROA.Abstract
public interface IContextRepositoryHub
{ {
IContextRepository GetRepository(int clientId); public interface IContextRepositoryHub
{
IContextRepository GetRepository(int clientId);
}
} }
+5 -4
View File
@@ -1,8 +1,9 @@
using mROA.Implementation; using mROA.Implementation;
namespace mROA.Abstract; namespace mROA.Abstract
public interface IExecuteModule : IInjectableModule
{ {
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository); public interface IExecuteModule : IInjectableModule
{
ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository);
}
} }
+7 -3
View File
@@ -1,3 +1,7 @@
namespace mROA.Abstract; namespace mROA.Abstract
{
public interface IFrontendBridge : IInjectableModule; public interface IFrontendBridge : IInjectableModule
{
}
}
+7 -4
View File
@@ -1,6 +1,9 @@
namespace mROA.Abstract; using System;
public interface IGatewayModule : IDisposable, IInjectableModule namespace mROA.Abstract
{ {
void Run(); public interface IGatewayModule : IDisposable, IInjectableModule
{
void Run();
}
} }
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract; namespace mROA.Abstract
public interface IIdentityGenerator : IInjectableModule
{ {
int GetNextIdentity(); public interface IIdentityGenerator : IInjectableModule
{
int GetNextIdentity();
}
} }
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Abstract; namespace mROA.Abstract
public interface IInjectableModule
{ {
void Inject<T>(T dependency); public interface IInjectableModule
{
void Inject<T>(T dependency);
}
} }
+14 -10
View File
@@ -1,14 +1,18 @@
using System;
using System.IO;
using System.Threading.Tasks;
using mROA.Implementation; using mROA.Implementation;
namespace mROA.Abstract; namespace mROA.Abstract
public interface INextGenerationInteractionModule : IInjectableModule
{ {
int ConnectionId { get; } public interface INextGenerationInteractionModule : IInjectableModule
public Stream? BaseStream { get; set; } {
Task<NetworkMessage> GetNextMessageReceiving(); int ConnectionId { get; }
Task PostMessage(NetworkMessage message); public Stream? BaseStream { get; set; }
void HandleMessage(NetworkMessage message); Task<NetworkMessage> GetNextMessageReceiving();
NetworkMessage[] UnhandledMessages { get; } Task PostMessage(NetworkMessage message);
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate); void HandleMessage(NetworkMessage message);
NetworkMessage[] UnhandledMessages { get; }
NetworkMessage? FirstByFilter(Predicate<NetworkMessage> predicate);
}
} }
+9 -7
View File
@@ -1,11 +1,13 @@
using System.Reflection; using System.Collections.Generic;
using System.Reflection;
namespace mROA.Abstract; namespace mROA.Abstract
public interface IMethodRepository : IInjectableModule
{ {
MethodInfo GetMethod(int id); public interface IMethodRepository : IInjectableModule
int RegisterMethod(MethodInfo method); {
MethodInfo GetMethod(int id);
int RegisterMethod(MethodInfo method);
IEnumerable<MethodInfo> GetMethods(); IEnumerable<MethodInfo> GetMethods();
}
} }
+6 -5
View File
@@ -1,7 +1,8 @@
namespace mROA.Abstract; namespace mROA.Abstract
public interface IOwnershipRepository
{ {
int GetOwnershipId(); public interface IOwnershipRepository
int GetHostOwnershipId(); {
int GetOwnershipId();
int GetHostOwnershipId();
}
} }
@@ -1,6 +1,7 @@
namespace mROA.Abstract; namespace mROA.Abstract
public interface IRepresentationModuleProducer : IInjectableModule
{ {
IRepresentationModule Produce(int id); public interface IRepresentationModuleProducer : IInjectableModule
{
IRepresentationModule Produce(int id);
}
} }
+6 -3
View File
@@ -1,6 +1,9 @@
namespace mROA.Abstract; using System.Threading.Tasks;
public interface IRequestExtractor : IInjectableModule namespace mROA.Abstract
{ {
Task StartExtraction(); public interface IRequestExtractor : IInjectableModule
{
Task StartExtraction();
}
} }
+25 -22
View File
@@ -1,31 +1,34 @@
using System;
using System.Threading.Tasks;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.CommandExecution; using mROA.Implementation.CommandExecution;
namespace mROA.Abstract; namespace mROA.Abstract
public interface ISerialisationModule : IInjectableModule
{ {
void HandleIncomingRequest(int clientId, byte[] message); public interface ISerialisationModule : IInjectableModule
void PostResponse(NetworkMessage message, int clientId);
void SendWelcomeMessage(int clientId);
public interface IFrontendSerialisationModule : IInjectableModule
{ {
int ClientId { get; } void HandleIncomingRequest(int clientId, byte[] message);
Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution; void PostResponse(NetworkMessage message, int clientId);
Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId); void SendWelcomeMessage(int clientId);
void PostCallRequest(ICallRequest callRequest); public interface IFrontendSerialisationModule : IInjectableModule
{
int ClientId { get; }
Task<T> GetNextCommandExecution<T>(Guid requestId) where T : ICommandExecution;
Task<FinalCommandExecution<T>> GetFinalCommandExecution<T>(Guid requestId);
void PostCallRequest(ICallRequest callRequest);
}
} }
}
public interface IRepresentationModule : IInjectableModule public interface IRepresentationModule : IInjectableModule
{ {
int Id { get; } int Id { get; }
Task<T> GetMessageAsync<T>(Guid? requestId = null, MessageType? messageType = null); Task<T> GetMessageAsync<T>(Guid? requestId = null, MessageType? messageType = null);
T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null); T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null);
Task<byte[]> GetRawMessage(Guid? requestId = null, MessageType? messageType = null); Task<byte[]> GetRawMessage(Guid? requestId = null, MessageType? messageType = null);
Task PostCallMessageAsync<T>(Guid id, MessageType messageType, T payload) where T : notnull; Task PostCallMessageAsync<T>(Guid id, MessageType messageType, T payload) where T : notnull;
Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType); Task PostCallMessageAsync(Guid id, MessageType messageType, object payload, Type payloadType);
void PostCallMessage<T>(Guid id, MessageType messageType, T payload) where T : notnull; void PostCallMessage<T>(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);
}
} }
+13 -10
View File
@@ -1,14 +1,17 @@
namespace mROA.Abstract; using System;
public interface ISerializationToolkit : IInjectableModule namespace mROA.Abstract
{ {
byte[] Serialize<T>(T objectToSerialize); public interface ISerializationToolkit : IInjectableModule
byte[] Serialize(object objectToSerialize, Type type); {
T? Deserialize<T>(byte[] rawData); byte[] Serialize<T>(T objectToSerialize);
object? Deserialize(byte[] rawData, Type type); byte[] Serialize(object objectToSerialize, Type type);
T? Deserialize<T>(Span<byte> rawData); T? Deserialize<T>(byte[] rawData);
object? Deserialize(Span<byte> rawData, Type type); object? Deserialize(byte[] rawData, Type type);
T Cast<T>(object nonCasted); T? Deserialize<T>(Span<byte> rawData);
object Cast(object nonCasted, Type type); object? Deserialize(Span<byte> rawData, Type type);
T Cast<T>(object nonCasted);
object Cast(object nonCasted, Type type);
}
} }
@@ -1,3 +1,6 @@
namespace mROA.Implementation.Attributes; using System;
public class SharedObjectInterfaceAttribute : Attribute; namespace mROA.Implementation.Attributes
{
public class SharedObjectInterfaceAttribute : Attribute { }
}
@@ -1,3 +1,6 @@
namespace mROA.Implementation.Attributes; using System;
public class SharedObjectSingletonAttribute : Attribute; namespace mROA.Implementation.Attributes
{
public class SharedObjectSingletonAttribute : Attribute { }
}
@@ -1,17 +1,18 @@
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class BackendIdentityGenerator : IIdentityGenerator
{ {
private int _currentId; public class BackendIdentityGenerator : IIdentityGenerator
public int GetNextIdentity()
{
return ++_currentId;
}
public void Inject<T>(T dependency)
{ {
private int _currentId;
public int GetNextIdentity()
{
return ++_currentId;
}
public void Inject<T>(T dependency)
{
}
} }
} }
@@ -1,37 +1,39 @@
using System;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation.Bootstrap; using mROA.Implementation.Bootstrap;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public static class BasicConfigurationExtensions
{ {
public static void UseJsonSerialisation(this FullMixBuilder builder) public static class BasicConfigurationExtensions
{ {
builder.Modules.Add(new JsonSerializationToolkit()); public static void UseJsonSerialisation(this FullMixBuilder builder)
} {
builder.Modules.Add(new JsonSerializationToolkit());
}
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)); builder.Modules.Add(new NetworkGatewayModule(endPoint, interactionModuleType, injectableModules));
} }
public static void UseBasicExecution(this FullMixBuilder builder) public static void UseBasicExecution(this FullMixBuilder builder)
{ {
builder.Modules.Add(new BasicExecutionModule()); builder.Modules.Add(new BasicExecutionModule());
} }
public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies) public static void UseCollectableContextRepository(this FullMixBuilder builder, params Assembly[] assemblies)
{ {
var repo = new ContextRepository(); var repo = new ContextRepository();
repo.FillSingletons(assemblies); repo.FillSingletons(assemblies);
TransmissionConfig.RealContextRepository = repo; TransmissionConfig.RealContextRepository = repo;
builder.Modules.Add(repo); builder.Modules.Add(repo);
} }
public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository) public static void SetupMethodsRepository(this FullMixBuilder builder, IMethodRepository methodRepository)
{ {
builder.Modules.Add(methodRepository); builder.Modules.Add(methodRepository);
}
} }
} }
@@ -1,121 +1,128 @@
using System.Reflection; using System;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation.CommandExecution; using mROA.Implementation.CommandExecution;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class BasicExecutionModule : IExecuteModule
{ {
private IMethodRepository? _methodRepo; public class BasicExecutionModule : IExecuteModule
public void Inject<T>(T dependency)
{ {
if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo; private IMethodRepository? _methodRepo;
}
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository) public void Inject<T>(T dependency)
{ {
if (_methodRepo is null) if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo;
throw new NullReferenceException("Method repository was not defined"); }
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository)
{
if (_methodRepo is null)
throw new NullReferenceException("Method repository was not defined");
if (contextRepository is null) if (contextRepository is null)
throw new NullReferenceException("Context repository was not defined"); throw new NullReferenceException("Context repository was not defined");
var currentCommand = _methodRepo.GetMethod(command.CommandId); var currentCommand = _methodRepo.GetMethod(command.CommandId);
if (currentCommand == null) if (currentCommand == null)
throw new Exception($"Command {command.CommandId} not found"); throw new Exception($"Command {command.CommandId} not found");
var context = command.ObjectId != -1 var context = command.ObjectId != -1
? contextRepository.GetObject(command.ObjectId) ? contextRepository.GetObject(command.ObjectId)
: contextRepository.GetSingleObject(currentCommand.DeclaringType!); : contextRepository.GetSingleObject(currentCommand.DeclaringType!);
var parameter = command.Parameter; var parameter = command.Parameter;
if (currentCommand.ReturnType.BaseType == typeof(Task) && if (currentCommand.ReturnType.BaseType == typeof(Task) &&
currentCommand.ReturnType.GenericTypeArguments.Length == 1) currentCommand.ReturnType.GenericTypeArguments.Length == 1)
return TypedExecuteAsync(currentCommand, context, parameter, command); return TypedExecuteAsync(currentCommand, context, parameter, command);
if (currentCommand.ReturnType == typeof(Task)) if (currentCommand.ReturnType == typeof(Task))
return ExecuteAsync(currentCommand, context, parameter, command); return ExecuteAsync(currentCommand, context, parameter, command);
return Execute(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
};
} }
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, var finalResult = currentCommand.Invoke(context, parameter is null ? new object[0] : new[]
Exception = e.ToString() { parameter });
}; return new TypedFinalCommandExecution
} {
} CommandId = command.CommandId, Result = finalResult,
Id = command.Id,
private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter, Type = currentCommand.ReturnType
ICallRequest command) };
{ }
var tokenSource = new CancellationTokenSource(); catch (Exception e)
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
{ {
Id = command.Id, CommandId = command.CommandId, return new ExceptionCommandExecution
Exception = e.ToString() {
}; Id = command.Id, CommandId = command.CommandId,
Exception = e.ToString()
};
}
} }
}
private static ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter, private static ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
ICallRequest command) ICallRequest command)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
try
{ {
var result = var tokenSource = new CancellationTokenSource();
(Task)currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token])!; var token = tokenSource.Token;
try
result.Wait(token);
var finalResult = result.GetType().GetProperty("Result")?.GetValue(result);
return new TypedFinalCommandExecution
{ {
Id = command.Id, var result = (Task)currentCommand.Invoke(context, parameter is null ? new object[] { token } : new[]
Result = finalResult, { parameter, token })!;
CommandId = command.CommandId,
Type = finalResult?.GetType()
}; 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, var result =
Exception = e.ToString() (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()
};
}
} }
} }
} }
+29 -26
View File
@@ -1,35 +1,38 @@
using mROA.Abstract; using System;
using System.Collections.Generic;
using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class ConnectionHub : IConnectionHub
{ {
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new(); public class ConnectionHub : IConnectionHub
private ISerializationToolkit? _serializationToolkit; {
private readonly Dictionary<int, INextGenerationInteractionModule> _connections = new();
private ISerializationToolkit? _serializationToolkit;
public void RegisterInteraction(INextGenerationInteractionModule interaction) public void RegisterInteraction(INextGenerationInteractionModule interaction)
{ {
if (_serializationToolkit is null) if (_serializationToolkit is null)
throw new NullReferenceException("Serialization toolkit is null"); throw new NullReferenceException("Serialization toolkit is null");
_connections.Add(interaction.ConnectionId, interaction); _connections.Add(interaction.ConnectionId, interaction);
var module = new RepresentationModule(); var module = new RepresentationModule();
module.Inject(_serializationToolkit); module.Inject(_serializationToolkit);
module.Inject(interaction); module.Inject(interaction);
OnConnected?.Invoke(module); OnConnected?.Invoke(module);
} }
public INextGenerationInteractionModule GetInteracion(int id) public INextGenerationInteractionModule GetInteracion(int id)
{ {
return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found"); return _connections!.GetValueOrDefault(id, null) ?? throw new Exception("No connection found");
} }
public event ConnectionHandler? OnConnected; public event ConnectionHandler? OnConnected;
public event DisconnectionHandler? OnDisconnected; public event DisconnectionHandler? OnDisconnected;
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is ISerializationToolkit serializationToolkit) if (dependency is ISerializationToolkit serializationToolkit)
_serializationToolkit = serializationToolkit; _serializationToolkit = serializationToolkit;
}
} }
} }
@@ -1,88 +1,92 @@
using System.Collections.Frozen; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class ContextRepository : IContextRepository
{ {
private FrozenDictionary<int, object?>? _singletons; public class ContextRepository : IContextRepository
private object?[] _storage = new object[StartupSize];
private Task<int> _lastIndexFinder = Task.FromResult(0);
private const int StartupSize = 1024;
private const int GrowSize = 128;
public void FillSingletons(params Assembly[] assembly)
{ {
var types = assembly.SelectMany(x => x.GetTypes()).Where(type => private Dictionary<int, object?>? _singletons;
type is { IsClass: true, IsAbstract: false, IsGenericType: false } && private object?[] _storage = new object[StartupSize];
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);
}
public int ResisterObject(object o) private Task<int> _lastIndexFinder = Task.FromResult(0);
{
if (!_lastIndexFinder.IsCompleted)
_lastIndexFinder.Wait();
_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 FillSingletons(params Assembly[] assembly)
}
public void ClearObject(int id)
{
_storage[id] = null;
_lastIndexFinder = Task.FromResult(id);
}
public object GetObject(int id)
{
return (id == -1 || _storage.Length <= id ? null : _storage[id]) ?? throw new NullReferenceException();
}
public T GetObject<T>(int id)
{
return id == -1 || _storage.Length <= id ? throw new NullReferenceException("Cannot find that object. It is null"): (T)_storage[id]!;
}
public 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) var types = assembly.SelectMany(x => x.GetTypes()).Where(type =>
return i; 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]; public int ResisterObject(object o)
Array.Copy(_storage, nextStorage, _storage.Length); {
_storage = nextStorage; if (!_lastIndexFinder.IsCompleted)
return _storage.Length; _lastIndexFinder.Wait();
}
public void Inject<T>(T dependency)
{
}
_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<T>(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>(T dependency)
{
}
}
} }
@@ -1,50 +1,58 @@
using System;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class HubRequestExtractor(Type extractoType) : IInjectableModule
{ {
private IConnectionHub? _hub; public class HubRequestExtractor : IInjectableModule
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private ISerializationToolkit? _serializationToolkit;
private IExecuteModule? _executeModule;
public void Inject<T>(T dependency)
{ {
switch (dependency) private IConnectionHub? _hub;
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private ISerializationToolkit? _serializationToolkit;
private IExecuteModule? _executeModule;
private readonly Type _extractorType;
public HubRequestExtractor(Type extractorType)
{ {
case IConnectionHub connectionHub: _extractorType = extractorType;
_hub = connectionHub; }
_hub.OnConnected += HubOnOnConnected;
break; public void Inject<T>(T dependency)
case IContextRepository contextRepository: {
_contextRepository = contextRepository; switch (dependency)
break; {
case IMethodRepository methodRepository: case IConnectionHub connectionHub:
_methodRepository = methodRepository; _hub = connectionHub;
break; _hub.OnConnected += HubOnOnConnected;
case ISerializationToolkit serializationToolkit: break;
_serializationToolkit = serializationToolkit; case IContextRepository contextRepository:
break; _contextRepository = contextRepository;
case IExecuteModule executeModule: break;
_executeModule = executeModule; case IMethodRepository methodRepository:
break; _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();
}
} }
@@ -1,56 +1,65 @@
using System;
using System.Collections.Generic;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class MultiClientContextRepository(Func<int, IContextRepository> produceRepository) : IContextRepository, IContextRepositoryHub
{ {
private Dictionary<int, IContextRepository> _repositories = new(); public class MultiClientContextRepository : IContextRepository, IContextRepositoryHub
private IContextRepository GetRepositoryByClientId(int clientId)
{ {
if (_repositories.TryGetValue(clientId, out var repository)) private Dictionary<int, IContextRepository> _repositories = new();
return repository; private readonly Func<int, IContextRepository> _produceRepository;
public MultiClientContextRepository(Func<int, IContextRepository> produceRepository)
{
_produceRepository = produceRepository;
}
private IContextRepository GetRepositoryByClientId(int clientId)
{
if (_repositories.TryGetValue(clientId, out var repository))
return repository;
var created = produceRepository(clientId); var created = _produceRepository(clientId);
_repositories.Add(clientId, created); _repositories.Add(clientId, created);
return created; return created;
} }
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
} }
public int ResisterObject(object o) public int ResisterObject(object o)
{ {
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o); return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ResisterObject(o);
} }
public void ClearObject(int id) public void ClearObject(int id)
{ {
GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id); GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).ClearObject(id);
} }
public object GetObject(int id) public object GetObject(int id)
{ {
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id); return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject(id);
} }
public T? GetObject<T>(int id) public T? GetObject<T>(int id)
{ {
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject<T>(id); return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObject<T>(id);
} }
public object GetSingleObject(Type type) public object GetSingleObject(Type type)
{ {
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetSingleObject(type); return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetSingleObject(type);
} }
public int GetObjectIndex(object o) public int GetObjectIndex(object o)
{ {
return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObjectIndex(o); return GetRepositoryByClientId(TransmissionConfig.OwnershipRepository.GetOwnershipId()).GetObjectIndex(o);
} }
public IContextRepository GetRepository(int clientId) public IContextRepository GetRepository(int clientId)
{ {
return GetRepositoryByClientId(clientId); return GetRepositoryByClientId(clientId);
}
} }
} }
@@ -1,28 +1,31 @@
using mROA.Abstract; using System;
using System.Collections.Generic;
using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class MultiClientOwnershipRepository : IOwnershipRepository
{ {
private Dictionary<int, int> _ownerships = new(); public class MultiClientOwnershipRepository : IOwnershipRepository
public int GetOwnershipId()
{ {
return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0); private Dictionary<int, int> _ownerships = new();
}
public int GetHostOwnershipId() public int GetOwnershipId()
{ {
return 0; return _ownerships.GetValueOrDefault(Environment.CurrentManagedThreadId, 0);
} }
public void RegisterOwnership(int ownershipId) public int GetHostOwnershipId()
{ {
_ownerships.TryAdd(Environment.CurrentManagedThreadId, ownershipId); return 0;
} }
public void FreeOwnership() public void RegisterOwnership(int ownershipId)
{ {
_ownerships.Remove(Environment.CurrentManagedThreadId); _ownerships.TryAdd(Environment.CurrentManagedThreadId, ownershipId);
}
public void FreeOwnership()
{
_ownerships.Remove(Environment.CurrentManagedThreadId);
}
} }
} }
@@ -1,89 +1,91 @@
using System.Net; using System;
using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading.Tasks;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Backend; namespace mROA.Implementation.Backend
public class NetworkGatewayModule : IGatewayModule
{ {
private readonly Type? _interactionModuleType; public class NetworkGatewayModule : IGatewayModule
private readonly IInjectableModule[]? _injectableModules;
private readonly TcpListener _tcpListener;
private IConnectionHub? _hub;
private ISerializationToolkit? _serialization;
public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules)
{ {
_tcpListener = new(endpoint); private readonly Type? _interactionModuleType;
_interactionModuleType = interactionModuleType; private readonly IInjectableModule[]? _injectableModules;
_injectableModules = injectableModules; private readonly TcpListener _tcpListener;
} private IConnectionHub? _hub;
private ISerializationToolkit? _serialization;
public void Run() public NetworkGatewayModule(IPEndPoint endpoint, Type interactionModuleType, IInjectableModule[] injectableModules)
{
_tcpListener.Start();
Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
Console.WriteLine("Enter Backspace to stop");
Task.Run(HandleIncomingConnections);
while (true)
{ {
var key = Console.ReadKey(); _tcpListener = new(endpoint);
if (key.Key == ConsoleKey.Backspace) _interactionModuleType = interactionModuleType;
break; _injectableModules = injectableModules;
} }
Console.WriteLine("Stopping"); public void Run()
}
public void Dispose()
{
_tcpListener.Stop();
_tcpListener.Dispose();
}
private void HandleIncomingConnections()
{
if (_hub is null)
throw new NullReferenceException("Hub module is null");
if (_tcpListener == null)
throw new NullReferenceException("TcpListener is null");
if (_injectableModules is null)
throw new NullReferenceException("InjectableModules is null");
if (_interactionModuleType is null)
throw new NullReferenceException("InteractionModuleType is null");
if (_serialization is null)
throw new NullReferenceException("Serialization is null");
while (true)
{ {
var client = _tcpListener.AcceptTcpClient(); _tcpListener.Start();
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); Console.WriteLine($"Listening on {_tcpListener.LocalEndpoint}");
var interaction = Activator.CreateInstance(_interactionModuleType) as INextGenerationInteractionModule; Console.WriteLine("Enter Backspace to stop");
foreach (var injectableModule in _injectableModules) Task.Run(HandleIncomingConnections);
interaction!.Inject(injectableModule);
interaction!.Inject(_serialization); while (true)
interaction.BaseStream = client.GetStream();
interaction.PostMessage(new NetworkMessage
{ {
Id = Guid.NewGuid(), SchemaId = MessageType.IdAssigning, var key = Console.ReadKey();
Data = _serialization.Serialize(new IdAssingnment { Id = interaction.ConnectionId }) if (key.Key == ConsoleKey.Backspace)
}); break;
_hub.RegisterInteraction(interaction); }
Console.WriteLine("Client registered");
}
}
public void Inject<T>(T dependency) Console.WriteLine("Stopping");
{ }
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule; public void Dispose()
if (dependency is ISerializationToolkit serializationToolkit) {
_serialization = serializationToolkit; _tcpListener.Stop();
}
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>(T dependency)
{
if (dependency is IConnectionHub interactionModule)
_hub = interactionModule;
if (dependency is ISerializationToolkit serializationToolkit)
_serialization = serializationToolkit;
}
} }
} }
+16 -13
View File
@@ -1,20 +1,23 @@
using System.Collections.Generic;
using System.Linq;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Bootstrap; namespace mROA.Implementation.Bootstrap
public class FullMixBuilder
{ {
public List<IInjectableModule> Modules { get; } = []; public class FullMixBuilder
public void Build()
{ {
foreach (var module in Modules) public List<IInjectableModule> Modules { get; } = new() { };
foreach (var injection in Modules)
module.Inject(injection);
}
public T? GetModule<T>() public void Build()
{ {
return Modules.OfType<T>().FirstOrDefault(); foreach (var module in Modules)
foreach (var injection in Modules)
module.Inject(injection);
}
public T? GetModule<T>()
{
return Modules.OfType<T>().FirstOrDefault();
}
} }
} }
+19 -17
View File
@@ -1,24 +1,26 @@
using System.Text.Json.Serialization; using System;
using System.Text.Json.Serialization;
// ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global // ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
namespace mROA.Implementation; namespace mROA.Implementation
public interface ICallRequest
{ {
Guid Id { get; } public interface ICallRequest
int CommandId { get; } {
int ObjectId { get; } Guid Id { get; }
object? Parameter { get; } int CommandId { get; }
} int ObjectId { get; }
object? Parameter { get; }
}
public class DefaultCallRequest : ICallRequest public class DefaultCallRequest : ICallRequest
{ {
public Guid Id { get; set; } = Guid.NewGuid(); public Guid Id { get; set; } = Guid.NewGuid();
public int CommandId { get; init; } public int CommandId { get; set; }
public int ObjectId { get; init; } = -1; public int ObjectId { get; set; } = -1;
[JsonIgnore] [JsonIgnore]
public Type? ParameterType { get; init; } public Type? ParameterType { get; set; }
public object? Parameter { get; set; } public object? Parameter { get; set; }
}
} }
@@ -1,17 +1,19 @@
using mROA.Abstract; using System;
using mROA.Abstract;
using mROA.Implementation.Frontend; using mROA.Implementation.Frontend;
namespace mROA.Implementation.CommandExecution; namespace mROA.Implementation.CommandExecution
public class ExceptionCommandExecution : ICommandExecution
{ {
public Guid Id { get; init; } public class ExceptionCommandExecution : ICommandExecution
public int ClientId { get; set; }
public int CommandId { get; init; }
public required string Exception { get; set; }
public RemoteException GetException()
{ {
return new RemoteException(Exception) { CallRequestId = Id }; public Guid Id { get; set; }
public int ClientId { get; set; }
public int CommandId { get; set; }
public string Exception { get; set; }
public RemoteException GetException()
{
return new RemoteException(Exception) { CallRequestId = Id };
}
} }
} }
@@ -1,20 +1,22 @@
using System.Text.Json.Serialization; using System;
using System.Text.Json.Serialization;
using mROA.Abstract; using mROA.Abstract;
// ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable UnusedAutoPropertyAccessor.Global
namespace mROA.Implementation.CommandExecution; namespace mROA.Implementation.CommandExecution
public class FinalCommandExecution : ICommandExecution
{ {
public Guid Id { get; init; } public class FinalCommandExecution : ICommandExecution
[JsonIgnore] {
public int ClientId { get; set; } public Guid Id { get; set; }
[JsonIgnore] [JsonIgnore]
public int CommandId { get; init; } public int ClientId { get; set; }
} [JsonIgnore]
public int CommandId { get; set; }
}
public class FinalCommandExecution<T> : FinalCommandExecution public class FinalCommandExecution<T> : FinalCommandExecution
{ {
public T? Result { get; init; } public T? Result { get; set; }
}
} }
@@ -1,10 +1,12 @@
using System.Text.Json.Serialization; using System;
using System.Text.Json.Serialization;
namespace mROA.Implementation.CommandExecution; namespace mROA.Implementation.CommandExecution
public class TypedFinalCommandExecution : FinalCommandExecution<object>
{ {
[JsonIgnore] public class TypedFinalCommandExecution : FinalCommandExecution<object>
// ReSharper disable once UnusedAutoPropertyAccessor.Global {
public Type? Type { get; set; } [JsonIgnore]
// ReSharper disable once UnusedAutoPropertyAccessor.Global
public Type? Type { get; set; }
}
} }
@@ -1,40 +1,42 @@
using mROA.Abstract; using System;
using mROA.Abstract;
namespace mROA.Implementation; namespace mROA.Implementation
public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
{ {
private Type _reprModuleType; public class CreativeRepresentationModuleProducer : IRepresentationModuleProducer
private IInjectableModule[] _creationModules;
private IConnectionHub? _hub;
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
{ {
_creationModules = creationModules; private Type _reprModuleType;
_reprModuleType = reprModuleType; private IInjectableModule[] _creationModules;
} private IConnectionHub? _hub;
public CreativeRepresentationModuleProducer(IInjectableModule[] creationModules, Type reprModuleType)
{
_creationModules = creationModules;
_reprModuleType = reprModuleType;
}
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is IConnectionHub interactionModule) if (dependency is IConnectionHub interactionModule)
_hub = interactionModule; _hub = interactionModule;
} }
public IRepresentationModule Produce(int id) public IRepresentationModule Produce(int id)
{ {
if (_hub == null) if (_hub == null)
throw new NullReferenceException("Interaction module is null"); throw new NullReferenceException("Interaction module is null");
var produced = var produced =
Activator.CreateInstance(_reprModuleType) as IRepresentationModule ?? Activator.CreateInstance(_reprModuleType) as IRepresentationModule ??
throw new Exception("Bad serialization module type"); throw new Exception("Bad serialization module type");
foreach (var creationModule in _creationModules) foreach (var creationModule in _creationModules)
produced.Inject(creationModule); produced.Inject(creationModule);
produced.Inject(_hub.GetInteracion(id)); produced.Inject(_hub.GetInteracion(id));
return produced; return produced;
}
} }
} }
@@ -1,6 +1,8 @@
namespace mROA.Implementation.Frontend; using System;
// public class JsonFrontendSerialisationModule namespace mROA.Implementation.Frontend
{
// public class JsonFrontendSerialisationModule
// : ISerialisationModule.IFrontendSerialisationModule // : ISerialisationModule.IFrontendSerialisationModule
// { // {
// private IInteractionModule.IFrontendInteractionModule? _interactionModule; // private IInteractionModule.IFrontendInteractionModule? _interactionModule;
@@ -77,8 +79,16 @@ namespace mROA.Implementation.Frontend;
// } // }
// } // }
public class RemoteException(string error) : Exception public class RemoteException : Exception
{ {
public Guid CallRequestId; public Guid CallRequestId;
public override string Message => $"Error in request {CallRequestId} : {error}"; private readonly string _error;
public RemoteException(string error)
{
_error = error;
}
public override string Message => $"Error in request {CallRequestId} : {_error}";
}
} }
@@ -1,43 +1,51 @@
using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Frontend; namespace mROA.Implementation.Frontend
public class NetworkFrontendBridge(IPEndPoint ipEndPoint) : IFrontendBridge
{ {
private readonly TcpClient _tcpClient = new(); public class NetworkFrontendBridge : IFrontendBridge
private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
public void Inject<T>(T dependency)
{ {
switch (dependency) private readonly TcpClient _tcpClient = new();
private NextGenerationInteractionModule? _interactionModule;
private ISerializationToolkit? _serialization;
private readonly IPEndPoint _ipEndPoint;
public NetworkFrontendBridge(IPEndPoint ipEndPoint)
{ {
case NextGenerationInteractionModule interactionModule: _ipEndPoint = ipEndPoint;
_interactionModule = interactionModule;
break;
case ISerializationToolkit toolkit:
_serialization = toolkit;
break;
} }
}
public void Connect() public void Inject<T>(T dependency)
{ {
if (_interactionModule is null) switch (dependency)
throw new Exception("Interaction module was not injected"); {
if (_serialization == null) case NextGenerationInteractionModule interactionModule:
throw new NullReferenceException("Serialization toolkit is not initialized"); _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); _tcpClient.Connect(_ipEndPoint);
_interactionModule.BaseStream = _tcpClient.GetStream(); _interactionModule.BaseStream = _tcpClient.GetStream();
var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult(); var welcomeMessage = _interactionModule.GetNextMessageReceiving().GetAwaiter().GetResult();
if (welcomeMessage.SchemaId != MessageType.IdAssigning) 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()}");
} }
TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize<IdAssingnment>(welcomeMessage.Data)!.Id); TransmissionConfig.OwnershipRepository = new StaticOwnershipRepository(_serialization.Deserialize<IdAssingnment>(welcomeMessage.Data)!.Id);
}
} }
} }
@@ -1,88 +1,92 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation.Backend; using mROA.Implementation.Backend;
using mROA.Implementation.CommandExecution; using mROA.Implementation.CommandExecution;
// ReSharper disable MethodHasAsyncOverload // ReSharper disable MethodHasAsyncOverload
namespace mROA.Implementation.Frontend; namespace mROA.Implementation.Frontend
public class RequestExtractor : IRequestExtractor
{ {
private IRepresentationModule? _representationModule; public class RequestExtractor : IRequestExtractor
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private IExecuteModule? _executeModule;
private ISerializationToolkit? _serializationToolkit;
public void Inject<T>(T dependency)
{ {
switch (dependency) private IRepresentationModule? _representationModule;
private IContextRepository? _contextRepository;
private IMethodRepository? _methodRepository;
private IExecuteModule? _executeModule;
private ISerializationToolkit? _serializationToolkit;
public void Inject<T>(T dependency)
{ {
case IExecuteModule executeModule: switch (dependency)
_executeModule = executeModule;
break;
case IContextRepository contextRepository:
_contextRepository = contextRepository;
break;
case IMethodRepository methodRepository:
_methodRepository = methodRepository;
break;
case IRepresentationModule representationModule:
_representationModule = representationModule;
break;
case ISerializationToolkit serializationToolkit:
_serializationToolkit = serializationToolkit;
break;
}
}
public async Task StartExtraction()
{
if (_serializationToolkit == null)
throw new NullReferenceException("Serializing toolkit is null.");
if (_executeModule == null)
throw new NullReferenceException("Execute module is null.");
if (_contextRepository == null)
throw new NullReferenceException("Context repository is null.");
if (_representationModule == null)
throw new NullReferenceException("Representation module is null.");
if (_methodRepository == null)
throw new NullReferenceException("Method repository is null.");
await Task.Yield();
var multiClientOwnershipRepository = TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
try
{
while (true)
{ {
var request = case IExecuteModule executeModule:
_representationModule!.GetMessage<DefaultCallRequest>(messageType: MessageType.CallRequest); _executeModule = executeModule;
break;
// Console.WriteLine("Executing {0}", request.Id); case IContextRepository contextRepository:
_contextRepository = contextRepository;
if (request.Parameter is not null) break;
{ case IMethodRepository methodRepository:
var parameterType = _methodRepository!.GetMethod(request.CommandId).GetParameters().First() _methodRepository = methodRepository;
.ParameterType; break;
case IRepresentationModule representationModule:
request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType); _representationModule = representationModule;
} break;
case ISerializationToolkit serializationToolkit:
var result = _executeModule.Execute(request, _contextRepository); _serializationToolkit = serializationToolkit;
break;
var resultType = result is FinalCommandExecution
? MessageType.FinishedCommandExecution
: MessageType.ExceptionCommandExecution;
_representationModule.PostCallMessage(request.Id, resultType, result, result.GetType());
} }
} }
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); multiClientOwnershipRepository?.RegisterOwnership(_representationModule.Id);
try
{
while (true)
{
var request =
_representationModule!.GetMessage<DefaultCallRequest>(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);
}
} }
} }
} }
@@ -1,16 +1,24 @@
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation.Frontend; namespace mROA.Implementation.Frontend
public class StaticOwnershipRepository(int id) : IOwnershipRepository
{ {
public int GetOwnershipId() public class StaticOwnershipRepository : IOwnershipRepository
{ {
return id; private readonly int _id;
}
public int GetHostOwnershipId() public StaticOwnershipRepository(int id)
{ {
return id; _id = id;
}
public int GetOwnershipId()
{
return _id;
}
public int GetHostOwnershipId()
{
return _id;
}
} }
} }
+5 -4
View File
@@ -1,6 +1,7 @@
namespace mROA.Implementation; namespace mROA.Implementation
public class IdAssingnment
{ {
public int Id { get; set; } public class IdAssingnment
{
public int Id { get; set; }
}
} }
+51 -49
View File
@@ -1,59 +1,61 @@
using System.Text.Json; using System;
using System.Text.Json;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation; namespace mROA.Implementation
public class JsonSerializationToolkit : ISerializationToolkit
{ {
public byte[] Serialize<T>(T objectToSerialize) public class JsonSerializationToolkit : ISerializationToolkit
{ {
return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize); public byte[] Serialize<T>(T objectToSerialize)
}
public byte[] Serialize(object objectToSerialize, Type type)
{
return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type);
}
public T? Deserialize<T>(byte[] rawData)
{
return JsonSerializer.Deserialize<T>(rawData);
}
public object? Deserialize(byte[] rawData, Type type)
{
return JsonSerializer.Deserialize(rawData, type);
}
public T? Deserialize<T>(Span<byte> rawData)
{
return JsonSerializer.Deserialize<T>(rawData);
}
public object? Deserialize(Span<byte> rawData, Type type)
{
return JsonSerializer.Deserialize(rawData, type);
}
public T Cast<T>(object nonCasted)
{
return nonCasted switch
{ {
JsonElement jsonElement => jsonElement.Deserialize<T>()!, return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize);
T casted => casted, }
_ => throw new JsonException("Cannot cast object to type " + typeof(T).FullName)
};
}
public object Cast(object nonCasted, Type type) public byte[] Serialize(object objectToSerialize, Type type)
{ {
if (nonCasted is JsonElement jsonElement) return JsonSerializer.SerializeToUtf8Bytes(objectToSerialize, type);
return jsonElement.Deserialize(type)!; }
throw new JsonException("Cannot cast object to type " + type.FullName); public T? Deserialize<T>(byte[] rawData)
} {
return JsonSerializer.Deserialize<T>(rawData);
}
public void Inject<T>(T dependency) public object? Deserialize(byte[] rawData, Type type)
{ {
return JsonSerializer.Deserialize(rawData, type);
}
public T? Deserialize<T>(Span<byte> rawData)
{
return JsonSerializer.Deserialize<T>(rawData);
}
public object? Deserialize(Span<byte> rawData, Type type)
{
return JsonSerializer.Deserialize(rawData, type);
}
public T Cast<T>(object nonCasted)
{
return nonCasted switch
{
JsonElement jsonElement => jsonElement.Deserialize<T>()!,
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>(T dependency)
{
}
} }
} }
+37 -33
View File
@@ -1,43 +1,47 @@
using System.Reflection; using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
namespace mROA.Implementation; namespace mROA.Implementation
public class MethodRepository : IMethodRepository
{ {
private readonly List<MethodInfo> _methods = []; public class MethodRepository : IMethodRepository
public MethodInfo GetMethod(int id)
{ {
if (_methods.Count <= id) private readonly List<MethodInfo> _methods = new() { };
throw new Exception("Method such registered method");
return _methods[id]; public MethodInfo GetMethod(int id)
}
public int RegisterMethod(MethodInfo method)
{
_methods.Add(method);
return _methods.Count - 1;
}
public IEnumerable<MethodInfo> 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()) if (_methods.Count <= id)
RegisterMethod(method); throw new Exception("Method such registered method");
return _methods[id];
}
public int RegisterMethod(MethodInfo method)
{
_methods.Add(method);
return _methods.Count - 1;
}
public IEnumerable<MethodInfo> 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>(T dependency)
{
} }
} }
public void Inject<T>(T dependency)
{
}
} }
+14 -12
View File
@@ -1,18 +1,20 @@
using System.Text.Json.Serialization; using System;
using System.Text.Json.Serialization;
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
namespace mROA.Implementation; namespace mROA.Implementation
public class NetworkMessage
{ {
public Guid Id { get; init; } public class NetworkMessage
[JsonConverter(typeof(JsonStringEnumConverter))] {
public MessageType SchemaId { get; init; } 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 public enum MessageType
{ {
Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning Unknown, FinishedCommandExecution, ExceptionCommandExecution, AsyncCancelCommandExecution, CallRequest, IdAssigning
}
} }
@@ -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; namespace mROA.Implementation
public class NextGenerationInteractionModule : INextGenerationInteractionModule
{ {
private ISerializationToolkit? _serialization; public class NextGenerationInteractionModule : INextGenerationInteractionModule
public int ConnectionId { get; private set; }
public Stream? BaseStream { get; set; }
private Task<NetworkMessage>? _currentReceiving;
private const int BufferSize = ushort.MaxValue;
private readonly Memory<byte> _buffer = new byte[BufferSize];
private readonly List<NetworkMessage> _messageBuffer = new (128);
public void Inject<T>(T dependency)
{ {
switch (dependency) private ISerializationToolkit? _serialization;
public int ConnectionId { get; private set; }
public Stream? BaseStream { get; set; }
private Task<NetworkMessage>? _currentReceiving;
private const int BufferSize = ushort.MaxValue;
private readonly Memory<byte> _buffer = new byte[BufferSize];
private readonly List<NetworkMessage> _messageBuffer = new (128);
public void Inject<T>(T dependency)
{ {
case ISerializationToolkit toolkit: switch (dependency)
_serialization = toolkit; {
break; case ISerializationToolkit toolkit:
case IIdentityGenerator identityGenerator: _serialization = toolkit;
ConnectionId = identityGenerator.GetNextIdentity(); break;
break; case IIdentityGenerator identityGenerator:
ConnectionId = identityGenerator.GetNextIdentity();
break;
}
}
public Task<NetworkMessage> 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<NetworkMessage> predicate)
{
return _messageBuffer.FirstOrDefault(m => predicate(m));
}
private async Task<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 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<NetworkMessage>(localSpan.Span);
_messageBuffer.Add(message!);
_currentReceiving = GetNextMessage();
return message!;
} }
} }
public Task<NetworkMessage> 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<NetworkMessage> 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<NetworkMessage>(localSpan);
_messageBuffer.Add(message!);
_currentReceiving = Task.Run(GetNextMessage);
return message!;
}
} }
+50 -48
View File
@@ -1,57 +1,59 @@
using System.Collections.Frozen; using System;
using System.Collections.Generic;
using mROA.Abstract; using mROA.Abstract;
namespace mROA.Implementation; namespace mROA.Implementation
public class RemoteContextRepository : IContextRepository
{ {
private IRepresentationModuleProducer? _representationProducer; public class RemoteContextRepository : IContextRepository
public static FrozenDictionary<Type, Type> RemoteTypes = FrozenDictionary<Type, Type>.Empty;
public int ResisterObject(object o)
{ {
throw new NotSupportedException(); private IRepresentationModuleProducer? _representationProducer;
} public static Dictionary<Type, Type> RemoteTypes = new();
public int ResisterObject(object o)
public void ClearObject(int id)
{
throw new NotSupportedException();
}
public object GetObject(int id)
{
throw new NotSupportedException();
}
public T GetObject<T>(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();
} }
throw new NotSupportedException();
}
public void Inject<T>(T dependency) public void ClearObject(int id)
{ {
if (dependency is IRepresentationModuleProducer serialisationModule) throw new NotSupportedException();
_representationProducer = serialisationModule; }
public object GetObject(int id)
{
throw new NotSupportedException();
}
public T GetObject<T>(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>(T dependency)
{
if (dependency is IRepresentationModuleProducer serialisationModule)
_representationProducer = serialisationModule;
}
} }
} }
+48 -37
View File
@@ -1,53 +1,64 @@
using mROA.Abstract; using System.Threading.Tasks;
using mROA.Abstract;
using mROA.Implementation.CommandExecution; using mROA.Implementation.CommandExecution;
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
namespace mROA.Implementation; namespace mROA.Implementation
public abstract class RemoteObjectBase(int id, IRepresentationModule representationModule)
{ {
public int Id => id; public abstract class RemoteObjectBase
public int OwnerId => representationModule.Id;
protected async Task<T> GetResultAsync<T>(int methodId, object? parameter = default)
{ {
var request = new DefaultCallRequest private readonly int _id;
{ CommandId = methodId, ObjectId = id, Parameter = parameter, ParameterType = parameter?.GetType() }; private readonly IRepresentationModule _representationModule;
await representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
var successResponse = protected RemoteObjectBase(int id, IRepresentationModule representationModule)
representationModule.GetMessageAsync<FinalCommandExecution<T>>( {
messageType: MessageType.FinishedCommandExecution, requestId: request.Id); _id = id;
var errorResponse = _representationModule = representationModule;
representationModule.GetMessageAsync<ExceptionCommandExecution>( }
messageType: MessageType.ExceptionCommandExecution, requestId: request.Id);
Task.WaitAny(successResponse, errorResponse);
if (successResponse.IsCompletedSuccessfully) public int Id => _id;
return successResponse.Result.Result!; public int OwnerId => _representationModule.Id;
throw errorResponse.Result.GetException(); protected async Task<T> GetResultAsync<T>(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 successResponse =
{ _representationModule.GetMessageAsync<FinalCommandExecution<T>>(
var request = new DefaultCallRequest messageType: MessageType.FinishedCommandExecution, requestId: request.Id);
{ CommandId = methodId, ObjectId = id, Parameter = parameter, ParameterType = parameter?.GetType() }; var errorResponse =
await representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request); _representationModule.GetMessageAsync<ExceptionCommandExecution>(
messageType: MessageType.ExceptionCommandExecution, requestId: request.Id);
Task.WaitAny(successResponse, errorResponse);
var successResponse = if (successResponse.IsCompletedSuccessfully)
representationModule.GetMessageAsync<FinalCommandExecution>( return successResponse.Result.Result!;
messageType: MessageType.FinishedCommandExecution, requestId: request.Id);
var errorResponse =
representationModule.GetMessageAsync<ExceptionCommandExecution>(
messageType: MessageType.ExceptionCommandExecution, requestId: request.Id);
Task.WaitAny(successResponse, errorResponse); throw errorResponse.Result.GetException();
}
if (successResponse.IsCompletedSuccessfully) protected async Task CallAsync(int methodId, object? parameter = default)
return; {
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<FinalCommandExecution>(
messageType: MessageType.FinishedCommandExecution, requestId: request.Id);
var errorResponse =
_representationModule.GetMessageAsync<ExceptionCommandExecution>(
messageType: MessageType.ExceptionCommandExecution, requestId: request.Id);
Task.WaitAny(successResponse, errorResponse);
if (successResponse.IsCompletedSuccessfully)
return;
throw errorResponse.Result.GetException();
}
} }
} }
+82 -79
View File
@@ -1,93 +1,96 @@
using mROA.Abstract; using System;
using System.Threading.Tasks;
using mROA.Abstract;
namespace mROA.Implementation; namespace mROA.Implementation
public class RepresentationModule : IRepresentationModule
{ {
private ISerializationToolkit? _serialization; public class RepresentationModule : IRepresentationModule
private INextGenerationInteractionModule? _interaction;
public void Inject<T>(T dependency)
{ {
switch (dependency) private ISerializationToolkit? _serialization;
private INextGenerationInteractionModule? _interaction;
public void Inject<T>(T dependency)
{ {
case ISerializationToolkit toolkit: switch (dependency)
_serialization = toolkit;
break;
case INextGenerationInteractionModule interactionModule:
_interaction = interactionModule;
break;
}
}
public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId;
public async Task<T> GetMessageAsync<T>(Guid? requestId, MessageType? messageType)
{
if (_serialization == null)
throw new NullReferenceException("Serialization toolkit is not initialized");
return _serialization.Deserialize<T>(await GetRawMessage(requestId, messageType))!;
}
public T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null)
{
if (_serialization == null)
throw new NullReferenceException("Serialization toolkit is not initialized");
return _serialization.Deserialize<T>(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!;
}
public async Task<byte[]> 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(); case ISerializationToolkit toolkit:
if ((requestId is not null && message.Id != requestId) || _serialization = toolkit;
(messageType is not null && message.SchemaId != messageType)) continue; break;
case INextGenerationInteractionModule interactionModule:
_interaction.HandleMessage(message); _interaction = interactionModule;
return message.Data; break;
} }
} }
_interaction.HandleMessage(fromBuffer); public int Id => (_interaction ?? throw new NullReferenceException("Interaction is not initialized")).ConnectionId;
return fromBuffer.Data;
}
public async Task PostCallMessageAsync<T>(Guid id, MessageType messageType, T payload) where T : notnull public async Task<T> GetMessageAsync<T>(Guid? requestId, MessageType? messageType)
{ {
await PostCallMessageAsync(id, messageType, payload, typeof(T)); if (_serialization == null)
} throw new NullReferenceException("Serialization toolkit is not initialized");
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 return _serialization.Deserialize<T>(await GetRawMessage(requestId, messageType))!;
{ Id = id, SchemaId = messageType, Data = _serialization.Serialize(payload, payloadType) }); }
}
public void PostCallMessage<T>(Guid id, MessageType messageType, T payload) where T : notnull public T GetMessage<T>(Guid? requestId = null, MessageType? messageType = null)
{ {
PostCallMessageAsync(id, messageType, payload).GetAwaiter().GetResult(); if (_serialization == null)
} throw new NullReferenceException("Serialization toolkit is not initialized");
return _serialization.Deserialize<T>(GetRawMessage(requestId, messageType).GetAwaiter().GetResult())!;
}
public void PostCallMessage(Guid id, MessageType messageType, object payload, Type payloadType) public async Task<byte[]> GetRawMessage(Guid? requestId = null, MessageType? messageType = null)
{ {
PostCallMessageAsync(id, messageType, payload, payloadType).GetAwaiter().GetResult(); 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<T>(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<T>(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();
}
} }
} }
+81 -79
View File
@@ -1,101 +1,103 @@
using System.Text.Json.Serialization; using System;
using System.Text.Json.Serialization;
using mROA.Abstract; using mROA.Abstract;
// ReSharper disable UnusedMember.Global // ReSharper disable UnusedMember.Global
#pragma warning disable CS8618, CS9264 #pragma warning disable CS8618, CS9264
namespace mROA.Implementation; namespace mROA.Implementation
public static class TransmissionConfig
{ {
private static IContextRepository? _realContextRepository; public static class TransmissionConfig
private static IContextRepository? _remoteEndpointContextRepository;
private static IOwnershipRepository? _ownershipRepository;
public static IContextRepository RealContextRepository
{ {
get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null"); private static IContextRepository? _realContextRepository;
set => _realContextRepository = value; private static IContextRepository? _remoteEndpointContextRepository;
} private static IOwnershipRepository? _ownershipRepository;
public static IContextRepository RemoteEndpointContextRepository public static IContextRepository RealContextRepository
{
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<T> where T : notnull
{
private IContextRepository GetDefaultContextRepository() =>
(OwnerId == TransmissionConfig.OwnershipRepository.GetHostOwnershipId()
? TransmissionConfig.RealContextRepository
: TransmissionConfig.RemoteEndpointContextRepository) ??
throw new NullReferenceException(
"DefaultContextRepository was not defined");
private int _contextId = -2;
private int _ownerId = -1;
public int OwnerId
{
get
{ {
_ownerId = _ownerId == -1 ? TransmissionConfig.OwnershipRepository.GetOwnershipId() : _ownerId; get => _realContextRepository ?? throw new NullReferenceException("RealContextRepository is null");
return _ownerId; 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 class SharedObject<T> where T : notnull
public int ContextId
{ {
// ReSharper disable once UnusedMember.Global private IContextRepository GetDefaultContextRepository() =>
get (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; return _contextId;
}
_contextId = TransmissionConfig.RealContextRepository.GetObjectIndex(Value); set
return _contextId; {
_contextId = value;
Value = GetDefaultContextRepository().GetObject<T>(_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<T>(_contextId)!;
} }
}
[JsonIgnore] public T Value { get; private init; } // ReSharper disable once UnusedMember.Global
public SharedObject(T value)
// ReSharper disable once MemberCanBePrivate.Global
// ReSharper disable once UnusedMember.Global
public SharedObject()
{
}
// ReSharper disable once UnusedMember.Global
public SharedObject(T value)
{
Value = value;
if (value is RemoteObjectBase ro)
{ {
_ownerId = ro.OwnerId; Value = value;
_contextId = ro.Id;
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<T> value) => value.Value;
public static implicit operator SharedObject<T>(T value) =>
new(value);
} }
public static implicit operator T(SharedObject<T> value) => value.Value;
public static implicit operator SharedObject<T>(T value) =>
new(value);
} }
@@ -1,21 +1,23 @@
using mROA.Abstract; using System;
using mROA.Abstract;
namespace mROA.Implementation; namespace mROA.Implementation
public class StaticRepresentationModuleProducer : IRepresentationModuleProducer
{ {
private IRepresentationModule? _representationModule; public class StaticRepresentationModuleProducer : IRepresentationModuleProducer
{
private IRepresentationModule? _representationModule;
public IRepresentationModule Produce(int ownership) public IRepresentationModule Produce(int ownership)
{ {
if (_representationModule == null) if (_representationModule == null)
throw new NullReferenceException("The representation module is not initialized."); throw new NullReferenceException("The representation module is not initialized.");
return _representationModule; return _representationModule;
} }
public void Inject<T>(T dependency) public void Inject<T>(T dependency)
{ {
if (dependency is IRepresentationModule serialisationModule) if (dependency is IRepresentationModule serialisationModule)
_representationModule = serialisationModule; _representationModule = serialisationModule;
}
} }
} }
+43
View File
@@ -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<int> ReadExactlyAsync(this Stream stream, byte[] buffer, int offset, int count)
{
return await stream.ReadAtLeastAsyncCore(buffer.AsMemory(offset, count), count, true, default);
}
public static ValueTask<int> ReadExactlyAsync(this Stream stream, Memory<byte> buffer,
CancellationToken cancellationToken = default(CancellationToken))
{
return stream.ReadAtLeastAsyncCore(buffer, buffer.Length, true, cancellationToken);
}
private static async ValueTask<int> ReadAtLeastAsyncCore(this Stream stream,
Memory<byte> 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;
}
}
}
+6 -2
View File
@@ -1,8 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Title>mROA</Title> <Title>mROA</Title>
<Version>2.0.0</Version> <Version>2.0.0</Version>
@@ -12,6 +11,11 @@
<PackageProjectUrl>https://github.com/YaslePoy/mROA</PackageProjectUrl> <PackageProjectUrl>https://github.com/YaslePoy/mROA</PackageProjectUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<PackageTags>RPC</PackageTags> <PackageTags>RPC</PackageTags>
<LangVersion>9</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Text.Json" Version="9.0.2" />
</ItemGroup>
</Project> </Project>