База для нового бэкэнда
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -11,11 +12,22 @@ namespace mROA.Implementation.Backend
|
||||
{
|
||||
private IMethodRepository? _methodRepo;
|
||||
private ICancellationRepository? _cancellationRepo;
|
||||
private ISerializationToolkit? _serialization;
|
||||
|
||||
public void Inject<T>(T dependency)
|
||||
{
|
||||
if (dependency is IMethodRepository methodRepo) _methodRepo = methodRepo;
|
||||
if (dependency is ICancellationRepository cancellationRepo) _cancellationRepo = cancellationRepo;
|
||||
switch (dependency)
|
||||
{
|
||||
case IMethodRepository methodRepo:
|
||||
_methodRepo = methodRepo;
|
||||
break;
|
||||
case ICancellationRepository cancellationRepo:
|
||||
_cancellationRepo = cancellationRepo;
|
||||
break;
|
||||
case ISerializationToolkit serializationToolkit:
|
||||
_serialization = serializationToolkit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommandExecution Execute(ICallRequest command, IContextRepository contextRepository,
|
||||
@@ -24,50 +36,69 @@ namespace mROA.Implementation.Backend
|
||||
#if TRACE
|
||||
Console.WriteLine(command.GetType().Name);
|
||||
#endif
|
||||
if (_cancellationRepo is null)
|
||||
throw new NullReferenceException("Method repository was not defined");
|
||||
|
||||
if (_methodRepo is null)
|
||||
throw new NullReferenceException("Method repository was not defined");
|
||||
|
||||
if (contextRepository is null)
|
||||
throw new NullReferenceException("Context repository was not defined");
|
||||
|
||||
if (command is CancelRequest)
|
||||
{
|
||||
#if TRACE
|
||||
Console.WriteLine("Final cancelling request");
|
||||
#endif
|
||||
var cts = _cancellationRepo.GetCancellation(command.Id);
|
||||
cts.Cancel();
|
||||
_cancellationRepo.FreeCancelation(command.Id);
|
||||
return new FinalCommandExecution
|
||||
{
|
||||
Id = command.Id
|
||||
};
|
||||
}
|
||||
|
||||
var currentCommand = _methodRepo.GetMethod(command.CommandId);
|
||||
if (currentCommand == null)
|
||||
throw new Exception($"Command {command.CommandId} not found");
|
||||
|
||||
var context = command.ObjectId != -1
|
||||
? contextRepository.GetObject<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
|
||||
{
|
||||
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 TRACE
|
||||
@@ -80,23 +111,22 @@ namespace mROA.Implementation.Backend
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
return new ExceptionCommandExecution
|
||||
{
|
||||
Id = command.Id,
|
||||
Exception = e.ToString()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static ICommandExecution Execute(MethodInfo currentCommand, object context, object? parameter,
|
||||
ICallRequest command)
|
||||
private static ICommandExecution Execute(IMethodInvoker invoker, object instance, object?[] parameter,
|
||||
ICallRequest command, RequestContext executionContext)
|
||||
{
|
||||
try
|
||||
{
|
||||
var finalParameter = parameter is null
|
||||
? Array.Empty<object>()
|
||||
: new[]
|
||||
{ parameter };
|
||||
var finalResult = currentCommand.Invoke(context, finalParameter);
|
||||
var finalResult = invoker.Invoke(instance, parameter, new object[] { executionContext });
|
||||
|
||||
if (currentCommand.ReturnType.Name == "Void")
|
||||
if (invoker.IsVoid)
|
||||
{
|
||||
return new FinalCommandExecution
|
||||
{
|
||||
@@ -120,9 +150,9 @@ namespace mROA.Implementation.Backend
|
||||
}
|
||||
}
|
||||
|
||||
private ICommandExecution ExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
||||
private ICommandExecution ExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||
IRepresentationModule representationModule)
|
||||
IRepresentationModule representationModule, RequestContext executionContext)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||
@@ -132,11 +162,7 @@ namespace mROA.Implementation.Backend
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var finalParameter = parameter is null
|
||||
? new object[] { token }
|
||||
: new[]
|
||||
{ parameter, token };
|
||||
var result = (Task)currentCommand.Invoke(context, finalParameter)!;
|
||||
var result = (Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!;
|
||||
|
||||
|
||||
result.ContinueWith(_ =>
|
||||
@@ -173,9 +199,9 @@ namespace mROA.Implementation.Backend
|
||||
}
|
||||
}
|
||||
|
||||
private ICommandExecution TypedExecuteAsync(MethodInfo currentCommand, object context, object? parameter,
|
||||
private ICommandExecution TypedExecuteAsync(IMethodInvoker invoker, object instance, object?[]? parameters,
|
||||
ICallRequest command, ICancellationRepository cancellationRepository,
|
||||
IRepresentationModule representationModule)
|
||||
IRepresentationModule representationModule, RequestContext executionContext)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
cancellationRepository.RegisterCancellation(command.Id, tokenSource);
|
||||
@@ -183,12 +209,8 @@ namespace mROA.Implementation.Backend
|
||||
var token = tokenSource.Token;
|
||||
try
|
||||
{
|
||||
var finalParameter = parameter is null
|
||||
? new object[] { token }
|
||||
: new[]
|
||||
{ parameter, token };
|
||||
var result =
|
||||
(Task)currentCommand.Invoke(context, finalParameter)!;
|
||||
(Task)invoker.Invoke(instance, parameters, new object[] { executionContext, token })!;
|
||||
|
||||
result.ContinueWith(t =>
|
||||
{
|
||||
@@ -198,7 +220,7 @@ namespace mROA.Implementation.Backend
|
||||
Id = command.Id,
|
||||
Result = finalResult
|
||||
};
|
||||
_cancellationRepo.FreeCancelation(command.Id);
|
||||
_cancellationRepo!.FreeCancelation(command.Id);
|
||||
|
||||
var multiClientOwnershipRepository =
|
||||
TransmissionConfig.OwnershipRepository as MultiClientOwnershipRepository;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace mROA.Implementation
|
||||
Guid Id { get; }
|
||||
int CommandId { get; }
|
||||
int ObjectId { get; }
|
||||
object? Parameter { get; }
|
||||
object?[]? Parameters { get; }
|
||||
}
|
||||
|
||||
public class DefaultCallRequest : ICallRequest
|
||||
@@ -20,7 +20,7 @@ namespace mROA.Implementation
|
||||
public int CommandId { get; set; }
|
||||
public int ObjectId { get; set; } = -1;
|
||||
|
||||
public object? Parameter { get; set; }
|
||||
public object?[]? Parameters { get; set; }
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Call request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||
@@ -32,7 +32,7 @@ namespace mROA.Implementation
|
||||
public Guid Id { get; set; }
|
||||
public int CommandId { get; set; } = -2;
|
||||
public int ObjectId { get; set; } = -2;
|
||||
public object? Parameter { get; set; } = null;
|
||||
public object?[]? Parameters { get; set; } = null;
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Cancel request {{ Id : {Id}, CommandId : {CommandId}, ObjectId : {ObjectId} }}";
|
||||
|
||||
@@ -94,15 +94,6 @@ namespace mROA.Implementation.Frontend
|
||||
tokenSource.Cancel();
|
||||
var request = defaultRequest.Result;
|
||||
|
||||
if (request.Parameter is not null)
|
||||
{
|
||||
var method = _methodRepository!.GetMethod(request.CommandId);
|
||||
var parameterType = method.GetParameters().First()
|
||||
.ParameterType;
|
||||
|
||||
request.Parameter = _serializationToolkit.Cast(request.Parameter, parameterType);
|
||||
}
|
||||
|
||||
var result = _executeModule.Execute(request, _contextRepository, _representationModule);
|
||||
|
||||
var resultType = MessageType.Unknown;
|
||||
|
||||
@@ -9,23 +9,26 @@ namespace mROA.Implementation
|
||||
public bool IsVoid { get; set; }
|
||||
public Type[] ParameterTypes { get; set; } = Type.EmptyTypes;
|
||||
public Type? ReturnType { get; set; }
|
||||
public Func<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);
|
||||
}
|
||||
|
||||
public static MethodInvoker Dispose = new MethodInvoker
|
||||
public Type SuitableType { get; set; } = null!;
|
||||
|
||||
public static readonly IMethodInvoker Dispose = new MethodInvoker
|
||||
{
|
||||
IsAsync = false,
|
||||
IsVoid = true,
|
||||
ReturnType = null,
|
||||
Invoking = ((instance, parameters, special) =>
|
||||
Invoking = (instance, _, _) =>
|
||||
{
|
||||
(instance as IDisposable)?.Dispose();
|
||||
return null;
|
||||
})
|
||||
},
|
||||
SuitableType = typeof(IDisposable)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,11 @@ namespace mROA.Implementation
|
||||
public int Id => _identifier.ContextId;
|
||||
public int OwnerId => _identifier.OwnerId;
|
||||
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)
|
||||
{
|
||||
var request = new DefaultCallRequest
|
||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter
|
||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters
|
||||
};
|
||||
|
||||
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
||||
@@ -76,11 +76,11 @@ namespace mROA.Implementation
|
||||
throw errorResponse.Result.GetException();
|
||||
}
|
||||
|
||||
protected async Task CallAsync(int methodId, object? parameter = default,
|
||||
protected async Task CallAsync(int methodId, object?[]? parameters = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var request = new DefaultCallRequest
|
||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameter = parameter
|
||||
{ CommandId = methodId, ObjectId = _identifier.ContextId, Parameters = parameters
|
||||
};
|
||||
await _representationModule.PostCallMessageAsync(request.Id, MessageType.CallRequest, request);
|
||||
|
||||
|
||||
@@ -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