21 Commits
Author SHA1 Message Date
micialware dce374035f Caching singleton proxies 2026-07-07 22:39:25 +03:00
micialware a4c05af5c8 Fix udp bug 2026-07-07 22:30:46 +03:00
micialware 1ecca099d8 fixing reading message crash 2026-06-05 09:24:44 +03:00
micialware 5cc76ddbcc Refactoring 2026-06-05 09:02:25 +03:00
micialware 84f9840024 Codegen in modidier support 2026-01-29 23:15:39 +03:00
micialware b4280cd06d Bug found, temporal solution made 2025-09-24 00:18:09 +03:00
micialware aae30af664 Some refactoring 2025-09-24 00:11:10 +03:00
micialware dca21339db Update LICENSE 2025-09-12 00:53:04 +03:00
micialware dfad8b9141 Prepare for zero-copy sending 2025-08-16 19:51:35 +03:00
micialware 46d741a287 Changing references 2025-08-16 18:30:05 +03:00
micialware 24d346795d Benchmark kaput 2025-08-16 12:14:03 +03:00
micialware 8c137115f4 Add logging for deserialization 2025-08-09 13:16:12 +03:00
micialware cc7d2d478c Remove old option for distribution 2025-08-09 13:09:38 +03:00
micialware b409e5ef08 Abstract distribution model 2025-08-09 13:03:20 +03:00
micialware c29db73a0e Benchmark for execution test written 2025-08-07 23:39:42 +03:00
micialware 0f355b9df3 Flat COI binary representation 2025-08-07 19:14:17 +03:00
micialware 89a2bee8d2 Renaming and cleanup. Begin to use own small arena allocator 2025-08-07 18:52:31 +03:00
micialware 37f5d8a198 Merge pull request #7 from YaslePoy/stick-fix
Stick fix
2025-08-06 19:19:39 +03:00
micialware e7c9bec4cd Merge pull request #6 from YaslePoy/lock-free
Lock free
2025-08-06 19:19:03 +03:00
micialware 37e768d6e8 Remove waiting from demo 2025-08-06 15:03:46 +03:00
micialware 5ece345a3f Add logging 2025-08-06 14:50:10 +03:00
72 changed files with 1655 additions and 302 deletions
+2 -2
View File
@@ -7,14 +7,14 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>9</LangVersion> <LangVersion>12</LangVersion>
<PublishAot>true</PublishAot> <PublishAot>true</PublishAot>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+1 -1
View File
@@ -11,7 +11,7 @@ namespace Example.Backend
{ {
private readonly List<IPrinter> _printers = new(); private readonly List<IPrinter> _printers = new();
public IPrinter Create(string printerName) public IPrinter Create(in string printerName)
{ {
Console.WriteLine("Creating printer"); Console.WriteLine("Creating printer");
return new Printer { Name = printerName }; return new Printer { Name = printerName };
+4 -6
View File
@@ -26,8 +26,8 @@ class Program
builder.Services.AddOptions(); builder.Services.AddOptions();
var listening = new IPEndPoint(IPAddress.Any, 4567); var listening = new IPEndPoint(IPAddress.Any, 4567);
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = listening); builder.Services.Configure<GatewayOptions>(options => options.Endpoint = listening);
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.ExtractorFirst); builder.Services.AddSingleton<IDistributionModule, ExtractorFirstDistributionModule>();
builder.Services.Configure<SerializationBufferOffset>(options => options.Offset = 0);
builder.Services.AddSingleton<HubRequestExtractor>(); builder.Services.AddSingleton<HubRequestExtractor>();
builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>(); builder.Services.AddSingleton<IExecuteModule, BasicExecutionModule>();
builder.Services.AddSingleton<IRepresentationModuleProducer, CreativeRepresentationModuleProducer>(); builder.Services.AddSingleton<IRepresentationModuleProducer, CreativeRepresentationModuleProducer>();
@@ -40,7 +40,6 @@ class Program
return repo; return repo;
})); }));
builder.Services.AddSingleton<IMethodRepository>(p => builder.Services.AddSingleton<IMethodRepository>(p =>
{ {
var methodRepo = new CollectableMethodRepository(); var methodRepo = new CollectableMethodRepository();
@@ -48,13 +47,12 @@ class Program
return methodRepo; return methodRepo;
}); });
builder.Services.AddSingleton<ICallIndexProvider, GeneratedCallIndexProvider>(); builder.Services.AddSingleton<ICallIndexProvider, GeneratedCallIndexProvider>();
builder.Services.AddSingleton<ICancellationRepository, CancellationRepository>(); builder.Services.AddSingleton<ICancellationRepository, CancellationRepository>();
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.ExtractorFirst);
var host = builder.Build(); var host = builder.Build();
//
new RemoteTypeBinder(); new RemoteTypeBinder();
//
_ = host.Services.GetService<IUntrustedGateway>()!.Start(); _ = host.Services.GetService<IUntrustedGateway>()!.Start();
var gateway = host.Services.GetService<IGatewayModule>(); var gateway = host.Services.GetService<IGatewayModule>();
gateway.Run(); gateway.Run();
+1 -1
View File
@@ -31,7 +31,7 @@ namespace Example.Frontend
public string GetName() public string GetName()
{ {
Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!! Vova likes that:)"); Console.WriteLine("ClientBasedPrinter called from server!!!!!!!!!!!");
DemoCheck.BackwardCall = true; DemoCheck.BackwardCall = true;
return "ClientBasedPrinter from mroa"; return "ClientBasedPrinter from mroa";
+1 -1
View File
@@ -6,7 +6,7 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>9</LangVersion> <LangVersion>12</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+13 -10
View File
@@ -16,7 +16,6 @@ using mROA.Implementation;
using mROA.Implementation.Backend; using mROA.Implementation.Backend;
using mROA.Implementation.Frontend; using mROA.Implementation.Frontend;
class Program class Program
{ {
public static async Task Main(string[] args) public static async Task Main(string[] args)
@@ -46,6 +45,7 @@ class Program
builder.Services.AddOptions(); builder.Services.AddOptions();
builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint); builder.Services.Configure<GatewayOptions>(options => options.Endpoint = serverEndPoint);
builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.Channeled); builder.Services.Configure<DistributionOptions>(o => o.DistributionType = EDistributionType.Channeled);
builder.Services.Configure<SerializationBufferOffset>(options => options.Offset = 0);
builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>(); builder.Services.AddSingleton<IRepresentationModuleProducer, StaticRepresentationModuleProducer>();
builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>(); builder.Services.AddSingleton<IRequestExtractor, RequestExtractor>();
@@ -76,7 +76,14 @@ class Program
using (var disposingPrinter = factory.Create("Test")) using (var disposingPrinter = factory.Create("Test"))
{ {
disposingPrinter.SetFingerPrint(new[] { 1, 2, 3 }).ContinueWith(r => { Console.WriteLine(r.Status); }); disposingPrinter.SetFingerPrint(new[] { 1, 2, 3 }).ContinueWith(r =>
{
Console.WriteLine(r.Status);
if (r.Status == TaskStatus.Faulted)
{
Console.WriteLine(r.Exception);
}
});
await disposingPrinter.IntTest(new MyData { Id = 5, Score = 7, Name = "Test" }); await disposingPrinter.IntTest(new MyData { Id = 5, Score = 7, Name = "Test" });
DemoCheck.CreatingPrinter = true; DemoCheck.CreatingPrinter = true;
@@ -86,14 +93,12 @@ class Program
DemoCheck.EventCallback = true; DemoCheck.EventCallback = true;
}; };
Console.WriteLine("Printer created"); Console.WriteLine("Printer created");
Thread.Sleep(100);
frontendBridge.Obstacle(); // frontendBridge.Obstacle();
var name = disposingPrinter.GetName(); var name = disposingPrinter.GetName();
DemoCheck.BasicNonParamsCall = true; DemoCheck.BasicNonParamsCall = true;
Console.WriteLine("Printer name : {0}", name); Console.WriteLine("Printer name : {0}", name);
Thread.Sleep(100);
disposingPrinter.SomeoneIsApproaching("Mikhail"); disposingPrinter.SomeoneIsApproaching("Mikhail");
Console.WriteLine("Approaching detected"); Console.WriteLine("Approaching detected");
@@ -102,17 +107,14 @@ class Program
factory.Register(disposingPrinter); factory.Register(disposingPrinter);
DemoCheck.ClientBasedImplementation = true; DemoCheck.ClientBasedImplementation = true;
Console.WriteLine("Registered printer"); Console.WriteLine("Registered printer");
Thread.Sleep(100);
var registered = factory.GetFirstPrinter(); var registered = factory.GetFirstPrinter();
Console.WriteLine("First printer"); Console.WriteLine("First printer");
Thread.Sleep(100);
Console.WriteLine(registered); Console.WriteLine(registered);
Console.WriteLine("Collecting all printers"); Console.WriteLine("Collecting all printers");
var names = factory.CollectAllNames(); var names = factory.CollectAllNames();
Thread.Sleep(100);
Console.WriteLine("Names: " + string.Join(", ", names)); Console.WriteLine("Names: " + string.Join(", ", names));
@@ -145,13 +147,14 @@ class Program
var token = cts.Token; var token = cts.Token;
var t = Task.Run(async () => await loadSingleton!.AsyncTest(token)); var t = Task.Run(async () => await loadSingleton!.AsyncTest(token));
Thread.Sleep(5000); Console.WriteLine("Waiting for timer");
Thread.Sleep(2000);
cts.Cancel(); cts.Cancel();
Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}"); Console.WriteLine($"Token state {cts.Token.IsCancellationRequested}");
DemoCheck.TaskCancelation = true; DemoCheck.TaskCancelation = true;
#endif #endif
const int iterations = 10_000; const int iterations = 5;
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++)
+1 -1
View File
@@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
+20 -6
View File
@@ -1,4 +1,6 @@
using System.Net; using System.Diagnostics;
using System.Net;
using System.Runtime;
using Example.Shared; using Example.Shared;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@@ -9,14 +11,13 @@ using mROA.Implementation;
using mROA.Implementation.Backend; using mROA.Implementation.Backend;
using mROA.Implementation.Frontend; using mROA.Implementation.Frontend;
const int C = 100; const int C = 100;
var time = TimeSpan.FromSeconds(10); var time = TimeSpan.FromSeconds(10);
Console.WriteLine($"Starting bench for {time} from {C} connections"); Console.WriteLine($"Starting bench for {time} from {C} connections");
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
new RemoteTypeBinder(); new RemoteTypeBinder();
var eps = await GetLoadEndpoints(C); var eps = await GetLoadEndpoints(C);
var tasks = new Task<int>[C]; var tasks = new Task<(int, double[])>[C];
for (int i = 0; i < C; i++) for (int i = 0; i < C; i++)
{ {
tasks[i] = Requests(cts.Token, i, eps[i]); tasks[i] = Requests(cts.Token, i, eps[i]);
@@ -28,9 +29,17 @@ Console.WriteLine("Start waiting");
await Task.WhenAll(tasks); await Task.WhenAll(tasks);
Console.WriteLine("End waiting"); Console.WriteLine("End waiting");
var totalRequests = tasks.Sum(i => i.Result); var totalRequests = tasks.Sum(i => i.Result.Item1);
var totalLatency = tasks.SelectMany(i => i.Result.Item2).ToList();
totalLatency.Sort();
var n = totalLatency.Count;
var p50 = totalLatency[(int)(n * 50f / 100f)];
var p95 = totalLatency[(int)(n * 95f / 100f)];
var p99 = totalLatency[(int)(n * 99f / 100f)];
Console.WriteLine($"Total requests: {totalRequests:N0}"); Console.WriteLine($"Total requests: {totalRequests:N0}");
Console.WriteLine($"Results: {totalRequests / time.TotalSeconds:N} RPS"); Console.WriteLine($"Results: {totalRequests / time.TotalSeconds:N} RPS");
Console.WriteLine("Latency (µs): p50={0} p95={1} p99={2}", p50, p95, p99);
File.AppendAllText("results.txt", $"[FAST ID] {totalRequests}\r\n"); File.AppendAllText("results.txt", $"[FAST ID] {totalRequests}\r\n");
async Task<List<ILoadTest>> GetLoadEndpoints(int count) async Task<List<ILoadTest>> GetLoadEndpoints(int count)
@@ -94,10 +103,12 @@ async Task<List<ILoadTest>> GetLoadEndpoints(int count)
} }
} }
async Task<int> Requests(CancellationToken token, int id, ILoadTest load) async Task<(int, double[])> Requests(CancellationToken token, int id, ILoadTest load)
{ {
try try
{ {
var latencyList = new List<double>();
var sw = new Stopwatch();
int count = 0; int count = 0;
while (true) while (true)
{ {
@@ -106,11 +117,14 @@ async Task<int> Requests(CancellationToken token, int id, ILoadTest load)
break; break;
} }
sw.Restart();
await load.Next(2); await load.Next(2);
sw.Stop();
latencyList.Add(sw.Elapsed.TotalMicroseconds);
count++; count++;
} }
return count; return (count, latencyList.ToArray());
} }
catch (Exception e) catch (Exception e)
{ {
-2
View File
@@ -10,12 +10,10 @@
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" /> <ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" />
<ProjectReference Include="..\mROA\mROA.csproj"/> <ProjectReference Include="..\mROA\mROA.csproj"/>
<ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/> <ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
<PackageReference Include="mROA.Codegen" Version="2.0.5" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+2 -1
View File
@@ -12,7 +12,8 @@ namespace Example.Shared
{ {
double Resource { get; set; } double Resource { get; set; }
string GetName(); string GetName();
Task<IPage> Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken); Task<IPage> Print(string text, bool someParameter,
RequestContext context, CancellationToken cancellationToken);
event Action<IPage, RequestContext> OnPrint; event Action<IPage, RequestContext> OnPrint;
[Untrusted] [Untrusted]
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Example.Shared
[SharedObjectInterface] [SharedObjectInterface]
public interface IPrinterFactory : IShared public interface IPrinterFactory : IShared
{ {
IPrinter Create(string printerName); IPrinter Create(in string printerName);
void Register(IPrinter printer); void Register(IPrinter printer);
IPrinter GetPrinterByName(string printerName); IPrinter GetPrinterByName(string printerName);
IPrinter GetFirstPrinter(); IPrinter GetFirstPrinter();
+197 -17
View File
@@ -1,21 +1,201 @@
MIT License Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright (c) 2025 YaslePoy TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a copy 1. Definitions.
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all "License" shall mean the terms and conditions for use, reproduction,
copies or substantial portions of the Software. and distribution as defined by Sections 1 through 9 of this document.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR "Licensor" shall mean the copyright owner or entity authorized by
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, the copyright owner that is granting the License.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER "Legal Entity" shall mean the union of the acting entity and all
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, other entities that control, are controlled by, or are under common
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE control with that entity. For the purposes of this definition,
SOFTWARE. "control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2025 Mitrofanov M. M.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+15
View File
@@ -3,6 +3,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using mROA.Implementation; using mROA.Implementation;
namespace mROA.Benchmark;
public static class CborExtensions public static class CborExtensions
{ {
public static unsafe void WriteToCbor(this RequestId id, CborWriter writer) public static unsafe void WriteToCbor(this RequestId id, CborWriter writer)
@@ -32,4 +34,17 @@ public static class CborExtensions
MemoryMarshal.Write(span, ref id); MemoryMarshal.Write(span, ref id);
writer.WriteByteString(span); writer.WriteByteString(span);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RequestId ReadFromTrueCbor(CborReader reader)
{
var enc = reader.ReadEncodedValue(true);
return MemoryMarshal.Read<RequestId>(enc.Span[1..]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static RequestId ReadFromCbor(CborReader reader)
{
var enc = reader.ReadEncodedValue();
return MemoryMarshal.Read<RequestId>(enc.Span[1..]);
}
} }
+150
View File
@@ -0,0 +1,150 @@
using System.Formats.Cbor;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Jobs;
using mROA.Implementation;
namespace mROA.Benchmark;
[MemoryDiagnoser]
public class ConcurrentAlloc
{
private readonly CircularMemoryManager _cmm = new(1024);
private readonly FastCircularMemoryManager _fmm = new();
private CborWriter _writer = new();
[GlobalSetup]
public void Setup()
{
_writer.WriteStartArray(2);
_writer.WriteByteString([1, 2, 3, 4, 5, 6, 7, 8]);
_writer.WriteStartArray(2);
_writer.WriteInt32(12);
_writer.WriteTextString("tralala 7EBC1458-BB53-49EA-84C9-EFECC0FC08FD");
_writer.WriteEndArray();
_writer.WriteEndArray();
}
[Benchmark(Baseline = true)]
public int CircularAllocate()
{
var writer = _writer;
var buffer = _cmm.AllocSlice(writer.BytesWritten);
writer.Encode(buffer);
return buffer.Length;
}
[Benchmark]
public int CircularMemoryAllocate()
{
var writer = _writer;
var buffer = _cmm.AllocMemory(writer.BytesWritten);
writer.Encode(buffer.Span);
return buffer.Length;
}
[Benchmark]
public int FastCircularAllocate()
{
var writer = _writer;
var buffer = _fmm.Alloc(writer.BytesWritten);
writer.Encode(buffer);
return buffer.Length;
}
[Benchmark]
public int FastMemoryCircularAllocate()
{
var writer = _writer;
var buffer = _fmm.AllocMem(writer.BytesWritten);
writer.Encode(buffer.Span);
return buffer.Length;
}
[Benchmark]
public int HeapAllocate()
{
var writer = _writer;
var encoded = writer.Encode();
return encoded.Length;
}
}
public class FastCircularMemoryManager
{
private readonly byte[] _buffer;
private long _offset; // atomic offset (in bytes)
private readonly int _mask; // если размер степени двойки — можно использовать маску
public FastCircularMemoryManager(int size = 4096) // 4KB buffer
{
if (!IsPowerOfTwo(size))
throw new ArgumentException("Size should be power of two for performance.", nameof(size));
_buffer = new byte[size];
_offset = 0;
_mask = size - 1; // для быстрого циклического сдвига: (offset & _mask)
}
private static bool IsPowerOfTwo(int x) => x > 0 && (x & (x - 1)) == 0;
public Span<byte> Alloc(int size)
{
if (size > _buffer.Length)
return new byte[size]; // fallback
long oldOffset, newOffset;
int start;
// Atomic "bump pointer" с циклическим переполнением
do
{
oldOffset = Volatile.Read(ref _offset);
start = (int)(oldOffset & _mask);
// Проверяем, не пересекает ли выделение границу буфера
if (start + size > _buffer.Length)
{
// Переполнение — обнуляем (циклический буфер)
newOffset = size; // сбрасываем на начало + size
start = 0;
}
else
{
newOffset = oldOffset + size;
}
} while (Interlocked.CompareExchange(ref _offset, newOffset, oldOffset) != oldOffset);
return _buffer.AsSpan(start, size);
}
public Memory<byte> AllocMem(int size)
{
if (size > _buffer.Length)
return new byte[size]; // fallback
long oldOffset, newOffset;
int start;
// Atomic "bump pointer" с циклическим переполнением
do
{
oldOffset = Volatile.Read(ref _offset);
start = (int)(oldOffset & _mask);
// Проверяем, не пересекает ли выделение границу буфера
if (start + size > _buffer.Length)
{
// Переполнение — обнуляем (циклический буфер)
newOffset = size; // сбрасываем на начало + size
start = 0;
}
else
{
newOffset = oldOffset + size;
}
} while (Interlocked.CompareExchange(ref _offset, newOffset, oldOffset) != oldOffset);
return _buffer.AsMemory(start, size);
}
}
+15
View File
@@ -0,0 +1,15 @@
using mROA.Abstract;
using mROA.Implementation.Attributes;
namespace mROA.Benchmark
{
[SharedObjectInterface]
public interface ILoadTest : IShared
{
Task<int> Next(int last);
int Last(int next);
void C();
void A();
Task AsyncTest(CancellationToken token = default);
}
}
+11
View File
@@ -0,0 +1,11 @@
using mROA.Abstract;
using mROA.Implementation.Attributes;
namespace mROA.Benchmark
{
[SharedObjectInterface]
public interface IPage : IShared
{
byte[] GetData();
}
}
+51
View File
@@ -0,0 +1,51 @@
using mROA.Abstract;
using mROA.Implementation;
using mROA.Implementation.Attributes;
namespace mROA.Benchmark
{
[SharedObjectInterface]
public partial interface IPrinter : IDisposable, IShared
{
double Resource { get; set; }
string GetName();
Task<IPage> Print(string text, bool someParameter, RequestContext context, CancellationToken cancellationToken);
event Action<IPage, RequestContext> OnPrint;
[Untrusted]
Task SomeoneIsApproaching(string humanName);
Task SetFingerPrint(int[] fingerPrint);
Task IntTest(MyData data);
}
public class MyData
{
public int Id { get; set; }
public string Name { get; set; }
public double Score { get; set; }
public override string ToString()
{
return $"{{{nameof(Id)}: {Id}, {nameof(Name)}: {Name}, {nameof(Score)}: {Score}}}";
}
protected bool Equals(MyData other)
{
return Id == other.Id && Name == other.Name && Score.Equals(other.Score);
}
public override bool Equals(object obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((MyData)obj);
}
public override int GetHashCode()
{
return HashCode.Combine(Id, Name, Score);
}
}
}
+15
View File
@@ -0,0 +1,15 @@
using mROA.Abstract;
using mROA.Implementation.Attributes;
namespace mROA.Benchmark
{
[SharedObjectInterface]
public interface IPrinterFactory : IShared
{
IPrinter Create(string printerName);
void Register(IPrinter printer);
IPrinter GetPrinterByName(string printerName);
IPrinter GetFirstPrinter();
string[] CollectAllNames();
}
}
+30
View File
@@ -0,0 +1,30 @@
using BenchmarkDotNet.Attributes;
namespace mROA.Benchmark;
[MemoryDiagnoser]
[DisassemblyDiagnoser]
public class InvokePerformance
{
public Func<int, int> A = x =>
{
var result = x * 5 + x * x / 5;
return result;
};
public SomeMath B = x => x * 5 + x * x / 5;
[Benchmark(Baseline = true)]
public int ActionInvoke()
{
return A(132);
}
[Benchmark]
public int DelegateInvoke()
{
return A(132);
}
}
public delegate int SomeMath(int x);
+133
View File
@@ -0,0 +1,133 @@
using BenchmarkDotNet.Attributes;
using mROA.Abstract;
using mROA.Codegen;
using mROA.Implementation;
namespace mROA.Benchmark;
[MemoryDiagnoser]
// [DisassemblyDiagnoser]
public class MethodAccess
{
private CollectableMethodRepository _current = new();
private FastMethodRepository _fast = new();
private readonly int _count = new GeneratedInvokersCollection().Count;
[GlobalSetup]
public void SetupMethodAccess()
{
_current.AppendInvokers(new GeneratedInvokersCollection());
_fast.AppendInvokers(new GeneratedInvokersCollection());
}
// [Benchmark(Baseline = true)]
// public IMethodInvoker CurrentSingle()
// {
// return _current.GetMethod(0);
// }
//
// [Benchmark]
// public IMethodInvoker CurrentDispose()
// {
// return _current.GetMethod(-1);
// }
//
// [Benchmark]
// public IMethodInvoker FastSingle()
// {
// return _fast.GetMethod(0);
// }
//
// [Benchmark]
// public IMethodInvoker FastDispose()
// {
// return _fast.GetMethod(-1);
// }
// [Benchmark]
// public IMethodInvoker FastSingleBaked()
// {
// return _fast.GetMethodBaked(0);
// }
//
// [Benchmark]
// public IMethodInvoker FastDisposeBaked()
// {
// return _fast.GetMethodBaked(-1);
// }
[Benchmark(Baseline = true)]
public IMethodInvoker CurrentAll()
{
IMethodInvoker inv = null;
for (int i = -1; i < _count; i++)
{
inv = _current.GetMethod(i);
}
return inv;
}
[Benchmark]
public IMethodInvoker FastAll()
{
IMethodInvoker inv = null;
for (int i = -1; i < _count; i++)
{
inv = _fast.GetMethod(i);
}
return inv;
}
[Benchmark]
public IMethodInvoker FastAllBaked()
{
IMethodInvoker inv = null;
for (int i = -1; i < _count; i++)
{
inv = _fast.GetMethodBaked(i);
}
return inv;
}
[Benchmark]
public IMethodInvoker FastAllBakedPreicrement()
{
IMethodInvoker inv = null;
for (int i = -1; i < _count; i++)
{
inv = _fast.GetMethodBakedPreicrement(i);
}
return inv;
}
}
internal class FastMethodRepository : IMethodRepository
{
private readonly List<IMethodInvoker> _methods = [MethodInvoker.Dispose];
private IMethodInvoker[] _baked = [];
public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers)
{
_methods.AddRange(methodInvokers);
_baked = _methods.ToArray();
}
public IMethodInvoker GetMethod(int id)
{
return _methods[id + 1];
}
public IMethodInvoker GetMethodBaked(int id)
{
return _baked[id + 1];
}
public IMethodInvoker GetMethodBakedPreicrement(int id)
{
return _baked[++id];
}
}
+2 -2
View File
@@ -3,6 +3,6 @@
using BenchmarkDotNet.Running; using BenchmarkDotNet.Running;
using mROA.Benchmark; using mROA.Benchmark;
Console.WriteLine("Hello, World!"); Console.WriteLine("Hello, Performance!");
BenchmarkRunner.Run<IdGeneration>(); BenchmarkRunner.Run<MethodAccess>();
+38
View File
@@ -0,0 +1,38 @@
using System.Formats.Cbor;
using BenchmarkDotNet.Attributes;
using mROA.Implementation;
namespace mROA.Benchmark;
[MemoryDiagnoser]
[DisassemblyDiagnoser]
public class RequestReader
{
private ReadOnlyMemory<byte> _data;
public RequestReader()
{
_data = new ReadOnlyMemory<byte>([80, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
}
[Benchmark(Baseline = true)]
public ulong DefaultRead()
{
var reader = new CborReader(_data);
return new RequestId(reader.ReadByteString()).P0;
}
[Benchmark]
public ulong MemoryRead()
{
var reader = new CborReader(_data);
return CborExtensions.ReadFromCbor(reader).P0;
}
[Benchmark]
public ulong MemoryTrueRead()
{
var reader = new CborReader(_data);
return CborExtensions.ReadFromTrueCbor(reader).P0;
}
}
+4 -3
View File
@@ -2,12 +2,13 @@ using System.Formats.Cbor;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using mROA.Implementation; using mROA.Implementation;
namespace mROA.Benchmark;
[MemoryDiagnoser] [MemoryDiagnoser]
public class RequestWriter public class RequestWriter
{ {
private const int N = 1000; public RequestId Id;
public RequestId Id = RequestId.Generate(); private readonly CborWriter _writer;
private CborWriter _writer;
public RequestWriter() public RequestWriter()
{ {
+73
View File
@@ -0,0 +1,73 @@
using BenchmarkDotNet.Attributes;
using mROA.Implementation;
namespace mROA.Benchmark;
public class StackOperations
{
private Stack<StackFrame> stack = new();
public StackOperations()
{
}
[Benchmark]
public void Stack()
{
}
private readonly struct StackFrame
{
public StackFrame(
CborMajorType? type,
int frameOffset,
int? definiteLength,
int itemsWritten,
int? currentKeyOffset,
int? currentValueOffset,
List<int>? keyValuePairEncodingRanges,
HashSet<(int Offset, int Length)>? keyEncodingRanges)
{
MajorType = type;
FrameOffset = frameOffset;
DefiniteLength = definiteLength;
ItemsWritten = itemsWritten;
CurrentKeyOffset = currentKeyOffset;
CurrentValueOffset = currentValueOffset;
KeyValuePairEncodingRanges = keyValuePairEncodingRanges;
KeyEncodingRanges = keyEncodingRanges;
}
public CborMajorType? MajorType { get; }
public int FrameOffset { get; }
public int? DefiniteLength { get; }
public int ItemsWritten { get; }
public int? CurrentKeyOffset { get; }
public int? CurrentValueOffset { get; }
public List<int>? KeyValuePairEncodingRanges { get; }
public HashSet<(int Offset, int Length)>? KeyEncodingRanges { get; }
}
}
internal enum CborMajorType
{
Unknown,
Int8,
Int16,
Int32,
Int64,
UInt8,
UInt16,
UInt32,
UInt64,
Float32,
Float64,
Double,
Double2,
Double3,
}
+133
View File
@@ -0,0 +1,133 @@
using BenchmarkDotNet.Attributes;
using mROA.Abstract;
using mROA.Cbor;
using mROA.Implementation;
using mROA.Implementation.Attributes;
using mROA.Implementation.Backend;
using mROA.Implementation.CommandExecution;
namespace mROA.Benchmark;
public class TaskWaiting
{
private readonly BasicExecutionModule _executionModule;
private readonly CallRequest _syncRequest;
private readonly CallRequest _asyncRequest;
private readonly InstanceRepository _instanceRepo;
private readonly EndPointContext _endPointContext;
private readonly FastRepresentationModule _representationModule;
public TaskWaiting()
{
_executionModule = new BasicExecutionModule(new CancellationRepository(), new TestMethodRepo(), new CborSerializationToolkit(null));
_syncRequest = new CallRequest{CommandId = 0, Parameters = null, Id = RequestId.Generate(), ObjectId = new ComplexObjectIdentifier(-1, 0)};
_asyncRequest = new CallRequest{CommandId = 1, Parameters = null, Id = RequestId.Generate(), ObjectId = new ComplexObjectIdentifier(-1, 0)};
_instanceRepo = new InstanceRepository(null);
_instanceRepo.FillSingletons(typeof(TaskWaiting).Assembly);
_endPointContext = new EndPointContext(_instanceRepo, null)
{
OwnerId = 0
};
_representationModule = new FastRepresentationModule();
}
[Benchmark(Baseline = true)]
public int DefaultJob()
{
return (int)((FinalCommandExecution<object>)_executionModule.Execute(_syncRequest, _instanceRepo, _representationModule, _endPointContext)).Result;
}
[Benchmark]
public async Task<int> DefaultJobAsync()
{
_representationModule.Signal = new TaskCompletionSource<int>();
var task = _representationModule.Signal.Task;
_ = _executionModule.Execute(_asyncRequest, _instanceRepo, _representationModule, _endPointContext);
_ = await task;
return (int)((FinalCommandExecution<object>)_representationModule.Result).Result;
}
}
public class TestMethodRepo : IMethodRepository
{
public IMethodInvoker GetMethod(int id)
{
if (id == 0)
return new MethodInvoker
{
IsVoid = false,
IsTrusted = true,
ReturnType = typeof(int),
ParameterTypes = Type.EmptyTypes,
SuitableType = typeof(IJobClass),
Invoking = (i, _, _) => (i as IJobClass).A()
};
return new AsyncMethodInvoker
{
IsVoid = false,
IsTrusted = true,
ReturnType = typeof(int),
ParameterTypes = Type.EmptyTypes,
SuitableType = typeof(IJobClass),
Invoking = (i, _, _, post) => (i as IJobClass).B().ContinueWith(task => post(task.Result))
};
}
}
[SharedObjectInterface]
public interface IJobClass
{
int A();
Task<int> B();
}
[SharedObjectSingleton]
public class JobClass : IJobClass
{
private readonly RequestWriter _requestWriter = new();
public int A()
{
return _requestWriter.DefaultCbor();
}
public Task<int> B()
{
return Task.FromResult(_requestWriter.DefaultCbor());
}
}
public class FastRepresentationModule : IRepresentationModule
{
public TaskCompletionSource<int> Signal = new();
public object Result;
public int Id { get; }
public IEndPointContext Context { get; }
public Task<(object? Deserialized, EMessageType MessageType)> GetSingle(Predicate<NetworkMessage> rule, IEndPointContext? context, CancellationToken token = default, params Func<NetworkMessage, Type?>[] converter)
{
throw new NotImplementedException();
}
public IAsyncEnumerable<(object parced, EMessageType originalType)> GetStream(Predicate<NetworkMessage> rule, IEndPointContext? context, CancellationToken token = default,
params Func<NetworkMessage, Type?>[] converter)
{
throw new NotImplementedException();
}
public Task PostCallMessageAsync<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull
{
Result = payload;
Signal.SetResult(0);
return Task.CompletedTask;
}
public void PostCallMessage<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull
{
throw new NotImplementedException();
}
public Task PostCallMessageUntrustedAsync<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context) where T : notnull
{
throw new NotImplementedException();
}
}
+7 -10
View File
@@ -9,17 +9,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2"/>
<PackageReference Include="System.Formats.Cbor" Version="9.0.8"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj"/>
<ProjectReference Include="..\mROA.Codegen\mROA.Codegen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>
<ProjectReference Include="..\mROA\mROA.csproj"/> <ProjectReference Include="..\mROA\mROA.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="System.Formats.Cbor">
<HintPath>..\..\..\..\.nuget\packages\system.formats.cbor\9.0.7\lib\net9.0\System.Formats.Cbor.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.15.2" />
</ItemGroup>
</Project> </Project>
+81 -34
View File
@@ -1,10 +1,11 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Formats.Cbor; using System.Formats.Cbor;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading;
using Microsoft.Extensions.Options;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.Attributes; using mROA.Implementation.Attributes;
@@ -14,7 +15,13 @@ namespace mROA.Cbor
{ {
public class CborSerializationToolkit : IContextualSerializationToolKit public class CborSerializationToolkit : IContextualSerializationToolKit
{ {
private readonly CborWriter _writer = new(initialCapacity: 2048); private readonly ThreadLocal<CborWriter> _writer = new(() => new CborWriter(initialCapacity: 2048));
private readonly int _offset;
public CborSerializationToolkit(IOptions<SerializationBufferOffset> offsetOptions) : this(offsetOptions.Value
.Offset)
{
}
private readonly IOrdinaryStructureParser[] _parsers = private readonly IOrdinaryStructureParser[] _parsers =
{ {
@@ -23,6 +30,12 @@ namespace mROA.Cbor
}; };
private readonly Dictionary<Type, List<PropertyInfo>> _propertiesCache = new(); private readonly Dictionary<Type, List<PropertyInfo>> _propertiesCache = new();
public CborSerializationToolkit(int offset)
{
_offset = offset;
}
public static TimeSpan SerializationTime = TimeSpan.Zero; public static TimeSpan SerializationTime = TimeSpan.Zero;
private bool FindParser(Type t, out IOrdinaryStructureParser parser) private bool FindParser(Type t, out IOrdinaryStructureParser parser)
@@ -51,25 +64,24 @@ namespace mROA.Cbor
public byte[] Serialize(object objectToSerialize, IEndPointContext context) public byte[] Serialize(object objectToSerialize, IEndPointContext context)
{ {
byte[] result; var writer = _writer.Value;
lock (_writer) writer.Reset();
{ WriteData(objectToSerialize, writer, context);
_writer.Reset(); var result = new byte[_offset + writer.BytesWritten];
WriteData(objectToSerialize, _writer, context); var span = result.AsSpan();
result = _writer.Encode(); writer.Encode(span[_offset..]);
}
return result; return result;
} }
public int Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext context) public int Serialize(object objectToSerialize, Span<byte> destination, IEndPointContext context)
{ {
lock (_writer) var writer = _writer.Value;
{ writer.Reset();
_writer.Reset(); WriteData(objectToSerialize, writer, context);
WriteData(objectToSerialize, _writer, context); return writer.Encode(destination);
return _writer.Encode(destination);
}
} }
public T Deserialize<T>(byte[] rawData, IEndPointContext? context) public T Deserialize<T>(byte[] rawData, IEndPointContext? context)
@@ -88,14 +100,18 @@ namespace mROA.Cbor
} }
public object? Deserialize(ReadOnlyMemory<byte> rawMemory, Type type, IEndPointContext? context) public object? Deserialize(ReadOnlyMemory<byte> rawMemory, Type type, IEndPointContext? context)
{
try
{ {
var reader = new CborReader(rawMemory); var reader = new CborReader(rawMemory);
return ReadData(reader, type, context); return ReadData(reader, type, context);
} }
catch (Exception)
public T Cast<T>(object nonCasted, IEndPointContext? context)
{ {
return (T)Cast(nonCasted, typeof(T), context); Console.WriteLine(
$"Bad deserialization for type {type}. Bytes: {BitConverter.ToString(rawMemory.ToArray())}");
throw;
}
} }
public object? Cast(object? nonCasted, Type type, IEndPointContext? context) public object? Cast(object? nonCasted, Type type, IEndPointContext? context)
@@ -115,12 +131,17 @@ namespace mROA.Cbor
return new RequestId((byte[])nonCasted); return new RequestId((byte[])nonCasted);
} }
if (type.IsInterface)
{
return ReadSharedShell(type, context, (ulong)nonCasted);
}
return Convert.ChangeType(nonCasted, type); return Convert.ChangeType(nonCasted, type);
} }
public IContextualSerializationToolKit Clone() public IContextualSerializationToolKit Clone()
{ {
return new CborSerializationToolkit(); return new CborSerializationToolkit(_offset);
} }
public void WriteData(object? obj, CborWriter writer, IEndPointContext? context) public void WriteData(object? obj, CborWriter writer, IEndPointContext? context)
@@ -182,9 +203,20 @@ namespace mROA.Cbor
WriteObject(sharedObject, writer, context); WriteObject(sharedObject, writer, context);
break; break;
default: default:
if (obj.GetType().IsEnum) var objType = obj.GetType();
if (objType.IsEnum)
{ {
writer.WriteInt32((int)obj); var basicType = Enum.GetUnderlyingType(obj.GetType());
if (basicType == typeof(byte))
{
writer.WriteInt32((byte)obj);
}
else if (basicType == typeof(int))
{
writer.WriteInt32((byte)obj);
}
break; break;
} }
@@ -235,9 +267,7 @@ namespace mROA.Cbor
Activator.CreateInstance(sharedShell, obj, context) as Activator.CreateInstance(sharedShell, obj, context) as
ISharedObjectShell; ISharedObjectShell;
writer.WriteStartArray(1);
writer.WriteUInt64(so.Identifier.Flat); writer.WriteUInt64(so.Identifier.Flat);
writer.WriteEndArray();
return; return;
} }
@@ -267,6 +297,10 @@ namespace mROA.Cbor
return reader.ReadInt64(); return reader.ReadInt64();
if (type == typeof(uint)) if (type == typeof(uint))
return reader.ReadUInt32(); return reader.ReadUInt32();
if (type.IsInterface)
{
return ReadSharedShell(type, context, reader.ReadUInt64());
}
return reader.ReadUInt64(); return reader.ReadUInt64();
case CborReaderState.ByteString: case CborReaderState.ByteString:
@@ -378,19 +412,9 @@ namespace mROA.Cbor
if (type.IsInterface) if (type.IsInterface)
{ {
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type);
var so =
Activator.CreateInstance(sharedShell) as
ISharedObjectShell;
if (context != null)
so.EndPointContext = context;
reader.ReadStartArray();
var identifier = reader.ReadUInt64(); var identifier = reader.ReadUInt64();
reader.ReadEndArray();
so.Identifier = ComplexObjectIdentifier.FromFlat(identifier); return ReadSharedShell(type, context, identifier);
return so.UniversalValue;
} }
var instance = Activator.CreateInstance(type)!; var instance = Activator.CreateInstance(type)!;
@@ -400,6 +424,20 @@ namespace mROA.Cbor
return instance; return instance;
} }
private static object ReadSharedShell(Type type, IEndPointContext? context, ulong identifier)
{
var sharedShell = typeof(SharedObjectShellShell<>).MakeGenericType(type);
var so =
Activator.CreateInstance(sharedShell) as
ISharedObjectShell;
if (context != null)
so.EndPointContext = context;
so.Identifier = ComplexObjectIdentifier.FromFlat(identifier);
return so.UniversalValue;
}
private ISharedObjectShell ReadSharedObject(CborReader reader, Type type, IEndPointContext? context) private ISharedObjectShell ReadSharedObject(CborReader reader, Type type, IEndPointContext? context)
{ {
var sharedObject = (Activator.CreateInstance(type) as ISharedObjectShell)!; var sharedObject = (Activator.CreateInstance(type) as ISharedObjectShell)!;
@@ -427,6 +465,15 @@ namespace mROA.Cbor
{ {
var property = properties[index]; var property = properties[index];
var value = ReadData(reader, property.PropertyType, context); var value = ReadData(reader, property.PropertyType, context);
if (property.PropertyType.IsEnum)
{
if (property.PropertyType.GetEnumUnderlyingType() == typeof(byte))
{
value = Convert.ChangeType(value, typeof(byte));
}
}
property.SetValue(obj, value); property.SetValue(obj, value);
} }
+13 -12
View File
@@ -1,5 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Formats.Cbor; using System.Formats.Cbor;
using System.Runtime.InteropServices;
using mROA.Abstract; using mROA.Abstract;
using mROA.Implementation; using mROA.Implementation;
using mROA.Implementation.CommandExecution; using mROA.Implementation.CommandExecution;
@@ -14,16 +16,15 @@ namespace mROA.Cbor
public class CallRequestParser : IOrdinaryStructureParser public class CallRequestParser : IOrdinaryStructureParser
{ {
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) public void Write(CborWriter writer, object value, IEndPointContext context,
CborSerializationToolkit serialization)
{ {
var v = (CallRequest)value; var v = (CallRequest)value;
writer.WriteStartArray(4); writer.WriteStartArray(4);
v.Id.WriteToCborInline(writer); v.Id.WriteToCborInline(writer);
// writer.WriteByteString(v.Id.ToByteArray()); // writer.WriteByteString(v.Id.ToByteArray());
writer.WriteInt32(v.CommandId); writer.WriteInt32(v.CommandId);
writer.WriteStartArray(1);
writer.WriteUInt64(v.ObjectId.Flat); writer.WriteUInt64(v.ObjectId.Flat);
writer.WriteEndArray();
serialization.WriteData(v.Parameters, writer, context); serialization.WriteData(v.Parameters, writer, context);
writer.WriteEndArray(); writer.WriteEndArray();
} }
@@ -35,7 +36,8 @@ namespace mROA.Cbor
{ {
Id = new RequestId(reader.ReadByteString()), Id = new RequestId(reader.ReadByteString()),
CommandId = reader.ReadInt32(), CommandId = reader.ReadInt32(),
ObjectId = (ComplexObjectIdentifier)ComplexObjectIdentifierParser.Instance.Read(reader, context, serialization), ObjectId = (ComplexObjectIdentifier)ComplexObjectIdentifierParser.Instance.Read(reader, context,
serialization),
Parameters = serialization.ReadData(reader, typeof(object[]), context) as object[] Parameters = serialization.ReadData(reader, typeof(object[]), context) as object[]
}; };
reader.ReadEndArray(); reader.ReadEndArray();
@@ -46,25 +48,24 @@ namespace mROA.Cbor
public class ComplexObjectIdentifierParser : IOrdinaryStructureParser public class ComplexObjectIdentifierParser : IOrdinaryStructureParser
{ {
public static readonly ComplexObjectIdentifierParser Instance = new(); public static readonly ComplexObjectIdentifierParser Instance = new();
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization)
public void Write(CborWriter writer, object value, IEndPointContext context,
CborSerializationToolkit serialization)
{ {
writer.WriteStartArray(1);
writer.WriteUInt64(((ComplexObjectIdentifier)value).Flat); writer.WriteUInt64(((ComplexObjectIdentifier)value).Flat);
writer.WriteEndArray();
} }
public object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization) public object Read(CborReader reader, IEndPointContext context, CborSerializationToolkit serialization)
{ {
reader.ReadStartArray();
var value = new ComplexObjectIdentifier { Flat = reader.ReadUInt64() }; var value = new ComplexObjectIdentifier { Flat = reader.ReadUInt64() };
reader.ReadEndArray();
return value; return value;
} }
} }
public class FinalCommandExecutionParser : IOrdinaryStructureParser public class FinalCommandExecutionParser : IOrdinaryStructureParser
{ {
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) public void Write(CborWriter writer, object value, IEndPointContext context,
CborSerializationToolkit serialization)
{ {
var v = (FinalCommandExecution<object>)value; var v = (FinalCommandExecution<object>)value;
writer.WriteStartArray(2); writer.WriteStartArray(2);
@@ -89,11 +90,11 @@ namespace mROA.Cbor
public class FinalCommandExecutionResultlessParser : IOrdinaryStructureParser public class FinalCommandExecutionResultlessParser : IOrdinaryStructureParser
{ {
public void Write(CborWriter writer, object value, IEndPointContext context, CborSerializationToolkit serialization) public void Write(CborWriter writer, object value, IEndPointContext context,
CborSerializationToolkit serialization)
{ {
var v = (FinalCommandExecution)value; var v = (FinalCommandExecution)value;
writer.WriteStartArray(1); writer.WriteStartArray(1);
// writer.WriteByteString(v.Id.ToByteArray());
v.Id.WriteToCborInline(writer); v.Id.WriteToCborInline(writer);
writer.WriteEndArray(); writer.WriteEndArray();
} }
+2 -2
View File
@@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>2.0.7</Version> <Version>3.0.4</Version>
<LangVersion>9</LangVersion> <LangVersion>9</LangVersion>
<PackageIcon>mroaLogo.png</PackageIcon> <PackageIcon>mroaLogo.png</PackageIcon>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@@ -31,6 +31,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="System.Formats.Cbor" Version="9.0.7" /> <PackageReference Include="System.Formats.Cbor" Version="9.0.8" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+1
View File
@@ -23,6 +23,7 @@ namespace mROA.Codegen
ReturnType = typeof(<!L returnType>), ReturnType = typeof(<!L returnType>),
ParameterTypes = new Type[] { <!L parametersType> }, ParameterTypes = new Type[] { <!L parametersType> },
SuitableType = typeof(<!L suitableType>), SuitableType = typeof(<!L suitableType>),
RequireCancellation = <!L cancellation>,
Invoking = (i, parameters, special, post) => <!L funcInvoking>, Invoking = (i, parameters, special, post) => <!L funcInvoking>,
}<!T> }<!T>
<!T syncInvoker> <!T syncInvoker>
-1
View File
@@ -26,7 +26,6 @@ namespace mROA.Codegen
<!T eventBinderTemplate> <!T eventBinderTemplate>
(instance as <!L type>).<!L eventName> += (<!L parametersDeclaration>) => (instance as <!L type>).<!L eventName> += (<!L parametersDeclaration>) =>
{ {
Console.WriteLine($"Try to send to {ownerId} with hash code {context.GetHashCode()}");
<!I callFilter> <!I callFilter>
Console.WriteLine("Sending event..."); Console.WriteLine("Sending event...");
var request = new CallRequest var request = new CallRequest
@@ -11,7 +11,9 @@ namespace mROA.Codegen.Templates
private const string CommandIdTag = "commandId"; private const string CommandIdTag = "commandId";
private const string TransferParametersTag = "transferParameters"; private const string TransferParametersTag = "transferParameters";
public EventBinderTemplate(TemplateDocument template) : base(template) { } public EventBinderTemplate(TemplateDocument template) : base(template)
{
}
public void DefineCallFilter(string value) public void DefineCallFilter(string value)
{ {
@@ -10,7 +10,9 @@ namespace mROA.Codegen.Templates
private const string IndexSpanTag = "indexSpan"; private const string IndexSpanTag = "indexSpan";
private const string RemoteTypePairTag = "remoteTypePair"; private const string RemoteTypePairTag = "remoteTypePair";
public IndexProviderTemplate() : base(TemplateFile) { } public IndexProviderTemplate() : base(TemplateFile)
{
}
public void DefineNamespace(string value) public void DefineNamespace(string value)
{ {
+9 -1
View File
@@ -9,9 +9,12 @@ namespace mROA.Codegen.Templates
private const string ParametersTypeTag = "parametersType"; private const string ParametersTypeTag = "parametersType";
private const string SuitableTypeTag = "suitableType"; private const string SuitableTypeTag = "suitableType";
private const string FuncInvokingTag = "funcInvoking"; private const string FuncInvokingTag = "funcInvoking";
private const string CancellationTag = "cancellation";
private const string IsTrustedTag = "isTrusted"; private const string IsTrustedTag = "isTrusted";
public InvokerTemplate(TemplateDocument template) : base(template) { } public InvokerTemplate(TemplateDocument template) : base(template)
{
}
public void DefineIsVoid(string value) public void DefineIsVoid(string value)
{ {
@@ -42,5 +45,10 @@ namespace mROA.Codegen.Templates
{ {
Define(IsTrustedTag, value); Define(IsTrustedTag, value);
} }
public void DefineCancellation(string value)
{
Define(CancellationTag, value);
}
} }
} }
+3 -1
View File
@@ -9,7 +9,9 @@ namespace mROA.Codegen.Templates
private const string InvokerTag = "invoker"; private const string InvokerTag = "invoker";
public MethodRepoTemplate() : base(TemplateFile) { } public MethodRepoTemplate() : base(TemplateFile)
{
}
public void InsertInvoke(string value) public void InsertInvoke(string value)
{ {
@@ -9,7 +9,9 @@ namespace mROA.Codegen.Templates
private const string TypeTag = "type"; private const string TypeTag = "type";
private const string EventBinderTag = "eventBinder"; private const string EventBinderTag = "eventBinder";
public ObjectBinderTemplate(TemplateDocument template) : base(template) { } public ObjectBinderTemplate(TemplateDocument template) : base(template)
{
}
public void DefineType(string value) public void DefineType(string value)
{ {
@@ -8,7 +8,9 @@ namespace mROA.Codegen.Templates
private const string NamespaceTag = "namespace"; private const string NamespaceTag = "namespace";
private const string SignatureTag = "signature"; private const string SignatureTag = "signature";
public PartialInterfaceTemplate() : base(TemplateFile) { } public PartialInterfaceTemplate() : base(TemplateFile)
{
}
public void DefineName(string value) public void DefineName(string value)
{ {
+3 -1
View File
@@ -9,7 +9,9 @@ namespace mROA.Codegen.Templates
private const string NamespaceNameTag = "namespaceName"; private const string NamespaceNameTag = "namespaceName";
private const string MethodsTag = "methods"; private const string MethodsTag = "methods";
public ProxyTemplate() : base(TemplateFile) { } public ProxyTemplate() : base(TemplateFile)
{
}
public void DefineClassName(string value) public void DefineClassName(string value)
{ {
@@ -7,7 +7,9 @@ namespace mROA.Codegen.Templates
private const string ObjectBinderTemplateTag = "objectBinderTemplate"; private const string ObjectBinderTemplateTag = "objectBinderTemplate";
private const string EventBinderTag = "eventBinder"; private const string EventBinderTag = "eventBinder";
public RemoteTypeBinderTemplate() : base(TemplateFile) { } public RemoteTypeBinderTemplate() : base(TemplateFile)
{
}
public ObjectBinderTemplate CloneInnerObjectBinder() public ObjectBinderTemplate CloneInnerObjectBinder()
{ {
+9 -1
View File
@@ -17,10 +17,18 @@
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl> <RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Version>2.0.7</Version> <Version>3.0.3</Version>
<PackageIcon>mroaLogo.png</PackageIcon> <PackageIcon>mroaLogo.png</PackageIcon>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<PackageLicenseFile>LICENSE-2.0.txt</PackageLicenseFile>
</PropertyGroup>
<ItemGroup>
<None Include="LICENSE-2.0.txt" Pack="true" PackagePath="$(PackageLicenseFile)"/>
</ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4"> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
+34 -14
View File
@@ -137,15 +137,18 @@ namespace mROA.Codegen
// declaredMethods.Add(impl); // declaredMethods.Add(impl);
break; break;
case IEventSymbol eventSymbol: case IEventSymbol eventSymbol:
proxyTemplate.InsertMethods($"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};"); proxyTemplate.InsertMethods(
$"public event {eventSymbol.Type.ToUnityString()}? {eventSymbol.Name};");
// declaredMethods.Add( // declaredMethods.Add(
// $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};"); // $"public event {eventSymbol.Type.ToDisplayString()}? {eventSymbol.Name};");
break; break;
} }
GenerateEventImplementation(proxyTemplate, methodRepoTemplate, typeBinder, classSymbol, invokers, context); GenerateEventImplementation(proxyTemplate, methodRepoTemplate, typeBinder, classSymbol, invokers,
context);
var endInvokers = invokers.Count; var endInvokers = invokers.Count;
indexProviderTemplate.InsertIndexSpan($"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},"); indexProviderTemplate.InsertIndexSpan(
$"{{ typeof({originalName}), new[] {{ {CodegenUtilities.JoinWithComa(Enumerable.Range(startInvokers, endInvokers - startInvokers).Select(i => i.ToString()))} }} }},");
proxyTemplate.DefineClassName(className); proxyTemplate.DefineClassName(className);
proxyTemplate.DefineOriginalName(originalName); proxyTemplate.DefineOriginalName(originalName);
proxyTemplate.DefineNamespaceName(namespaceName); proxyTemplate.DefineNamespaceName(namespaceName);
@@ -157,7 +160,8 @@ namespace mROA.Codegen
#if !DONT_ADD #if !DONT_ADD
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8)); context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
#endif #endif
indexProviderTemplate.InsertRemoteTypePair($"{{ typeof({classSymbol.ToUnityString()}), (id, r, c, indices) => new {namespaceName}.{className}(id, r, c, indices) }}"); indexProviderTemplate.InsertRemoteTypePair(
$"{{ typeof({classSymbol.ToUnityString()}), (id, r, c, indices) => new {namespaceName}.{className}(id, r, c, indices) }}");
} }
if (totalMethods.Count != 0) if (totalMethods.Count != 0)
@@ -184,7 +188,8 @@ namespace mROA.Codegen
} }
} }
private void GenerateEventImplementation(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate, RemoteTypeBinderTemplate remoteTypeBinder, INamedTypeSymbol classSymbol, private void GenerateEventImplementation(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate,
RemoteTypeBinderTemplate remoteTypeBinder, INamedTypeSymbol classSymbol,
List<string> invokers, SourceProductionContext context) List<string> invokers, SourceProductionContext context)
{ {
var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers()) var events = classSymbol.AllInterfaces.Add(classSymbol).SelectMany(i => i.GetMembers())
@@ -235,7 +240,8 @@ namespace mROA.Codegen
return caller; return caller;
} }
private void GenerateDeclaredMethod(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate, IMethodSymbol method, List<string> invokers, private void GenerateDeclaredMethod(ProxyTemplate proxyTemplate, MethodRepoTemplate methodRepoTemplate,
IMethodSymbol method, List<string> invokers,
INamedTypeSymbol baseInterface) INamedTypeSymbol baseInterface)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
@@ -316,11 +322,14 @@ namespace mROA.Codegen
var parametersInsertList = new List<string>(); var parametersInsertList = new List<string>();
var useCancellationToken = false;
foreach (var parameter in method.Parameters) foreach (var parameter in method.Parameters)
switch (parameter.Type.Name) switch (parameter.Type.Name)
{ {
case "CancellationToken": case "CancellationToken":
parametersInsertList.Add("(CancellationToken)special[1]"); parametersInsertList.Add("(CancellationToken)special[1]");
useCancellationToken = true;
break; break;
case "RequestContext": case "RequestContext":
parametersInsertList.Add("(RequestContext)special[0]"); parametersInsertList.Add("(RequestContext)special[0]");
@@ -359,6 +368,7 @@ namespace mROA.Codegen
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking(funcInvoking); invokerTemplate.DefineFuncInvoking(funcInvoking);
invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower());
invokerTemplate.DefineCancellation(useCancellationToken.ToString().ToLower());
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
else else
@@ -370,6 +380,7 @@ namespace mROA.Codegen
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking(funcInvoking); invokerTemplate.DefineFuncInvoking(funcInvoking);
invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower()); invokerTemplate.DefineIsTrusted((!isUntrusted).ToString().ToLower());
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
} }
@@ -378,7 +389,8 @@ namespace mROA.Codegen
invokers.Add(backend); invokers.Add(backend);
} }
private void GenerateBinderCode(ObjectBinderTemplate objectBinderTemplate, IEventSymbol eventSymbol, INamedTypeSymbol baseType) private void GenerateBinderCode(ObjectBinderTemplate objectBinderTemplate, IEventSymbol eventSymbol,
INamedTypeSymbol baseType)
{ {
var eventBinderTemplate = objectBinderTemplate.CloneInnerEventBinder(); var eventBinderTemplate = objectBinderTemplate.CloneInnerEventBinder();
@@ -403,13 +415,15 @@ namespace mROA.Codegen
eventBinderTemplate.DefineType(baseType.ToUnityString()); eventBinderTemplate.DefineType(baseType.ToUnityString());
eventBinderTemplate.DefineEventName(eventSymbol.Name); eventBinderTemplate.DefineEventName(eventSymbol.Name);
eventBinderTemplate.DefineParametersDeclaration(parametersDeclaration); eventBinderTemplate.DefineParametersDeclaration(parametersDeclaration);
eventBinderTemplate.DefineCommandIdTag($"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]"); eventBinderTemplate.DefineCommandIdTag(
$"context.CallIndexProvider.GetIndices(typeof({baseType.ToUnityString()}))[{index}]");
eventBinderTemplate.DefineTransferParameters(transferParameters); eventBinderTemplate.DefineTransferParameters(transferParameters);
var eventBinderCode = eventBinderTemplate.Compile(); var eventBinderCode = eventBinderTemplate.Compile();
objectBinderTemplate.InsertEventBinder(eventBinderCode); objectBinderTemplate.InsertEventBinder(eventBinderCode);
} }
private void GenerateEventCode(MethodRepoTemplate methodRepoTemplate, IEventSymbol eventSymbol, List<string> invokers, ITypeSymbol baseInterface) private void GenerateEventCode(MethodRepoTemplate methodRepoTemplate, IEventSymbol eventSymbol,
List<string> invokers, ITypeSymbol baseInterface)
{ {
var level = "\t\t\t"; var level = "\t\t\t";
@@ -482,7 +496,8 @@ namespace mROA.Codegen
invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString());
invokerTemplate.DefineParametersType(parameterTypes); invokerTemplate.DefineParametersType(parameterTypes);
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]"); invokerTemplate.DefineFuncInvoking(
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}]");
invokerTemplate.DefineIsTrusted("true"); invokerTemplate.DefineIsTrusted("true");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
@@ -494,7 +509,8 @@ namespace mROA.Codegen
invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString());
invokerTemplate.DefineParametersType(""); invokerTemplate.DefineParametersType("");
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}"); invokerTemplate.DefineFuncInvoking(
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name}");
invokerTemplate.DefineIsTrusted("true"); invokerTemplate.DefineIsTrusted("true");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
@@ -524,7 +540,8 @@ namespace mROA.Codegen
invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString());
invokerTemplate.DefineParametersType(parameterTypes); invokerTemplate.DefineParametersType(parameterTypes);
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}"); invokerTemplate.DefineFuncInvoking(
$"(i as {method.ContainingType.ToUnityString()})[{parameterInserts}] = {valueInsert}");
invokerTemplate.DefineIsTrusted("true"); invokerTemplate.DefineIsTrusted("true");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
@@ -536,7 +553,8 @@ namespace mROA.Codegen
invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString()); invokerTemplate.DefineReturnType(method.ReturnType.ToUnityString());
invokerTemplate.DefineParametersType($"typeof({method.Parameters.First().Type.ToUnityString()})"); invokerTemplate.DefineParametersType($"typeof({method.Parameters.First().Type.ToUnityString()})");
invokerTemplate.DefineSuitableType(baseInterface.ToUnityString()); invokerTemplate.DefineSuitableType(baseInterface.ToUnityString());
invokerTemplate.DefineFuncInvoking($"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {CodegenUtilities.Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}"); invokerTemplate.DefineFuncInvoking(
$"(i as {method.ContainingType.ToUnityString()}).{(method.AssociatedSymbol as IPropertySymbol)!.Name} = {CodegenUtilities.Caster((method.AssociatedSymbol as IPropertySymbol)!.Type, "parameters[0]")}");
invokerTemplate.DefineIsTrusted("true"); invokerTemplate.DefineIsTrusted("true");
backend = invokerTemplate.Compile(); backend = invokerTemplate.Compile();
@@ -575,7 +593,9 @@ namespace mROA.Codegen
public static string ToFullString(IParameterSymbol parameter) public static string ToFullString(IParameterSymbol parameter)
{ {
return parameter.Type.ToUnityString() + " " + parameter.Name; var coreString = $"{parameter.Type.ToUnityString()} {parameter.Name}";
if (parameter.RefKind == RefKind.In) coreString = $"in {coreString}";
return coreString;
} }
public static string ToFullString(ITypeSymbol type) public static string ToFullString(ITypeSymbol type)
+22
View File
@@ -0,0 +1,22 @@
using mROA.Benchmark;
namespace mROA.Test;
[TestFixture]
public class BenchmarkTest
{
[Test]
public void Benchmark()
{
var bench = new TaskWaiting();
var x = bench.DefaultJob();
var y = bench.DefaultJobAsync();
y.Wait();
if (x == y.Result)
{
Assert.Pass();
}
Assert.Fail();
}
}
+23
View File
@@ -0,0 +1,23 @@
using System;
using System.Threading.Tasks;
using mROA.Implementation;
namespace mROA.Test;
[TestFixture]
public class ConcurrentTest
{
private CircularMemoryManager _cmm;
[SetUp]
public void Setup()
{
_cmm = new CircularMemoryManager(100);
}
[Test]
public void ParallelAlloc()
{
Assert.Fail();
}
}
+1
View File
@@ -27,6 +27,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\mROA.Benchmark\mROA.Benchmark.csproj" />
<ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" /> <ProjectReference Include="..\mROA.Cbor\mROA.Cbor.csproj" />
<ProjectReference Include="..\mROA\mROA.csproj" /> <ProjectReference Include="..\mROA\mROA.csproj" />
</ItemGroup> </ItemGroup>
-10
View File
@@ -25,10 +25,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.CodegenTools", "mROA.C
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Load", "Example.Load\Example.Load.csproj", "{930B236B-BDAA-4B8C-8054-5B992BAE6622}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.Load", "Example.Load\Example.Load.csproj", "{930B236B-BDAA-4B8C-8054-5B992BAE6622}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Functionality.Shared", "Functionality.Shared\Functionality.Shared.csproj", "{D9D28596-E10C-4A98-A2AA-573219467506}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{8C20901F-B416-4ABC-8AA4-9059646B081B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{E021E8B3-56C2-400E-A05E-523CF7831189}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "mROA.Benchmark", "mROA.Benchmark\mROA.Benchmark.csproj", "{E021E8B3-56C2-400E-A05E-523CF7831189}"
EndProject EndProject
Global Global
@@ -73,10 +69,6 @@ Global
{930B236B-BDAA-4B8C-8054-5B992BAE6622}.Debug|Any CPU.Build.0 = Debug|Any CPU {930B236B-BDAA-4B8C-8054-5B992BAE6622}.Debug|Any CPU.Build.0 = Debug|Any CPU
{930B236B-BDAA-4B8C-8054-5B992BAE6622}.Release|Any CPU.ActiveCfg = Release|Any CPU {930B236B-BDAA-4B8C-8054-5B992BAE6622}.Release|Any CPU.ActiveCfg = Release|Any CPU
{930B236B-BDAA-4B8C-8054-5B992BAE6622}.Release|Any CPU.Build.0 = Release|Any CPU {930B236B-BDAA-4B8C-8054-5B992BAE6622}.Release|Any CPU.Build.0 = Release|Any CPU
{D9D28596-E10C-4A98-A2AA-573219467506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9D28596-E10C-4A98-A2AA-573219467506}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9D28596-E10C-4A98-A2AA-573219467506}.Release|Any CPU.Build.0 = Release|Any CPU
{E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.Build.0 = Debug|Any CPU {E021E8B3-56C2-400E-A05E-523CF7831189}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.ActiveCfg = Release|Any CPU {E021E8B3-56C2-400E-A05E-523CF7831189}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -91,7 +83,5 @@ Global
{9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} {9BD25A13-3165-47C0-9EAA-5C59EC490E32} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} {E7703F5B-F2A6-4A88-AA57-EBB1E38D533E} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{930B236B-BDAA-4B8C-8054-5B992BAE6622} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E} {930B236B-BDAA-4B8C-8054-5B992BAE6622} = {FC4FA752-10A7-4D78-A7C2-9BCD8A81FB5E}
{8C20901F-B416-4ABC-8AA4-9059646B081B} = {EAE92F5A-664C-41AB-8811-5885524B5347}
{D9D28596-E10C-4A98-A2AA-573219467506} = {8C20901F-B416-4ABC-8AA4-9059646B081B}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
+10
View File
@@ -0,0 +1,10 @@
using System;
using mROA.Implementation;
namespace mROA.Abstract
{
public interface IDistributionModule
{
Action<NetworkMessage> GetDistributionAction(int clientId);
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ namespace mROA.Abstract
{ {
ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository, ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository,
IRepresentationModule representationModule, IEndPointContext context); IRepresentationModule representationModule, IEndPointContext context);
ICommandExecution Cancel(CancelRequest command);
ICommandExecution Cancel(CancelRequest command);
} }
} }
+2 -1
View File
@@ -25,7 +25,8 @@ namespace mROA.Abstract
void PostCallMessage<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context) void PostCallMessage<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context)
where T : notnull; where T : notnull;
Task PostCallMessageUntrustedAsync<T>(RequestId id, EMessageType eMessageType, T payload, IEndPointContext? context) Task PostCallMessageUntrustedAsync<T>(RequestId id, EMessageType eMessageType, T payload,
IEndPointContext? context)
where T : notnull; where T : notnull;
} }
} }
+1 -1
View File
@@ -7,7 +7,7 @@ namespace mROA.Abstract
public interface IRequestExtractor public interface IRequestExtractor
{ {
Task StartExtraction(); Task StartExtraction();
void PushMessage(object parced, EMessageType originalType); void PushMessage(object parsed, EMessageType originalType);
Predicate<NetworkMessage> Rule { get; } Predicate<NetworkMessage> Rule { get; }
Func<NetworkMessage, Type?>[] Converters { get; } Func<NetworkMessage, Type?>[] Converters { get; }
} }
@@ -10,7 +10,6 @@ namespace mROA.Implementation.Backend
private readonly ICancellationRepository _cancellationRepo; private readonly ICancellationRepository _cancellationRepo;
private readonly IMethodRepository _methodRepo; private readonly IMethodRepository _methodRepo;
private readonly IContextualSerializationToolKit _serialization; private readonly IContextualSerializationToolKit _serialization;
public BasicExecutionModule(ICancellationRepository cancellationRepo, IMethodRepository methodRepo, public BasicExecutionModule(ICancellationRepository cancellationRepo, IMethodRepository methodRepo,
IContextualSerializationToolKit serialization) IContextualSerializationToolKit serialization)
{ {
@@ -18,11 +17,9 @@ namespace mROA.Implementation.Backend
_methodRepo = methodRepo; _methodRepo = methodRepo;
_serialization = serialization; _serialization = serialization;
} }
public ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository, public ICommandExecution? Execute(CallRequest command, IInstanceRepository instanceRepository,
IRepresentationModule representationModule, IEndPointContext endPointContext) IRepresentationModule representationModule, IEndPointContext endPointContext)
{ {
// _logger.LogInformation("Executing {0}", command.Id);
try try
{ {
var invoker = _methodRepo.GetMethod(command.CommandId); var invoker = _methodRepo.GetMethod(command.CommandId);
@@ -57,7 +54,6 @@ namespace mROA.Implementation.Backend
}; };
} }
} }
private ICommandExecution? ExecuteRequest(CallRequest command, IInstanceRepository instanceRepository, private ICommandExecution? ExecuteRequest(CallRequest command, IInstanceRepository instanceRepository,
IRepresentationModule representationModule, IEndPointContext endPointContext, IMethodInvoker invoker, IRepresentationModule representationModule, IEndPointContext endPointContext, IMethodInvoker invoker,
object context, object?[]? castedParams, RequestContext execContext) object context, object?[]? castedParams, RequestContext execContext)
@@ -81,7 +77,6 @@ namespace mROA.Implementation.Backend
return result; return result;
} }
} }
private static object GetInstance(CallRequest command, IInstanceRepository instanceRepository, private static object GetInstance(CallRequest command, IInstanceRepository instanceRepository,
IMethodInvoker invoker, IEndPointContext endPointContext) IMethodInvoker invoker, IEndPointContext endPointContext)
{ {
@@ -91,7 +86,6 @@ namespace mROA.Implementation.Backend
return context; return context;
} }
private object?[] CastedParams(CallRequest command, IMethodInvoker invoker, IEndPointContext context) private object?[] CastedParams(CallRequest command, IMethodInvoker invoker, IEndPointContext context)
{ {
object?[] castedParams = new object[invoker.ParameterTypes.Length]; object?[] castedParams = new object[invoker.ParameterTypes.Length];
@@ -102,7 +96,6 @@ namespace mROA.Implementation.Backend
return castedParams; return castedParams;
} }
public ICommandExecution Cancel(CancelRequest command) public ICommandExecution Cancel(CancelRequest command)
{ {
var cts = _cancellationRepo.GetCancellation(command.Id); var cts = _cancellationRepo.GetCancellation(command.Id);
@@ -116,7 +109,6 @@ namespace mROA.Implementation.Backend
Id = command.Id Id = command.Id
}; };
} }
private static ICommandExecution? Execute(MethodInvoker invoker, object instance, object?[] parameter, private static ICommandExecution? Execute(MethodInvoker invoker, object instance, object?[] parameter,
CallRequest command, RequestContext executionContext) CallRequest command, RequestContext executionContext)
{ {
@@ -141,25 +133,33 @@ namespace mROA.Implementation.Backend
Id = command.Id Id = command.Id
}; };
} }
private ICommandExecution? ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, private ICommandExecution? ExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
CallRequest command, ICancellationRepository cancellationRepository, CallRequest command, ICancellationRepository cancellationRepository,
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
{
CancellationToken? token = null;
if (invoker.RequireCancellation)
{ {
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
cancellationRepository.RegisterCancellation(command.Id, tokenSource); cancellationRepository.RegisterCancellation(command.Id, tokenSource);
var token = tokenSource.Token;
token = tokenSource.Token;
}
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ => invoker.Invoke(instance, parameters, new object[] { executionContext, token }, _ =>
{ {
if (token.IsCancellationRequested) if (invoker.RequireCancellation)
{
_cancellationRepo.FreeCancellation(command.Id);
if (token.Value.IsCancellationRequested)
return; return;
}
var payload = new FinalCommandExecution var payload = new FinalCommandExecution
{ {
Id = command.Id Id = command.Id
}; };
_cancellationRepo.FreeCancellation(command.Id);
if (invoker.IsTrusted) if (invoker.IsTrusted)
@@ -170,25 +170,35 @@ namespace mROA.Implementation.Backend
return null; return null;
} }
private ICommandExecution? TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters, private ICommandExecution? TypedExecuteAsync(AsyncMethodInvoker invoker, object instance, object?[]? parameters,
CallRequest command, ICancellationRepository cancellationRepository, CallRequest command, ICancellationRepository cancellationRepository,
IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context) IRepresentationModule representationModule, RequestContext executionContext, IEndPointContext context)
{
CancellationToken? token = null;
if (invoker.RequireCancellation)
{ {
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
cancellationRepository.RegisterCancellation(command.Id, tokenSource); cancellationRepository.RegisterCancellation(command.Id, tokenSource);
var token = tokenSource.Token; token = tokenSource.Token;
}
invoker.Invoke(instance, parameters, new object[] { executionContext, token }, invoker.Invoke(instance, parameters, new object[] { executionContext, token },
finalResult => finalResult =>
{ {
if (invoker.RequireCancellation)
{
_cancellationRepo.FreeCancellation(command.Id);
if (token.Value.IsCancellationRequested)
return;
}
var payload = new FinalCommandExecution<object> var payload = new FinalCommandExecution<object>
{ {
Id = command.Id, Id = command.Id,
Result = finalResult Result = finalResult
}; };
_cancellationRepo.FreeCancellation(command.Id);
representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution, representationModule.PostCallMessageAsync(command.Id, EMessageType.FinishedCommandExecution,
payload, context); payload, context);
@@ -14,15 +14,14 @@ namespace mROA.Implementation.Backend
private readonly TcpListener _tcpListener; private readonly TcpListener _tcpListener;
private readonly IConnectionHub _hub; private readonly IConnectionHub _hub;
private readonly HubRequestExtractor _hre; private readonly HubRequestExtractor _hre;
private readonly DistributionOptions _distribution; private readonly IDistributionModule _distribution;
private readonly IContextualSerializationToolKit _serialization; private readonly IContextualSerializationToolKit _serialization;
private readonly Dictionary<int, CancellationTokenSource> _extractorsTokenSources = new(); private readonly Dictionary<int, CancellationTokenSource> _extractorsTokenSources = new();
private readonly ICallIndexProvider _callIndexProvider; private readonly ICallIndexProvider _callIndexProvider;
private readonly IIdentityGenerator _identityGenerator; private readonly IIdentityGenerator _identityGenerator;
public NetworkGatewayModule(IOptions<GatewayOptions> options, IIdentityGenerator identityGenerator, public NetworkGatewayModule(IOptions<GatewayOptions> options, IIdentityGenerator identityGenerator,
IContextualSerializationToolKit serialization, ICallIndexProvider callIndexProvider, IConnectionHub hub, IContextualSerializationToolKit serialization, ICallIndexProvider callIndexProvider, IConnectionHub hub, HubRequestExtractor hre, IDistributionModule distribution)
IOptions<DistributionOptions> distribution, HubRequestExtractor hre)
{ {
_tcpListener = new(options.Value.Endpoint); _tcpListener = new(options.Value.Endpoint);
_identityGenerator = identityGenerator; _identityGenerator = identityGenerator;
@@ -30,7 +29,7 @@ namespace mROA.Implementation.Backend
_callIndexProvider = callIndexProvider; _callIndexProvider = callIndexProvider;
_hub = hub; _hub = hub;
_hre = hre; _hre = hre;
_distribution = distribution.Value; _distribution = distribution;
} }
public void Run() public void Run()
@@ -58,6 +57,7 @@ namespace mROA.Implementation.Backend
private async Task HandleConnection(TcpClient client) private async Task HandleConnection(TcpClient client)
{ {
client.NoDelay = true;
Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}"); Console.WriteLine($"Client connected from {client.Client.RemoteEndPoint}");
var interaction = new ChannelInteractionModule(_serialization, _identityGenerator); var interaction = new ChannelInteractionModule(_serialization, _identityGenerator);
@@ -94,7 +94,8 @@ namespace mROA.Implementation.Backend
} }
private void HandleNewClient(EndPointContext context, ChannelInteractionModule interaction, private void HandleNewClient(EndPointContext context, ChannelInteractionModule interaction,
ChannelInteractionModule.StreamExtractor streamExtractor, CancellationTokenSource cts, NetworkMessage connection) ChannelInteractionModule.StreamExtractor streamExtractor, CancellationTokenSource cts,
NetworkMessage connection)
{ {
context.HostId = 0; context.HostId = 0;
context.OwnerId = -interaction.ConnectionId; context.OwnerId = -interaction.ConnectionId;
@@ -106,12 +107,10 @@ namespace mROA.Implementation.Backend
_extractorsTokenSources[interaction.ConnectionId] = cts; _extractorsTokenSources[interaction.ConnectionId] = cts;
_hub.RegisterInteraction(interaction); _hub.RegisterInteraction(interaction);
var requestExtractor = _hre.HubOnOnConnected(new RepresentationModule(interaction, _serialization.Clone())); _hre.HubOnOnConnected(new RepresentationModule(interaction, _serialization.Clone()));
streamExtractor.MessageReceived = _distribution.GetDistributionAction(interaction.ConnectionId);
if (_distribution.DistributionType != EDistributionType.Channeled)
{
BindRequestFirstDistribution(context, interaction, streamExtractor, requestExtractor);
}
} }
private void BindRequestFirstDistribution(IEndPointContext context, IChannelInteractionModule interaction, private void BindRequestFirstDistribution(IEndPointContext context, IChannelInteractionModule interaction,
@@ -127,7 +126,7 @@ namespace mROA.Implementation.Backend
var func = converters[i]; var func = converters[i];
if (func(message) is not { } t) continue; if (func(message) is not { } t) continue;
var deserialized = _serialization.Deserialize(message.Data, t, context); var deserialized = _serialization.Deserialize(message.Data, t, context)!;
Task.Run(() => requestExtractor.PushMessage(deserialized, message.MessageType)); Task.Run(() => requestExtractor.PushMessage(deserialized, message.MessageType));
break; break;
} }
@@ -155,11 +154,7 @@ namespace mROA.Implementation.Backend
}; };
_ = streamExtractor.SendFromChannel(recoveryInteraction.TrustedPostChanel, cts.Token); _ = streamExtractor.SendFromChannel(recoveryInteraction.TrustedPostChanel, cts.Token);
if (_distribution.DistributionType == EDistributionType.ExtractorFirst) streamExtractor.MessageReceived = _distribution.GetDistributionAction(recoveryInteraction.ConnectionId);
{
BindRequestFirstDistribution(recoveryInteraction.Context, recoveryInteraction, streamExtractor,
_hre[recoveryInteraction.ConnectionId]);
}
Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token).ConfigureAwait(false)); Task.Run(async () => await streamExtractor.LoopedReceive(cts.Token).ConfigureAwait(false));
+7 -6
View File
@@ -14,15 +14,17 @@ namespace mROA.Implementation.Backend
{ {
private readonly IConnectionHub _hub; private readonly IConnectionHub _hub;
private readonly UdpClient _client; private readonly UdpClient _client;
private readonly Dictionary<IPEndPoint, int> _reservedPorts = new(); private readonly Dictionary<IPEndPoint, Action<NetworkMessage>> _distributionActions = new();
private readonly CancellationTokenSource _tokenSource = new(); private readonly CancellationTokenSource _tokenSource = new();
private readonly IContextualSerializationToolKit _serializationToolkit; private readonly IContextualSerializationToolKit _serializationToolkit;
private readonly IDistributionModule _distribution;
public UdpGateway(IOptions<GatewayOptions> options, IConnectionHub hub, public UdpGateway(IOptions<GatewayOptions> options, IConnectionHub hub,
IContextualSerializationToolKit serializationToolkit) IContextualSerializationToolKit serializationToolkit, IDistributionModule distribution)
{ {
_hub = hub; _hub = hub;
_serializationToolkit = serializationToolkit; _serializationToolkit = serializationToolkit;
_distribution = distribution;
_client = new UdpClient(options.Value.Endpoint); _client = new UdpClient(options.Value.Endpoint);
} }
@@ -49,13 +51,12 @@ namespace mROA.Implementation.Backend
{ {
case UntrustedConnect: case UntrustedConnect:
channelId = BitConverter.ToInt32(parsed.Data); channelId = BitConverter.ToInt32(parsed.Data);
_reservedPorts[incoming.RemoteEndPoint] = channelId; _distributionActions[incoming.RemoteEndPoint] = _distribution.GetDistributionAction(channelId);
_ = UntrustedSend(_hub.GetInteraction(channelId), incoming.RemoteEndPoint); _ = UntrustedSend(_hub.GetInteraction(channelId), incoming.RemoteEndPoint);
break; break;
default: default:
channelId = _reservedPorts[incoming.RemoteEndPoint]; _distributionActions[incoming.RemoteEndPoint].Invoke(parsed);
var interaction = _hub.GetInteraction(channelId);
await interaction.ReceiveChanel.Writer.WriteAsync(parsed, token);
break; break;
} }
} }
-2
View File
@@ -2,8 +2,6 @@
namespace mROA.Implementation namespace mROA.Implementation
{ {
public struct CallRequest public struct CallRequest
{ {
public RequestId Id { get; set; } public RequestId Id { get; set; }
@@ -143,7 +143,6 @@ namespace mROA.Implementation
public class StreamExtractor public class StreamExtractor
{ {
private const int BufferSize = ushort.MaxValue + 19; private const int BufferSize = ushort.MaxValue + 19;
private readonly Stream _ioStream; private readonly Stream _ioStream;
private readonly Memory<byte> _buffer = new byte[BufferSize]; private readonly Memory<byte> _buffer = new byte[BufferSize];
@@ -156,20 +155,21 @@ namespace mROA.Implementation
public async Task SingleReceive(CancellationToken token = default) public async Task SingleReceive(CancellationToken token = default)
{ {
var firstRead = await _ioStream.ReadAsync(_buffer, token);
_ = await _ioStream.ReadExactlyAsync(_buffer[..19], token);
var meta = MemoryMarshal.Read<NetworkMessage.NetworkMessageMeta>(_buffer.Span); var meta = MemoryMarshal.Read<NetworkMessage.NetworkMessageMeta>(_buffer.Span);
var len = meta.BodyLength; var len = meta.BodyLength;
var readLen = firstRead - 19;
if (readLen != len) var range = 19..(len + 19);
{ // Console.WriteLine($"{range} {_buffer.Length}");
var lastPart = _buffer[firstRead..(len + 19)]; var lastPart = _buffer[range];
await _ioStream.ReadExactlyAsync(lastPart, cancellationToken: token); await _ioStream.ReadExactlyAsync(lastPart, cancellationToken: token);
}
var message = meta.ToMessage(_buffer.Span); var message = meta.ToMessage(_buffer.Span);
// Console.WriteLine("RECV " + message);
MessageReceived(message); MessageReceived(message);
} }
@@ -187,8 +187,8 @@ namespace mROA.Implementation
MemoryMarshal.Write(_buffer.Span, ref meta); MemoryMarshal.Write(_buffer.Span, ref meta);
message.Data.CopyTo(_buffer.Span[19..]); message.Data.CopyTo(_buffer.Span[19..]);
var sendingSpan = _buffer[..(19 + meta.BodyLength)]; var sendingSpan = _buffer[..(19 + meta.BodyLength)];
// Console.WriteLine("SEND " + message);
await _ioStream.WriteAsync(sendingSpan, token); await _ioStream.WriteAsync(sendingSpan, token);
// _logger.LogTrace("SEND {0}", message.ToString());
} }
public async Task SendFromChannel(ChannelReader<NetworkMessage> channel, public async Task SendFromChannel(ChannelReader<NetworkMessage> channel,
@@ -0,0 +1,60 @@
using System;
using System.Threading;
namespace mROA.Implementation
{
public class CircularMemoryManager
{
private readonly Memory<byte> _buffer;
private Memory<byte> _current;
private SpinLock _spinLock = new(false);
public CircularMemoryManager(int size)
{
_buffer = new Memory<byte>(new byte[size]);
_current = _buffer;
}
public Span<byte> AllocSlice(int size)
{
Span<byte> order;
var lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken);
if (_current.Length < size)
_current = _buffer;
order = _current.Span[..size];
_current = _current[size..];
}
finally
{
if (lockTaken) _spinLock.Exit(false);
}
return order;
}
public Memory<byte> AllocMemory(int size)
{
Memory<byte> order;
var lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken);
if (_current.Length < size)
_current = _buffer;
order = _current[..size];
_current = _current[size..];
}
finally
{
if (lockTaken) _spinLock.Exit(false);
}
return order;
}
}
}
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using mROA.Abstract; using mROA.Abstract;
@@ -5,16 +6,16 @@ namespace mROA.Implementation
{ {
public class CollectableMethodRepository : IMethodRepository public class CollectableMethodRepository : IMethodRepository
{ {
private readonly List<IMethodInvoker> _methods = new(); private readonly List<IMethodInvoker> _methods = new() { MethodInvoker.Dispose };
private IMethodInvoker[] _baked = Array.Empty<IMethodInvoker>();
public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers) public void AppendInvokers(IEnumerable<IMethodInvoker> methodInvokers)
{ {
_methods.AddRange(methodInvokers); _methods.AddRange(methodInvokers);
_baked = _methods.ToArray();
} }
public IMethodInvoker GetMethod(int id) public IMethodInvoker GetMethod(int id)
{ {
return id == -1 ? MethodInvoker.Dispose : _methods[id]; return _baked[++id];
} }
} }
} }
@@ -0,0 +1,11 @@
using System;
using mROA.Abstract;
namespace mROA.Implementation.CommandExecution
{
public class AsyncCommandExecution : ICommandExecution
{
public RequestId Id { get; set; }
public EMessageType MessageType => EMessageType.Unknown;
}
}
@@ -0,0 +1,70 @@
using System;
using System.Threading.Tasks;
using mROA.Abstract;
using mROA.Implementation.Backend;
namespace mROA.Implementation
{
public class ChannelDistributionModule : IDistributionModule
{
private readonly IConnectionHub _hub;
public ChannelDistributionModule(IConnectionHub hub)
{
_hub = hub;
}
public Action<NetworkMessage> GetDistributionAction(int clientId)
{
var writer = _hub.GetInteraction(clientId).ReceiveChanel.Writer;
return message =>
{
writer.TryWrite(message);
};
}
}
public class ExtractorFirstDistributionModule : IDistributionModule
{
private readonly IConnectionHub _hub;
private readonly IContextualSerializationToolKit _serialization;
private readonly HubRequestExtractor _extractorHub;
public ExtractorFirstDistributionModule(HubRequestExtractor extractorHub, IConnectionHub hub, IContextualSerializationToolKit serialization)
{
_extractorHub = extractorHub;
_hub = hub;
_serialization = serialization;
}
public Action<NetworkMessage> GetDistributionAction(int clientId)
{
var interaction = _hub.GetInteraction(clientId);
var writer = interaction.ReceiveChanel.Writer;
var context = interaction.Context;
var requestExtractor = _extractorHub[clientId];
var converters = requestExtractor.Converters;
var serialization = _serialization.Clone();
return message =>
{
if (requestExtractor.Rule(message))
{
for (var i = 0; i < converters.Length; i++)
{
var func = converters[i];
if (func(message) is not { } t) continue;
var deserialized = serialization.Deserialize(message.Data, t, context)!;
Task.Run(() => requestExtractor.PushMessage(deserialized, message.MessageType));
break;
}
return;
}
writer.WriteAsync(message).ConfigureAwait(false);
};
}
}
}
@@ -51,7 +51,6 @@ namespace mROA.Implementation.Frontend
$"Incorrect message type. Must be IdAssigning, current : {idMessage.MessageType.ToString()}"); $"Incorrect message type. Must be IdAssigning, current : {idMessage.MessageType.ToString()}");
} }
_ = Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token)); _ = Task.Run(async () => await _currentExtractor.LoopedReceive(_rawExtractorCancellation.Token));
var assignment = _serialization.Deserialize<IdAssignment>(idMessage.Data, _context); var assignment = _serialization.Deserialize<IdAssignment>(idMessage.Data, _context);
@@ -36,20 +36,20 @@ namespace mROA.Implementation.Frontend
} }
} }
public void PushMessage(object parced, EMessageType originalType) public void PushMessage(object parsed, EMessageType originalType)
{ {
switch (originalType) switch (originalType)
{ {
case EMessageType.CallRequest: case EMessageType.CallRequest:
HandleCallRequest((CallRequest)parced); HandleCallRequest((CallRequest)parsed);
break; break;
case EMessageType.ClientDisconnect: case EMessageType.ClientDisconnect:
return; return;
case EMessageType.EventRequest: case EMessageType.EventRequest:
HandleEventRequest((CallRequest)parced); HandleEventRequest((CallRequest)parsed);
break; break;
case EMessageType.CancelRequest: case EMessageType.CancelRequest:
HandleCancelRequest((CancelRequest)parced); HandleCancelRequest((CancelRequest)parsed);
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@@ -55,7 +55,7 @@ namespace mROA.Implementation.Frontend
var initMessage = new NetworkMessage var initMessage = new NetworkMessage
{ {
MessageType = EMessageType.UntrustedConnect, Id = RequestId.Generate(), MessageType = EMessageType.UntrustedConnect, Id = RequestId.Generate(),
Data = BitConverter.GetBytes(_channelInteractionModule.ConnectionId) Data = BitConverter.GetBytes(-_channelInteractionModule.ConnectionId)
}; };
var initParsed = _serializationToolkit.Serialize(initMessage, _context); var initParsed = _serializationToolkit.Serialize(initMessage, _context);
+1 -1
View File
@@ -37,7 +37,7 @@ namespace mROA.Implementation
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes; public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
public Type? ReturnType { get; set; } public Type? ReturnType { get; set; }
public Type SuitableType { get; set; } = typeof(object); public Type SuitableType { get; set; } = typeof(object);
public bool RequireCancellation { get; set; } = true;
public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } = public Action<object, object?[]?, object[], Action<object?>> Invoking { get; set; } =
(_, _, _, post) => { post.Invoke(null); }; (_, _, _, post) => { post.Invoke(null); };
+1 -2
View File
@@ -35,8 +35,7 @@ namespace mROA.Implementation
public EMessageType MessageType { get; set; } public EMessageType MessageType { get; set; }
public byte[] Data { get; set; } public byte[] Data { get; set; }
public object Serialized { get; set; }
public IEndPointContext Context { get; set; }
public override string ToString() public override string ToString()
{ {
return $" {Id}:{MessageType} [{Data.Length}]"; return $" {Id}:{MessageType} [{Data.Length}]";
@@ -8,6 +8,7 @@ namespace mROA.Implementation
public class RemoteInstanceRepository : IInstanceRepository public class RemoteInstanceRepository : IInstanceRepository
{ {
private readonly List<RemoteObjectBase> _producedProxies = new(); private readonly List<RemoteObjectBase> _producedProxies = new();
private readonly List<RemoteObjectBase> _producedSingletonProxies = new();
private readonly ICallIndexProvider _callIndexProvider; private readonly ICallIndexProvider _callIndexProvider;
private readonly IRepresentationModuleProducer _representationProducer; private readonly IRepresentationModuleProducer _representationProducer;
@@ -32,9 +33,9 @@ namespace mROA.Implementation
public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context) where T : class public T GetObject<T>(ComplexObjectIdentifier id, IEndPointContext context) where T : class
{ {
var index = _producedProxies.Find(i => i.Identifier.Equals(id)); var existing = _producedProxies.Find(i => i.Identifier.Equals(id));
if (index is not null) if (existing is not null)
return (T)(index as object); return (T)(existing as object);
if (!_callIndexProvider.Activators.TryGetValue(typeof(T), out var remoteType)) if (!_callIndexProvider.Activators.TryGetValue(typeof(T), out var remoteType))
throw new NotSupportedException(); throw new NotSupportedException();
@@ -55,6 +56,10 @@ namespace mROA.Implementation
public object GetSingletonObject(Type type, IEndPointContext context) public object GetSingletonObject(Type type, IEndPointContext context)
{ {
var existing = _producedSingletonProxies.Find(i => i.GetType() == type);
if (existing is not null)
return existing;
var representationModule = var representationModule =
_representationProducer.Produce(context.OwnerId); _representationProducer.Produce(context.OwnerId);
@@ -62,6 +67,7 @@ namespace mROA.Implementation
_callIndexProvider.GetIndices(type))!; _callIndexProvider.GetIndices(type))!;
_producedProxies.Add(instance); _producedProxies.Add(instance);
_producedSingletonProxies.Add(instance);
return _producedProxies.Last(); return _producedProxies.Last();
} }
@@ -34,7 +34,6 @@ namespace mROA.Implementation
var writer = _interaction.ReceiveChanel.Writer; var writer = _interaction.ReceiveChanel.Writer;
var reader = _interaction.ReceiveChanel.Reader; var reader = _interaction.ReceiveChanel.Reader;
await foreach (var message in reader.ReadAllAsync(token)) await foreach (var message in reader.ReadAllAsync(token))
{ {
if (!rule(message)) if (!rule(message))
@@ -0,0 +1,7 @@
namespace mROA.Implementation
{
public class SerializationBufferOffset
{
public int Offset { get; set; } = 0;
}
}
+2 -1
View File
@@ -9,7 +9,8 @@ namespace mROA
{ {
public static async ValueTask<int> ReadExactlyAsync(this Stream stream, byte[] buffer, int offset, int count) 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, CancellationToken.None); return await stream.ReadAtLeastAsyncCore(buffer.AsMemory(offset, count), count, true,
CancellationToken.None);
} }
public static ValueTask<int> ReadExactlyAsync(this Stream stream, Memory<byte> buffer, public static ValueTask<int> ReadExactlyAsync(this Stream stream, Memory<byte> buffer,
+2 -9
View File
@@ -4,7 +4,7 @@
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>netstandard2.1</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Title>mROA</Title> <Title>mROA</Title>
<Version>2.0.8</Version> <Version>3.0.4</Version>
<Authors>YaslePoy</Authors> <Authors>YaslePoy</Authors>
<Description>Fast and easy RPC with contex</Description> <Description>Fast and easy RPC with contex</Description>
<RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl> <RepositoryUrl>https://github.com/YaslePoy/mROA</RepositoryUrl>
@@ -22,7 +22,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DefineConstants></DefineConstants> <DefineConstants>;</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -38,11 +38,4 @@
<PackagePath></PackagePath> <PackagePath></PackagePath>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Extensions.Logging.Abstractions">
<HintPath>..\..\..\..\.nuget\packages\microsoft.extensions.logging.abstractions\9.0.7\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
</Project> </Project>