тесты на работу модуля исполнения работают
This commit is contained in:
@@ -0,0 +1,37 @@
|
|||||||
|
using mROA.Implementation;
|
||||||
|
|
||||||
|
namespace mROA.Test;
|
||||||
|
|
||||||
|
[SharedObjectInterafce]
|
||||||
|
public interface ITestController
|
||||||
|
{
|
||||||
|
void A();
|
||||||
|
Task AAsync(CancellationToken cancellationToken);
|
||||||
|
int B();
|
||||||
|
Task<int> BAsync(CancellationToken cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SharedObjectSingleton]
|
||||||
|
public class TestController : ITestController
|
||||||
|
{
|
||||||
|
private int _bOut = 5;
|
||||||
|
public void A()
|
||||||
|
{
|
||||||
|
Console.WriteLine("A called");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task AAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int B()
|
||||||
|
{
|
||||||
|
return _bOut++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<int> BAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.FromResult(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,4 +5,5 @@ public interface IContextRepository
|
|||||||
int ResisterObject(object o);
|
int ResisterObject(object o);
|
||||||
void ClearObject(int id);
|
void ClearObject(int id);
|
||||||
object GetObject(int id);
|
object GetObject(int id);
|
||||||
|
object GetSingleObject(Type type);
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,9 @@ using mROA.Implementation;
|
|||||||
|
|
||||||
namespace mROA;
|
namespace mROA;
|
||||||
|
|
||||||
public interface IInputModule
|
public interface ISerialisationModule
|
||||||
{
|
{
|
||||||
void HandleIncomingRequest(int clientId, string command);
|
void HandleIncomingRequest(int clientId, string command);
|
||||||
void PostResponse(ICommandExecution call);
|
void PostResponse(ICommandExecution call);
|
||||||
|
void SetExecuteModule(IExecuteModule executeModule);
|
||||||
}
|
}
|
||||||
@@ -7,14 +7,14 @@ public interface ICallRequest
|
|||||||
int ClientId { get; set; }
|
int ClientId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class StaticCallRequest : ICallRequest
|
public class SingletonCallRequest : ICallRequest
|
||||||
{
|
{
|
||||||
public virtual int RequestTypeId => (int)RequestType.Static;
|
public virtual int RequestTypeId => (int)RequestType.Singleton;
|
||||||
public int CommandId { get; set; }
|
public int CommandId { get; set; }
|
||||||
public int ClientId { get; set; }
|
public int ClientId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CallRequest : StaticCallRequest
|
public class CallRequest : SingletonCallRequest
|
||||||
{
|
{
|
||||||
public override int RequestTypeId => (int)RequestType.NonParametrized;
|
public override int RequestTypeId => (int)RequestType.NonParametrized;
|
||||||
public int ObjectId { get; set; }
|
public int ObjectId { get; set; }
|
||||||
@@ -28,7 +28,7 @@ public class ParametrizedCallRequest : CallRequest
|
|||||||
|
|
||||||
enum RequestType
|
enum RequestType
|
||||||
{
|
{
|
||||||
Static,
|
Singleton,
|
||||||
NonParametrized,
|
NonParametrized,
|
||||||
Parametrized
|
Parametrized
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
namespace mROA.Implementation;
|
using System.Collections.Frozen;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
public class ContextRepository : IContextRepository
|
public class ContextRepository : IContextRepository
|
||||||
{
|
{
|
||||||
|
private FrozenDictionary<int, object?> _singletons;
|
||||||
private object[] _storage;
|
private object[] _storage;
|
||||||
private int _lastIndex;
|
private int _lastIndex;
|
||||||
|
|
||||||
@@ -16,6 +20,14 @@ public class ContextRepository : IContextRepository
|
|||||||
_storage = new object[StartupSize];
|
_storage = new object[StartupSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FillSingletons(Assembly assembly)
|
||||||
|
{
|
||||||
|
var types = assembly.GetTypes().Where(type =>
|
||||||
|
type is { IsClass: true, IsAbstract: false, IsGenericType: false } &&
|
||||||
|
type.GetCustomAttributes(typeof(SharedObjectSingletonAttribute), true).Length > 0);
|
||||||
|
_singletons = types.ToFrozenDictionary(t => t.GetInterfaces().FirstOrDefault(i => i.GetCustomAttributes(typeof(SharedObjectInterafceAttribute), true).Length > 0)!.GetHashCode(), Activator.CreateInstance);
|
||||||
|
}
|
||||||
|
|
||||||
public int ResisterObject(object o)
|
public int ResisterObject(object o)
|
||||||
{
|
{
|
||||||
if (_lastIndexFinder is not null)
|
if (_lastIndexFinder is not null)
|
||||||
@@ -42,6 +54,11 @@ public class ContextRepository : IContextRepository
|
|||||||
return _storage.Length == -1 || _storage.Length <= id ? null : _storage[id];
|
return _storage.Length == -1 || _storage.Length <= id ? null : _storage[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object GetSingleObject(Type type)
|
||||||
|
{
|
||||||
|
return _singletons.TryGetValue(type.GetHashCode(), out var value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> FindLastIndex()
|
private async Task<int> FindLastIndex()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _storage.Length; i++)
|
for (int i = 0; i < _storage.Length; i++)
|
||||||
@@ -54,5 +71,4 @@ public class ContextRepository : IContextRepository
|
|||||||
Array.Copy(_storage, nextStorage, _storage.Length);
|
Array.Copy(_storage, nextStorage, _storage.Length);
|
||||||
return _storage.Length;
|
return _storage.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+16
-18
@@ -4,18 +4,18 @@ using System.Text.Json.Serialization;
|
|||||||
|
|
||||||
namespace mROA.Implementation;
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
public class InputModule : IInputModule
|
public class JsonSerialisationModule : ISerialisationModule
|
||||||
{
|
{
|
||||||
private readonly IInteractionModule _dataSource;
|
private readonly IInteractionModule _dataSource;
|
||||||
private readonly IExecuteModule _executeModule;
|
private IExecuteModule _executeModule;
|
||||||
|
public JsonSerialisationModule(IInteractionModule dataSource)
|
||||||
public InputModule(IInteractionModule dataSource, IExecuteModule executeModule)
|
|
||||||
{
|
{
|
||||||
_dataSource = dataSource;
|
_dataSource = dataSource;
|
||||||
_executeModule = executeModule;
|
|
||||||
_dataSource.SetMessageHandler(HandleIncomingRequest);
|
_dataSource.SetMessageHandler(HandleIncomingRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetExecuteModule(IExecuteModule executeModule) => _executeModule = executeModule;
|
||||||
|
|
||||||
public void HandleIncomingRequest(int clientId, string command)
|
public void HandleIncomingRequest(int clientId, string command)
|
||||||
{
|
{
|
||||||
var type = JsonDocument.Parse(command).RootElement.GetProperty("RequestTypeId").GetInt32();
|
var type = JsonDocument.Parse(command).RootElement.GetProperty("RequestTypeId").GetInt32();
|
||||||
@@ -25,7 +25,7 @@ public class InputModule : IInputModule
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
request = JsonSerializer.Deserialize<StaticCallRequest>(command);
|
request = JsonSerializer.Deserialize<SingletonCallRequest>(command);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
request = JsonSerializer.Deserialize<CallRequest>(command);
|
request = JsonSerializer.Deserialize<CallRequest>(command);
|
||||||
@@ -34,27 +34,25 @@ public class InputModule : IInputModule
|
|||||||
request = JsonSerializer.Deserialize<ParametrizedCallRequest>(command);
|
request = JsonSerializer.Deserialize<ParametrizedCallRequest>(command);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
request = JsonSerializer.Deserialize<StaticCallRequest>(command);
|
request = JsonSerializer.Deserialize<SingletonCallRequest>(command);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.ClientId = clientId;
|
request.ClientId = clientId;
|
||||||
var response = _executeModule.Execute(request);
|
var response = _executeModule.Execute(request);
|
||||||
var texted = string.Empty;
|
PostResponse(response);
|
||||||
if (response is FinalCommandExecution finalCommand)
|
|
||||||
{
|
|
||||||
texted = JsonSerializer.Serialize(finalCommand);
|
|
||||||
}else if (response is AsyncCommandExecution asyncCommand)
|
|
||||||
{
|
|
||||||
texted = JsonSerializer.Serialize(asyncCommand);
|
|
||||||
}
|
|
||||||
var binary = Encoding.UTF8.GetBytes(texted);
|
|
||||||
_dataSource.SendTo(clientId, binary);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostResponse(ICommandExecution call)
|
public void PostResponse(ICommandExecution call)
|
||||||
{
|
{
|
||||||
var texted = JsonSerializer.Serialize(call);
|
var texted = string.Empty;
|
||||||
|
if (call is FinalCommandExecution finalCommand)
|
||||||
|
{
|
||||||
|
texted = JsonSerializer.Serialize(finalCommand);
|
||||||
|
}else if (call is AsyncCommandExecution asyncCommand)
|
||||||
|
{
|
||||||
|
texted = JsonSerializer.Serialize(asyncCommand);
|
||||||
|
}
|
||||||
var binary = Encoding.UTF8.GetBytes(texted);
|
var binary = Encoding.UTF8.GetBytes(texted);
|
||||||
_dataSource.SendTo(call.ClientId, binary);
|
_dataSource.SendTo(call.ClientId, binary);
|
||||||
}
|
}
|
||||||
@@ -4,11 +4,11 @@ namespace mROA.Implementation;
|
|||||||
|
|
||||||
public class MethodRepository : IMethodRepository
|
public class MethodRepository : IMethodRepository
|
||||||
{
|
{
|
||||||
private List<MethodInfo> _methods;
|
private List<MethodInfo> _methods = [];
|
||||||
|
|
||||||
public MethodInfo GetMethod(int id)
|
public MethodInfo GetMethod(int id)
|
||||||
{
|
{
|
||||||
if (_methods.Count >= id)
|
if (_methods.Count <= id)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return _methods[id];
|
return _methods[id];
|
||||||
@@ -24,4 +24,14 @@ public class MethodRepository : IMethodRepository
|
|||||||
{
|
{
|
||||||
return _methods;
|
return _methods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CollectForAssembly(Assembly assembly)
|
||||||
|
{
|
||||||
|
var types = assembly.GetTypes().Where(i => i.IsInterface && i.GetCustomAttributes(typeof(SharedObjectInterafceAttribute), true).Length > 0);
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
foreach (var method in type.GetMethods())
|
||||||
|
RegisterMethod(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,44 +2,67 @@
|
|||||||
|
|
||||||
namespace mROA.Implementation;
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
public class PrepairedExecutionModule(
|
public class PrepairedExecutionModule : IExecuteModule
|
||||||
IMethodRepository methodRepo,
|
|
||||||
IInputModule inputModule,
|
|
||||||
IContextRepository contextRepo)
|
|
||||||
: IExecuteModule
|
|
||||||
{
|
{
|
||||||
|
private readonly IMethodRepository _methodRepo;
|
||||||
|
private readonly ISerialisationModule _serialisationModule;
|
||||||
|
private readonly IContextRepository _contextRepo;
|
||||||
|
private readonly MethodInfo _resultExtractionMethod;
|
||||||
|
|
||||||
|
public PrepairedExecutionModule(IMethodRepository methodRepo,
|
||||||
|
ISerialisationModule serialisationModule,
|
||||||
|
IContextRepository contextRepo)
|
||||||
|
{
|
||||||
|
_methodRepo = methodRepo;
|
||||||
|
_serialisationModule = serialisationModule;
|
||||||
|
_contextRepo = contextRepo;
|
||||||
|
_serialisationModule.SetExecuteModule(this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public ICommandExecution Execute(ICallRequest command)
|
public ICommandExecution Execute(ICallRequest command)
|
||||||
{
|
{
|
||||||
var currentCommand = methodRepo.GetMethod(command.CommandId);
|
var currentCommand = _methodRepo.GetMethod(command.CommandId);
|
||||||
if (currentCommand == null)
|
if (currentCommand == null)
|
||||||
throw new Exception($"Command {command.CommandId} not found");
|
throw new Exception($"Command {command.CommandId} not found");
|
||||||
|
|
||||||
var context = command is CallRequest request ? contextRepo.GetObject(request.ObjectId) : null;
|
var context = command is CallRequest request ? _contextRepo.GetObject(request.ObjectId) : _contextRepo.GetSingleObject(currentCommand.DeclaringType);
|
||||||
var parameter = command is ParametrizedCallRequest callRequest ? callRequest.Parameter : null;
|
var parameter = command is ParametrizedCallRequest callRequest ? callRequest.Parameter : null;
|
||||||
|
|
||||||
if (currentCommand.ReturnType == typeof(Task<>))
|
if (currentCommand.ReturnType.BaseType == typeof(Task) && currentCommand.ReturnType.GenericTypeArguments.Length == 1)
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
|
|
||||||
var result =
|
var result =
|
||||||
currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token]) as Task<object>;
|
currentCommand.Invoke(context, parameter is null ? [token] : [parameter, token]) as Task;
|
||||||
var exec = new AsyncCommandExecution(tokenSource)
|
var exec = new AsyncCommandExecution(tokenSource)
|
||||||
{ CommandId = command.CommandId, ClientId = command.ClientId };
|
{ CommandId = command.CommandId, ClientId = command.ClientId };
|
||||||
|
|
||||||
result.ContinueWith(task =>
|
result.ContinueWith(task =>
|
||||||
{
|
{
|
||||||
var result = task.Result;
|
var result = task.GetType().GetProperty("Result").GetValue(task);
|
||||||
inputModule.PostResponse(new FinalCommandExecution
|
_serialisationModule.PostResponse(new FinalCommandExecution
|
||||||
{
|
{
|
||||||
ExecutionId = exec.ExecutionId, Result = result, CommandId = command.CommandId,
|
ExecutionId = exec.ExecutionId, Result = result, CommandId = command.CommandId,
|
||||||
ClientId = command.ClientId
|
ClientId = command.ClientId
|
||||||
});
|
});
|
||||||
}, token);
|
}, token);
|
||||||
|
|
||||||
|
// result.ContinueWith(task =>
|
||||||
|
// {
|
||||||
|
// var result = task.Result;
|
||||||
|
// _serialisationModule.PostResponse(new FinalCommandExecution
|
||||||
|
// {
|
||||||
|
// ExecutionId = exec.ExecutionId, Result = result, CommandId = command.CommandId,
|
||||||
|
// ClientId = command.ClientId
|
||||||
|
// });
|
||||||
|
// }, token);
|
||||||
|
|
||||||
return exec;
|
return exec;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (currentCommand.ReturnType == typeof(Task))
|
||||||
{
|
{
|
||||||
var tokenSource = new CancellationTokenSource();
|
var tokenSource = new CancellationTokenSource();
|
||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
@@ -50,7 +73,7 @@ public class PrepairedExecutionModule(
|
|||||||
|
|
||||||
result.ContinueWith(_ =>
|
result.ContinueWith(_ =>
|
||||||
{
|
{
|
||||||
inputModule.PostResponse(new FinalCommandExecution
|
_serialisationModule.PostResponse(new FinalCommandExecution
|
||||||
{
|
{
|
||||||
ExecutionId = exec.ExecutionId, Result = null, CommandId = command.CommandId,
|
ExecutionId = exec.ExecutionId, Result = null, CommandId = command.CommandId,
|
||||||
ClientId = command.ClientId
|
ClientId = command.ClientId
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
|
public class SharedObjectInterafceAttribute : Attribute;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
|
public class SharedObjectSingletonAttribute : Attribute;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
namespace mROA.Implementation;
|
||||||
|
|
||||||
|
public class MockSerializationModule : ISerialisationModule
|
||||||
|
{
|
||||||
|
public void HandleIncomingRequest(int clientId, string command)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostResponse(ICommandExecution call)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetExecuteModule(IExecuteModule executeModule)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user