База для нового бэкэнда
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using Example.Shared;
|
||||||
|
|
||||||
|
namespace Example.Backend
|
||||||
|
{
|
||||||
|
public class CsTest
|
||||||
|
{
|
||||||
|
public T FinalCasted<T>(IDataList<T> list, int index)
|
||||||
|
{
|
||||||
|
return list.Get(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public object NonCasted(object list, int index)
|
||||||
|
{
|
||||||
|
return FinalCasted(list as IDataList<object>, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Example.Shared;
|
||||||
|
|
||||||
|
namespace Example.Backend
|
||||||
|
{
|
||||||
|
public class PagesList : IPagesList
|
||||||
|
{
|
||||||
|
public IReadOnlyList<IPage> Collection { get; }
|
||||||
|
public IPage Get(int index)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(IPage item)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(int index, IPage item)
|
||||||
|
{
|
||||||
|
throw new System.NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using Example.Backend;
|
using Example.Backend;
|
||||||
|
using Example.Shared;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
using mROA.Cbor;
|
using mROA.Cbor;
|
||||||
using mROA.Codegen;
|
using mROA.Codegen;
|
||||||
@@ -48,5 +49,6 @@ class Program
|
|||||||
var gateway = builder.GetModule<IGatewayModule>();
|
var gateway = builder.GetModule<IGatewayModule>();
|
||||||
|
|
||||||
gateway.Run();
|
gateway.Run();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,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!!!!!!!!!!! Vova likes that:)");
|
||||||
|
|
||||||
return "ClientBasedPrinter from mroa";
|
return "ClientBasedPrinter from mroa";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class Program
|
|||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var builder = new FullMixBuilder();
|
var builder = new FullMixBuilder();
|
||||||
new RemoteTypeBinder();
|
// new RemoteTypeBinder();
|
||||||
// builder.Modules.Add(new JsonSerializationToolkit());
|
// builder.Modules.Add(new JsonSerializationToolkit());
|
||||||
builder.Modules.Add(new CborSerializationToolkit());
|
builder.Modules.Add(new CborSerializationToolkit());
|
||||||
|
|
||||||
@@ -106,5 +106,7 @@ class Program
|
|||||||
// Console.WriteLine("X is {0}", x);
|
// Console.WriteLine("X is {0}", x);
|
||||||
// Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
// Console.WriteLine("Time : {0}", timer.Elapsed.TotalMilliseconds);
|
||||||
// Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
// Console.WriteLine($"Time per call: {timer.Elapsed.TotalMilliseconds / iterations} ms");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using mROA.Implementation;
|
||||||
using mROA.Implementation.Attributes;
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
namespace Example.Shared
|
namespace Example.Shared
|
||||||
{
|
{
|
||||||
// [SharedObjectInterface]
|
public interface IDataList<T> : IShared, IDisposable
|
||||||
// public interface IDataList<T> : IShared
|
{
|
||||||
// {
|
IReadOnlyList<T> Collection { get; }
|
||||||
// T Get(int index);
|
T Get(int index);
|
||||||
// void Add(T item);
|
void Add(T item);
|
||||||
// void Set(int index, T item);
|
void Set(int index, T item);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using mROA.Implementation.Attributes;
|
||||||
|
|
||||||
|
namespace Example.Shared
|
||||||
|
{
|
||||||
|
[SharedObjectInterface]
|
||||||
|
public interface IPagesList : IDataList<IPage>
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,8 +52,11 @@ namespace mROA.Cbor
|
|||||||
return (T)Cast(nonCasted, typeof(T), context);
|
return (T)Cast(nonCasted, typeof(T), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Cast(object nonCasted, Type type, IEndPointContext? context)
|
public object? Cast(object? nonCasted, Type type, IEndPointContext? context)
|
||||||
{
|
{
|
||||||
|
if (nonCasted == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (nonCasted.GetType() == type)
|
if (nonCasted.GetType() == type)
|
||||||
return nonCasted;
|
return nonCasted;
|
||||||
|
|
||||||
|
|||||||
@@ -17,74 +17,57 @@ namespace mROA.Codegen
|
|||||||
[Generator]
|
[Generator]
|
||||||
public class mROASourceGenerator : ISourceGenerator
|
public class mROASourceGenerator : ISourceGenerator
|
||||||
{
|
{
|
||||||
private const string Namespace = "mROA.Implementation";
|
|
||||||
private const string AttributeName = "SharedObjectInterafceAttribute";
|
|
||||||
|
|
||||||
private const string AttributeSourceCode = $@"// <auto-generated/>
|
|
||||||
|
|
||||||
namespace {Namespace}
|
|
||||||
{{
|
|
||||||
[System.AttributeUsage(System.AttributeTargets.Class)]
|
|
||||||
public class {AttributeName} : System.Attribute
|
|
||||||
{{
|
|
||||||
}}
|
|
||||||
}}";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generate code action.
|
|
||||||
/// It will be executed on specific nodes (ClassDeclarationSyntax annotated with the [Report] attribute) changed by the user.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">Source generation context used to add source files.</param>
|
|
||||||
/// <param name="compilation">Compilation used to provide access to the Semantic Model.</param>
|
|
||||||
/// <param name="classes">Nodes annotated with the [Report] attribute that trigger the generate action.</param>
|
|
||||||
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
|
private void GenerateCode(GeneratorExecutionContext context, Compilation compilation,
|
||||||
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
ImmutableArray<InterfaceDeclarationSyntax> classes)
|
||||||
{
|
{
|
||||||
var methods = new List<(string, IMethodSymbol)>();
|
var methods = new List<(string, IMethodSymbol)>();
|
||||||
var frontendContextRepo = new List<string>();
|
var frontendContextRepo = new List<string>();
|
||||||
// Go through all filtered class declarations.
|
|
||||||
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
var declarations = classes.ToList().OrderBy(i => i.Identifier.Text).ToList();
|
||||||
foreach (var classDeclarationSyntax in declarations)
|
foreach (var classDeclarationSyntax in declarations)
|
||||||
{
|
{
|
||||||
// We need to get semantic model of the class to retrieve metadata.
|
|
||||||
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
var semanticModel = compilation.GetSemanticModel(classDeclarationSyntax.SyntaxTree);
|
||||||
|
|
||||||
|
|
||||||
// Symbols allow us to get the compile-time information.
|
|
||||||
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
if (semanticModel.GetDeclaredSymbol(classDeclarationSyntax) is not INamedTypeSymbol classSymbol)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 'Identifier' means the token of the node. Get class name from the syntax node.
|
|
||||||
var className = classDeclarationSyntax.Identifier.Text;
|
var className = classDeclarationSyntax.Identifier.Text;
|
||||||
|
var methodBody = CollectMethods(classSymbol);
|
||||||
// Go through all class members with a particular type (property) to generate method lines.
|
|
||||||
var methodBody = classSymbol.GetMembers()
|
|
||||||
.OfType<IMethodSymbol>().OrderBy(i => i.Name);
|
|
||||||
|
|
||||||
var originalName = className;
|
var originalName = className;
|
||||||
// Build up the source code
|
|
||||||
className = className.TrimStart('I') + "RemoteEndpoint";
|
className = className.TrimStart('I') + "RemoteEndpoint";
|
||||||
|
|
||||||
|
|
||||||
var methodsText = new List<string>();
|
var methodsText = new List<string>();
|
||||||
|
|
||||||
foreach (var method in methodBody)
|
foreach (var method in methodBody)
|
||||||
{
|
{
|
||||||
var index = methods.Count;
|
var index = methods.Count;
|
||||||
methods.Add((namespaceName + "." + originalName, method));
|
methods.Add((namespaceName + "." + originalName, method));
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
bool isParametrized;
|
||||||
|
|
||||||
bool isAsync = method.ReturnType.Name == "Task";
|
bool isAsync;
|
||||||
bool isVoid = method.ReturnType.Name == "Void" ||
|
bool isVoid;
|
||||||
method.ReturnType.ToString() == "System.Threading.Tasks.Task";
|
|
||||||
bool isParametrized = method.Parameters.Length == 1 && !isAsync ||
|
|
||||||
method.Parameters.Length == 2 && isAsync;
|
|
||||||
|
|
||||||
|
switch (method.ReturnType)
|
||||||
|
{
|
||||||
|
case INamedTypeSymbol namedType:
|
||||||
|
isAsync = namedType.Name == "Task";
|
||||||
|
isVoid = isAsync && namedType.TypeParameters.Length == 0 || namedType.Name == "Void";
|
||||||
|
isParametrized = method.Parameters.Length == 1 && !isAsync ||
|
||||||
|
method.Parameters.Length == 2 && isAsync;
|
||||||
|
break;
|
||||||
|
case IArrayTypeSymbol:
|
||||||
|
isAsync = false;
|
||||||
|
isVoid = false;
|
||||||
|
isParametrized = method.Parameters.Length != 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//Creating signature
|
//Creating signature
|
||||||
sb.AppendLine("public" + (isAsync
|
sb.AppendLine("public" + (isAsync
|
||||||
@@ -140,7 +123,7 @@ namespace {namespaceName}
|
|||||||
|
|
||||||
|
|
||||||
// Add the source code to the compilation.
|
// Add the source code to the compilation.
|
||||||
context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
// context.AddSource($"{className}.g.cs", SourceText.From(code, Encoding.UTF8));
|
||||||
|
|
||||||
frontendContextRepo.Add(
|
frontendContextRepo.Add(
|
||||||
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
|
$"{{ typeof({classSymbol.ToDisplayString()}), typeof({namespaceName}.{className}) }}");
|
||||||
@@ -148,31 +131,27 @@ namespace {namespaceName}
|
|||||||
|
|
||||||
if (methods.Count != 0)
|
if (methods.Count != 0)
|
||||||
{
|
{
|
||||||
// var methodsStringed = methods.Select(i =>
|
var methodsStringed = Array.Empty<string>();
|
||||||
// $"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\", new Type[] {{{string.Join(", ", i.Item2.Parameters.Select(p => $"typeof({p.Type.ToDisplayString()})"))}}})")
|
|
||||||
// .ToList();
|
|
||||||
var methodsStringed = methods.Select(i =>
|
|
||||||
$"typeof({i.Item1}).GetMethod(\"{i.Item2.Name}\")")
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
var coCodegenRepoCode = @$"// <auto-generated/>
|
var coCodegenRepoCode = @$"// <auto-generated/>
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using mROA.Abstract;
|
using mROA.Abstract;
|
||||||
|
using mROA.Implementation;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace mROA.Codegen
|
namespace mROA.Codegen
|
||||||
{{
|
{{
|
||||||
public class CoCodegenMethodRepository : IMethodRepository
|
public class CoCodegenMethodRepository : IMethodRepository
|
||||||
{{
|
{{
|
||||||
private readonly List<MethodInfo> _methods = new () {{
|
private readonly List<IMethodInvoker> _methods = new () {{
|
||||||
{string.Join(",\r\n\t\t\t", methodsStringed)}
|
{string.Join(",\r\n\t\t\t", methodsStringed)}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
public MethodInfo GetMethod(int id)
|
public IMethodInvoker GetMethod(int id)
|
||||||
{{
|
{{
|
||||||
if (id == -1)
|
if (id == -1)
|
||||||
return typeof(IDisposable).GetMethod(""Dispose"");
|
return mROA.Implementation.MethodInvoker.Dispose;
|
||||||
|
|
||||||
if (_methods.Count <= id)
|
if (_methods.Count <= id)
|
||||||
return null;
|
return null;
|
||||||
@@ -186,7 +165,7 @@ namespace mROA.Codegen
|
|||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
";
|
";
|
||||||
context.AddSource($"CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
context.AddSource("CoCodegenMethodRepository.g.cs", SourceText.From(coCodegenRepoCode, Encoding.UTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frontendContextRepo.Count != 0)
|
if (frontendContextRepo.Count != 0)
|
||||||
@@ -209,7 +188,7 @@ namespace mROA.Codegen
|
|||||||
}}
|
}}
|
||||||
}}
|
}}
|
||||||
";
|
";
|
||||||
context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
// context.AddSource("RemoteTypeBinder.g.cs", SourceText.From(fronendRepoCode, Encoding.UTF8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,9 +204,7 @@ namespace mROA.Codegen
|
|||||||
|
|
||||||
private string ExtractTaskType(ITypeSymbol taskType)
|
private string ExtractTaskType(ITypeSymbol taskType)
|
||||||
{
|
{
|
||||||
var type = taskType.ToString();
|
return (taskType as INamedTypeSymbol).TypeParameters[0].ToDisplayString();
|
||||||
type = type.Substring(type.IndexOf('<') + 1);
|
|
||||||
return type.Substring(0, type.Length - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
@@ -266,8 +243,7 @@ namespace mROA.Codegen
|
|||||||
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
|
private bool ContainsSOIAttribute(SyntaxList<AttributeListSyntax> attributes, GeneratorExecutionContext context,
|
||||||
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
|
InterfaceDeclarationSyntax interfaceDeclarationSyntax)
|
||||||
{
|
{
|
||||||
foreach (AttributeListSyntax attributeListSyntax in attributes)
|
foreach (var attributeSyntax in attributes.SelectMany(attributeListSyntax => attributeListSyntax.Attributes))
|
||||||
foreach (AttributeSyntax attributeSyntax in attributeListSyntax.Attributes)
|
|
||||||
{
|
{
|
||||||
if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree)
|
if (context.Compilation.GetSemanticModel(interfaceDeclarationSyntax.SyntaxTree)
|
||||||
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
.GetSymbolInfo(attributeSyntax).Symbol is not IMethodSymbol attributeSymbol)
|
||||||
@@ -282,5 +258,16 @@ namespace mROA.Codegen
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<IMethodSymbol> CollectMethods(INamedTypeSymbol type)
|
||||||
|
{
|
||||||
|
var methods = type.GetMembers().OfType<IMethodSymbol>().ToList();
|
||||||
|
foreach (var inner in type.AllInterfaces)
|
||||||
|
{
|
||||||
|
methods.AddRange(inner.GetMembers().OfType<IMethodSymbol>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return methods.OrderBy(i => i.Name).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,7 @@ namespace mROA.Abstract
|
|||||||
bool IsVoid { get; }
|
bool IsVoid { get; }
|
||||||
Type[] ParameterTypes { get; }
|
Type[] ParameterTypes { get; }
|
||||||
Type? ReturnType { get; }
|
Type? ReturnType { get; }
|
||||||
object? Invoke(object instance, object?[] parameters, object[] special);
|
object? Invoke(object instance, object?[]? parameters, object[] special);
|
||||||
|
Type SuitableType { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,6 @@ namespace mROA.Abstract
|
|||||||
{
|
{
|
||||||
public interface IMethodRepository : IInjectableModule
|
public interface IMethodRepository : IInjectableModule
|
||||||
{
|
{
|
||||||
MethodInfo GetMethod(int id);
|
IMethodInvoker GetMethod(int id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,8 @@ namespace mROA.Abstract
|
|||||||
object? Deserialize(byte[] rawData, Type type);
|
object? Deserialize(byte[] rawData, Type type);
|
||||||
T? Deserialize<T>(Span<byte> rawData);
|
T? Deserialize<T>(Span<byte> rawData);
|
||||||
object? Deserialize(Span<byte> rawData, Type type);
|
object? Deserialize(Span<byte> rawData, Type type);
|
||||||
T? Cast<T>(object nonCasted);
|
T? Cast<T>(object? nonCasted);
|
||||||
object? Cast(object nonCasted, Type type);
|
object? Cast(object? nonCasted, Type type);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -11,11 +12,22 @@ namespace mROA.Implementation.Backend
|
|||||||
{
|
{
|
||||||
private IMethodRepository? _methodRepo;
|
private IMethodRepository? _methodRepo;
|
||||||
private ICancellationRepository? _cancellationRepo;
|
private ICancellationRepository? _cancellationRepo;
|
||||||
|
private ISerializationToolkit? _serialization;
|
||||||
|
|
||||||
public void Inject<T>(T dependency)
|
public void Inject<T>(T dependency)
|
||||||
{
|
{
|
||||||
if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo;
|
switch (dependency)
|
||||||
if (dependency is ICancellationRepository cancellationRepo) _cancellationRepo = cancellationRepo;
|
{
|
||||||
|
case IMethodRepository methodRepo:
|
||||||
|
_methodRepo = methodRepo;
|
||||||
|
break;
|
||||||
|
case ICancellationRepository cancellationRepo:
|
||||||
|
_cancellationRepo = cancellationRepo;
|
||||||
|
break;
|
||||||
|
case ISerializationToolkit serializationToolkit:
|
||||||
|
_serialization = serializationToolkit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
||||||
@@ -24,50 +36,69 @@ namespace mROA.Implementation.Backend
|
|||||||
#if TRACE
|
#if TRACE
|
||||||
Console.WriteLine(command.GetType().Name);
|
Console.WriteLine(command.GetType().Name);
|
||||||
#endif
|
#endif
|
||||||
if (_cancellationRepo is null)
|
|
||||||
throw new NullReferenceException("Method repository was not defined");
|
|
||||||
|
|
||||||
if (_methodRepo is null)
|
|
||||||
throw new NullReferenceException("Method repository was not defined");
|
|
||||||
|
|
||||||
if (contextRepository is null)
|
|
||||||
throw new NullReferenceException("Context repository was not defined");
|
|
||||||
|
|
||||||
if (command is CancelRequest)
|
|
||||||
{
|
|
||||||
#if TRACE
|
|
||||||
Console.WriteLine("Final cancelling request");
|
|
||||||
#endif
|
|
||||||
var cts = _cancellationRepo.GetCancellation(command.Id);
|
|
||||||
cts.Cancel();
|
|
||||||
_cancellationRepo.FreeCancelation(command.Id);
|
|
||||||
return new FinalCommandExecution
|
|
||||||
{
|
|
||||||
Id = command.Id
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var currentCommand = _methodRepo.GetMethod(command.CommandId);
|
|
||||||
if (currentCommand == null)
|
|
||||||
throw new Exception($"Command {command.CommandId} not found");
|
|
||||||
|
|
||||||
var context = command.ObjectId != -1
|
|
||||||
? contextRepository.GetObject<object>(command.ObjectId)
|
|
||||||
: contextRepository.GetSingleObject(currentCommand.DeclaringType!);
|
|
||||||
var parameter = command.Parameter;
|
|
||||||
|
|
||||||
if (currentCommand.ReturnType.BaseType == typeof(Task) &&
|
|
||||||
currentCommand.ReturnType.GenericTypeArguments.Length == 1)
|
|
||||||
return TypedExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo,
|
|
||||||
representationModule);
|
|
||||||
|
|
||||||
if (currentCommand.ReturnType == typeof(Task))
|
|
||||||
return ExecuteAsync(currentCommand, context, parameter, command, _cancellationRepo,
|
|
||||||
representationModule);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var result = Execute(currentCommand, context, parameter, command);
|
if (_cancellationRepo is null)
|
||||||
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
|
|
||||||
|
if (_methodRepo is null)
|
||||||
|
throw new NullReferenceException("Method repository was not defined");
|
||||||
|
|
||||||
|
if (contextRepository is null)
|
||||||
|
throw new NullReferenceException("Context repository was not defined");
|
||||||
|
|
||||||
|
if (command is CancelRequest)
|
||||||
|
{
|
||||||
|
#if TRACE
|
||||||
|
Console.WriteLine("Final cancelling request");
|
||||||
|
#endif
|
||||||
|
var cts = _cancellationRepo.GetCancellation(command.Id);
|
||||||
|
if (cts == null)
|
||||||
|
throw new NullReferenceException("Can't find cancellation for this request");
|
||||||
|
cts.Cancel();
|
||||||
|
_cancellationRepo.FreeCancelation(command.Id);
|
||||||
|
|
||||||
|
return new FinalCommandExecution
|
||||||
|
{
|
||||||
|
Id = command.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var invoker = _methodRepo.GetMethod(command.CommandId);
|
||||||
|
if (invoker == null)
|
||||||
|
throw new Exception($"Command {command.CommandId} not found");
|
||||||
|
|
||||||
|
var context = command.ObjectId != -1
|
||||||
|
? contextRepository.GetObject<object>(command.ObjectId)
|
||||||
|
: contextRepository.GetSingleObject(invoker.SuitableType);
|
||||||
|
|
||||||
|
if (context == null)
|
||||||
|
throw new NullReferenceException("Instance can't be null");
|
||||||
|
|
||||||
|
|
||||||
|
object?[]? castedParams = null;
|
||||||
|
|
||||||
|
if (invoker.ParameterTypes != Type.EmptyTypes)
|
||||||
|
{
|
||||||
|
castedParams = new object[invoker.ParameterTypes.Length];
|
||||||
|
for (int i = 0; i < castedParams.Length; i++)
|
||||||
|
{
|
||||||
|
castedParams[i] = _serialization.Cast(command.Parameters![i], invoker.ParameterTypes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var execContext = new RequestContext(command.Id, representationModule.Id);
|
||||||
|
|
||||||
|
if (invoker is { IsAsync: true, IsVoid: false })
|
||||||
|
return TypedExecuteAsync(invoker, context, castedParams, command, _cancellationRepo,
|
||||||
|
representationModule, execContext);
|
||||||
|
|
||||||
|
if (invoker.IsAsync)
|
||||||
|
return ExecuteAsync(invoker, context, castedParams, command, _cancellationRepo,
|
||||||
|
representationModule, execContext);
|
||||||
|
|
||||||
|
var result = Execute(invoker, context, castedParams, command, execContext);
|
||||||
if (command.CommandId == -1)
|
if (command.CommandId == -1)
|
||||||
{
|
{
|
||||||
#if TRACE
|
#if TRACE
|
||||||
@@ -80,23 +111,22 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
return new ExceptionCommandExecution
|
||||||
throw;
|
{
|
||||||
|
Id = command.Id,
|
||||||
|
Exception = e.ToString()
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter,
|
private static ICommandExecution Execute(IMethodInvoker invoker, object instance, object?[] parameter,
|
||||||
ICallRequest command)
|
ICallRequest command, RequestContext executionContext)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var finalParameter = parameter is null
|
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||||
? Array.Empty<object>()
|
|
||||||
: new[]
|
|
||||||
{ parameter };
|
|
||||||
var finalResult = currentCommand.Invoke(context, finalParameter);
|
|
||||||
|
|
||||||
if (currentCommand.ReturnType.Name == "Void")
|
if (invoker.IsVoid)
|
||||||
{
|
{
|
||||||
return new FinalCommandExecution
|
return new FinalCommandExecution
|
||||||
{
|
{
|
||||||
@@ -120,9 +150,9 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
private ICommandExecution ExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
IRepresentationModule representationModule)
|
IRepresentationModule representationModule, RequestContext executionContext)
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
@@ -132,11 +162,7 @@ namespace mROA.Implementation.Backend
|
|||||||
#endif
|
#endif
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var finalParameter = parameter is null
|
var result = (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!;
|
||||||
? new object[] { token }
|
|
||||||
: new[]
|
|
||||||
{ parameter, token };
|
|
||||||
var result = (Task)currentCommand.Invoke(context, finalParameter)!;
|
|
||||||
|
|
||||||
|
|
||||||
result.ContinueWith(_ =>
|
result.ContinueWith(_ =>
|
||||||
@@ -173,9 +199,9 @@ namespace mROA.Implementation.Backend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
private ICommandExecution TypedExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters,
|
||||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||||
IRepresentationModule representationModule)
|
IRepresentationModule representationModule, RequestContext executionContext)
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||||
@@ -183,12 +209,8 @@ namespace mROA.Implementation.Backend
|
|||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var finalParameter = parameter is null
|
|
||||||
? new object[] { token }
|
|
||||||
: new[]
|
|
||||||
{ parameter, token };
|
|
||||||
var result =
|
var result =
|
||||||
(Task)currentCommand.Invoke(context, finalParameter)!;
|
(Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!;
|
||||||
|
|
||||||
result.ContinueWith(t =>
|
result.ContinueWith(t =>
|
||||||
{
|
{
|
||||||
@@ -198,7 +220,7 @@ namespace mROA.Implementation.Backend
|
|||||||
Id = command.Id,
|
Id = command.Id,
|
||||||
Result = finalResult
|
Result = finalResult
|
||||||
};
|
};
|
||||||
_cancellationRepo.FreeCancelation(command.Id);
|
_cancellationRepo!.FreeCancelation(command.Id);
|
||||||
|
|
||||||
var multiClientOwnershipRepository =
|
var multiClientOwnershipRepository =
|
||||||
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace mROA.Implementation
|
|||||||
Guid Id { get; }
|
Guid Id { get; }
|
||||||
int CommandId { get; }
|
int CommandId { get; }
|
||||||
int ObjectId { get; }
|
int ObjectId { get; }
|
||||||
object? Parameter { get; }
|
object?[]? Parameters { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DefaultCallRequest : ICallRequest
|
public class DefaultCallRequest : ICallRequest
|
||||||
@@ -20,7 +20,7 @@ namespace mROA.Implementation
|
|||||||
public int CommandId { get; set; }
|
public int CommandId { get; set; }
|
||||||
public int ObjectId { get; set; } = -1;
|
public int ObjectId { get; set; } = -1;
|
||||||
|
|
||||||
public object? Parameter { get; set; }
|
public object?[]? Parameters { get; set; }
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||||
@@ -32,7 +32,7 @@ namespace mROA.Implementation
|
|||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
public int CommandId { get; set; } = -2;
|
public int CommandId { get; set; } = -2;
|
||||||
public int ObjectId { get; set; } = -2;
|
public int ObjectId { get; set; } = -2;
|
||||||
public object? Parameter { get; set; } = null;
|
public object?[]? Parameters { get; set; } = null;
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||||
|
|||||||
@@ -94,15 +94,6 @@ namespace mROA.Implementation.Frontend
|
|||||||
tokenSource.Cancel();
|
tokenSource.Cancel();
|
||||||
var request = defaultRequest.Result;
|
var request = defaultRequest.Result;
|
||||||
|
|
||||||
if (request.Parameter is not null)
|
|
||||||
{
|
|
||||||
var method = _methodRepository!.GetMethod(request.CommandId);
|
|
||||||
var parameterType = method.GetParameters().First()
|
|
||||||
.ParameterType;
|
|
||||||
|
|
||||||
request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = _executeModule.Execute(request, _contextRepository, _representationModule);
|
var result = _executeModule.Execute(request, _contextRepository, _representationModule);
|
||||||
|
|
||||||
var resultType = MessageType.Unknown;
|
var resultType = MessageType.Unknown;
|
||||||
|
|||||||
@@ -9,23 +9,26 @@ namespace mROA.Implementation
|
|||||||
public bool IsVoid { get; set; }
|
public bool IsVoid { get; set; }
|
||||||
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 Func<object, object?[], object[], object?> Invoking { get; set; }
|
public Func<object, object?[]?, object[], object?> Invoking { get; set; } = (_, _, _) => null;
|
||||||
|
|
||||||
public object? Invoke(object instance, object?[] parameters, object[] special)
|
public object? Invoke(object instance, object?[]? parameters, object[] special)
|
||||||
{
|
{
|
||||||
return Invoking(instance, parameters, special);
|
return Invoking(instance, parameters, special);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodInvoker Dispose = new MethodInvoker
|
public Type SuitableType { get; set; } = null!;
|
||||||
|
|
||||||
|
public static readonly IMethodInvoker Dispose = new MethodInvoker
|
||||||
{
|
{
|
||||||
IsAsync = false,
|
IsAsync = false,
|
||||||
IsVoid = true,
|
IsVoid = true,
|
||||||
ReturnType = null,
|
ReturnType = null,
|
||||||
Invoking = ((instance, parameters, special) =>
|
Invoking = (instance, _, _) =>
|
||||||
{
|
{
|
||||||
(instance as IDisposable)?.Dispose();
|
(instance as IDisposable)?.Dispose();
|
||||||
return null;
|
return null;
|
||||||
})
|
},
|
||||||
|
SuitableType = typeof(IDisposable)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,11 +22,11 @@ namespace mROA.Implementation
|
|||||||
public int Id => _identifier.ContextId;
|
public int Id => _identifier.ContextId;
|
||||||
public int OwnerId => _identifier.OwnerId;
|
public int OwnerId => _identifier.OwnerId;
|
||||||
public UniversalObjectIdentifier Identifier => _identifier;
|
public UniversalObjectIdentifier Identifier => _identifier;
|
||||||
protected async Task<T> GetResultAsync<T>(int methodId, object? parameter = default,
|
protected async Task<T> GetResultAsync<T>(int methodId, object?[]? parameters = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var request = new DefaultCallRequest
|
var request = new DefaultCallRequest
|
||||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter
|
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters
|
||||||
};
|
};
|
||||||
|
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
||||||
@@ -76,11 +76,11 @@ namespace mROA.Implementation
|
|||||||
throw errorResponse.Result.GetException();
|
throw errorResponse.Result.GetException();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task CallAsync(int methodId, object? parameter = default,
|
protected async Task CallAsync(int methodId, object?[]? parameters = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var request = new DefaultCallRequest
|
var request = new DefaultCallRequest
|
||||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter
|
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters
|
||||||
};
|
};
|
||||||
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace mROA.Implementation
|
||||||
|
{
|
||||||
|
public sealed class RequestContext
|
||||||
|
{
|
||||||
|
public int OwnerId { get; }
|
||||||
|
public Guid RequestId { get; }
|
||||||
|
|
||||||
|
public RequestContext(Guid requestId, int ownerId)
|
||||||
|
{
|
||||||
|
RequestId = requestId;
|
||||||
|
OwnerId = ownerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user