База для нового бэкэнда

This commit is contained in:
2025-03-06 14:10:52 +03:00
parent be6dedaee4
commit c802f337c7
18 changed files with 245 additions and 163 deletions
@@ -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;
+3 -3
View File
@@ -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;
+8 -5
View File
@@ -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)
};
}
}
+4 -4
View File
@@ -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);
+16
View File
@@ -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;
}
}
}