тесты на работу модуля исполнения работают
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);
|
||||
void ClearObject(int id);
|
||||
object GetObject(int id);
|
||||
object GetSingleObject(Type type);
|
||||
}
|
||||
@@ -2,8 +2,9 @@ using mROA.Implementation;
|
||||
|
||||
namespace mROA;
|
||||
|
||||
public interface IInputModule
|
||||
public interface ISerialisationModule
|
||||
{
|
||||
void HandleIncomingRequest(int clientId, string command);
|
||||
void PostResponse(ICommandExecution call);
|
||||
void SetExecuteModule(IExecuteModule executeModule);
|
||||
}
|
||||
@@ -7,14 +7,14 @@ public interface ICallRequest
|
||||
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 ClientId { get; set; }
|
||||
}
|
||||
|
||||
public class CallRequest : StaticCallRequest
|
||||
public class CallRequest : SingletonCallRequest
|
||||
{
|
||||
public override int RequestTypeId => (int)RequestType.NonParametrized;
|
||||
public int ObjectId { get; set; }
|
||||
@@ -28,7 +28,7 @@ public class ParametrizedCallRequest : CallRequest
|
||||
|
||||
enum RequestType
|
||||
{
|
||||
Static,
|
||||
Singleton,
|
||||
NonParametrized,
|
||||
Parametrized
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
namespace mROA.Implementation;
|
||||
using System.Collections.Frozen;
|
||||
using System.Reflection;
|
||||
|
||||
namespace mROA.Implementation;
|
||||
|
||||
public class ContextRepository : IContextRepository
|
||||
{
|
||||
private FrozenDictionary<int, object?> _singletons;
|
||||
private object[] _storage;
|
||||
private int _lastIndex;
|
||||
|
||||
@@ -16,6 +20,14 @@ public class ContextRepository : IContextRepository
|
||||
_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)
|
||||
{
|
||||
if (_lastIndexFinder is not null)
|
||||
@@ -42,6 +54,11 @@ public class ContextRepository : IContextRepository
|
||||
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()
|
||||
{
|
||||
for (int i = 0; i < _storage.Length; i++)
|
||||
@@ -54,5 +71,4 @@ public class ContextRepository : IContextRepository
|
||||
Array.Copy(_storage, nextStorage, _storage.Length);
|
||||
return _storage.Length;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-18
@@ -4,18 +4,18 @@ using System.Text.Json.Serialization;
|
||||
|
||||
namespace mROA.Implementation;
|
||||
|
||||
public class InputModule : IInputModule
|
||||
public class JsonSerialisationModule : ISerialisationModule
|
||||
{
|
||||
private readonly IInteractionModule _dataSource;
|
||||
private readonly IExecuteModule _executeModule;
|
||||
|
||||
public InputModule(IInteractionModule dataSource, IExecuteModule executeModule)
|
||||
private IExecuteModule _executeModule;
|
||||
public JsonSerialisationModule(IInteractionModule dataSource)
|
||||
{
|
||||
_dataSource = dataSource;
|
||||
_executeModule = executeModule;
|
||||
_dataSource.SetMessageHandler(HandleIncomingRequest);
|
||||
}
|
||||
|
||||
public void SetExecuteModule(IExecuteModule executeModule) => _executeModule = executeModule;
|
||||
|
||||
public void HandleIncomingRequest(int clientId, string command)
|
||||
{
|
||||
var type = JsonDocument.Parse(command).RootElement.GetProperty("RequestTypeId").GetInt32();
|
||||
@@ -25,7 +25,7 @@ public class InputModule : IInputModule
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
request = JsonSerializer.Deserialize<StaticCallRequest>(command);
|
||||
request = JsonSerializer.Deserialize<SingletonCallRequest>(command);
|
||||
break;
|
||||
case 1:
|
||||
request = JsonSerializer.Deserialize<CallRequest>(command);
|
||||
@@ -34,27 +34,25 @@ public class InputModule : IInputModule
|
||||
request = JsonSerializer.Deserialize<ParametrizedCallRequest>(command);
|
||||
break;
|
||||
default:
|
||||
request = JsonSerializer.Deserialize<StaticCallRequest>(command);
|
||||
request = JsonSerializer.Deserialize<SingletonCallRequest>(command);
|
||||
break;
|
||||
}
|
||||
|
||||
request.ClientId = clientId;
|
||||
var response = _executeModule.Execute(request);
|
||||
var texted = string.Empty;
|
||||
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);
|
||||
PostResponse(response);
|
||||
}
|
||||
|
||||
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);
|
||||
_dataSource.SendTo(call.ClientId, binary);
|
||||
}
|
||||
@@ -4,11 +4,11 @@ namespace mROA.Implementation;
|
||||
|
||||
public class MethodRepository : IMethodRepository
|
||||
{
|
||||
private List<MethodInfo> _methods;
|
||||
private List<MethodInfo> _methods = [];
|
||||
|
||||
public MethodInfo GetMethod(int id)
|
||||
{
|
||||
if (_methods.Count >= id)
|
||||
if (_methods.Count <= id)
|
||||
return null;
|
||||
|
||||
return _methods[id];
|
||||
@@ -24,4 +24,14 @@ public class MethodRepository : IMethodRepository
|
||||
{
|
||||
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;
|
||||
|
||||
public class PrepairedExecutionModule(
|
||||
IMethodRepository methodRepo,
|
||||
IInputModule inputModule,
|
||||
IContextRepository contextRepo)
|
||||
: IExecuteModule
|
||||
public class PrepairedExecutionModule : 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)
|
||||
{
|
||||
var currentCommand = methodRepo.GetMethod(command.CommandId);
|
||||
var currentCommand = _methodRepo.GetMethod(command.CommandId);
|
||||
if (currentCommand == null)
|
||||
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;
|
||||
|
||||
if (currentCommand.ReturnType == typeof(Task<>))
|
||||
if (currentCommand.ReturnType.BaseType == typeof(Task) && currentCommand.ReturnType.GenericTypeArguments.Length == 1)
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
var token = tokenSource.Token;
|
||||
|
||||
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)
|
||||
{ CommandId = command.CommandId, ClientId = command.ClientId };
|
||||
|
||||
result.ContinueWith(task =>
|
||||
{
|
||||
var result = task.Result;
|
||||
inputModule.PostResponse(new FinalCommandExecution
|
||||
var result = task.GetType().GetProperty("Result").GetValue(task);
|
||||
_serialisationModule.PostResponse(new FinalCommandExecution
|
||||
{
|
||||
ExecutionId = exec.ExecutionId, Result = result, CommandId = command.CommandId,
|
||||
ClientId = command.ClientId
|
||||
});
|
||||
}, 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;
|
||||
}
|
||||
else
|
||||
|
||||
if (currentCommand.ReturnType == typeof(Task))
|
||||
{
|
||||
var tokenSource = new CancellationTokenSource();
|
||||
var token = tokenSource.Token;
|
||||
@@ -50,7 +73,7 @@ public class PrepairedExecutionModule(
|
||||
|
||||
result.ContinueWith(_ =>
|
||||
{
|
||||
inputModule.PostResponse(new FinalCommandExecution
|
||||
_serialisationModule.PostResponse(new FinalCommandExecution
|
||||
{
|
||||
ExecutionId = exec.ExecutionId, Result = null, CommandId = command.CommandId,
|
||||
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