diff --git a/mROA/ICommandExecution.cs b/mROA/Abstract/ICommandExecution.cs similarity index 66% rename from mROA/ICommandExecution.cs rename to mROA/Abstract/ICommandExecution.cs index 6b626e1..04641f4 100644 --- a/mROA/ICommandExecution.cs +++ b/mROA/Abstract/ICommandExecution.cs @@ -2,10 +2,7 @@ namespace mROA; public interface ICommandExecution { - int ExecutionId { get; set; } - + Guid ExecutionId { get; init; } int ClientId { get; set; } int CommandId { get; set; } - - void Cancel(); } \ No newline at end of file diff --git a/mROA/Abstract/IContextRepository.cs b/mROA/Abstract/IContextRepository.cs new file mode 100644 index 0000000..beb7fa2 --- /dev/null +++ b/mROA/Abstract/IContextRepository.cs @@ -0,0 +1,8 @@ +namespace mROA; + +public interface IContextRepository +{ + int ResisterObject(object o); + void ClearObject(int id); + object GetObject(int id); +} \ No newline at end of file diff --git a/mROA/Abstract/IExecuteModule.cs b/mROA/Abstract/IExecuteModule.cs new file mode 100644 index 0000000..df9c495 --- /dev/null +++ b/mROA/Abstract/IExecuteModule.cs @@ -0,0 +1,6 @@ +namespace mROA; + +public interface IExecuteModule +{ + ICommandExecution Execute(int objectId, int commandId, object parameter); +} \ No newline at end of file diff --git a/mROA/Abstract/IInputModule.cs b/mROA/Abstract/IInputModule.cs new file mode 100644 index 0000000..0c55f50 --- /dev/null +++ b/mROA/Abstract/IInputModule.cs @@ -0,0 +1,7 @@ +namespace mROA; + +public interface IInputModule +{ + void HandleIncomingRequest(object command); + void PostResponse(ICommandExecution call); +} \ No newline at end of file diff --git a/mROA/IInteractionModule.cs b/mROA/Abstract/IInteractionModule.cs similarity index 56% rename from mROA/IInteractionModule.cs rename to mROA/Abstract/IInteractionModule.cs index ad2c005..e5c5878 100644 --- a/mROA/IInteractionModule.cs +++ b/mROA/Abstract/IInteractionModule.cs @@ -2,5 +2,6 @@ namespace mROA; public interface IInteractionModule { + void SetInteractionHandler(Action<(int clientId, byte[] message)> handler); void SendTo(int clientId, byte[] message); } \ No newline at end of file diff --git a/mROA/Abstract/IMethodRepository.cs b/mROA/Abstract/IMethodRepository.cs new file mode 100644 index 0000000..731d7de --- /dev/null +++ b/mROA/Abstract/IMethodRepository.cs @@ -0,0 +1,11 @@ +using System.Reflection; + +namespace mROA; + +public interface IMethodRepository +{ + MethodInfo GetMethod(int id); + int RegisterMethod(MethodInfo method); + + IEnumerable GetMethods(); +} \ No newline at end of file diff --git a/mROA/IExecuteModule.cs b/mROA/IExecuteModule.cs deleted file mode 100644 index 98f483f..0000000 --- a/mROA/IExecuteModule.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace mROA; - -public interface IExecuteModule -{ - void Execute(int objectId, int commandId, object parameter); -} \ No newline at end of file diff --git a/mROA/IInputModule.cs b/mROA/IInputModule.cs deleted file mode 100644 index b6626fd..0000000 --- a/mROA/IInputModule.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace mROA; - -public interface IInputModule -{ - void AddIncomingRequestHandler(Action handler); - void SendResponse(ICommandExecution call, object response); -} \ No newline at end of file diff --git a/mROA/Implementation/CallRequest.cs b/mROA/Implementation/CallRequest.cs new file mode 100644 index 0000000..f887642 --- /dev/null +++ b/mROA/Implementation/CallRequest.cs @@ -0,0 +1,34 @@ +namespace mROA.Implementation; + +public interface ICallRequest +{ + int RequestTypeId { get; } + int CommandId { get; set; } + int ClientId { get; set; } +} + +public class StaticCallRequest : ICallRequest +{ + public virtual int RequestTypeId => (int)RequestType.Static; + public int CommandId { get; set; } + public int ClientId { get; set; } +} + +public class CallRequest : StaticCallRequest +{ + public override int RequestTypeId => (int)RequestType.NonParametrized; + public int ObjectId { get; set; } +} + +public class ParametrizedCallRequest : CallRequest +{ + public override int RequestTypeId => (int)RequestType.Parametrized; + public object Parameter { get; set; } +} + +enum RequestType +{ + Static, + NonParametrized, + Parametrized +} \ No newline at end of file diff --git a/mROA/Implementation/ContextRepository.cs b/mROA/Implementation/ContextRepository.cs new file mode 100644 index 0000000..b4475ed --- /dev/null +++ b/mROA/Implementation/ContextRepository.cs @@ -0,0 +1,58 @@ +namespace mROA.Implementation; + +public class ContextRepository : IContextRepository +{ + private object[] _storage; + private int _lastIndex; + + private Task? _lastIndexFinder; + + const int StartupSize = 1024; + const int GrowSize = 128; + + + public ContextRepository() + { + _storage = new object[StartupSize]; + } + + public int ResisterObject(object o) + { + if (_lastIndexFinder is not null) + _lastIndexFinder.Wait(); + + var oldIndex = _lastIndex; + _lastIndex = _lastIndexFinder.Result; + + _storage[oldIndex] = o; + + _lastIndexFinder = FindLastIndex(); + + return _lastIndex; + } + + public void ClearObject(int id) + { + _storage[id] = null; + _lastIndexFinder = Task.FromResult(id); + } + + public object GetObject(int id) + { + return _storage.Length == -1 || _storage.Length <= id ? null : _storage[id]; + } + + private async Task FindLastIndex() + { + for (int i = 0; i < _storage.Length; i++) + { + if (_storage[i] is null) + return i; + } + + var nextStorage = new object[_storage.Length + GrowSize]; + Array.Copy(_storage, nextStorage, _storage.Length); + return _storage.Length; + } + +} \ No newline at end of file diff --git a/mROA/Implementation/FinalCommandExecution.cs b/mROA/Implementation/FinalCommandExecution.cs new file mode 100644 index 0000000..bbf70c3 --- /dev/null +++ b/mROA/Implementation/FinalCommandExecution.cs @@ -0,0 +1,36 @@ +namespace mROA.Implementation; + +public class FinalCommandExecution : ICommandExecution +{ + public Guid ExecutionId { get; init; } = new Guid(); + public int ClientId { get; set; } + public int CommandId { get; set; } + public object? Result { get; set; } +} + +public class ExeptionCommandExecution : ICommandExecution +{ + public Guid ExecutionId { get; init; } = new Guid(); + public int ClientId { get; set; } + public int CommandId { get; set; } + public string Reason { get; set; } +} + +public class AsyncCommandExecution : ICommandExecution +{ + public Guid ExecutionId { get; init; } = new Guid(); + public int ClientId { get; set; } + public int CommandId { get; set; } + + public void Cancel() + { + LocalToken.Cancel(); + } + + private CancellationTokenSource LocalToken; + + public AsyncCommandExecution(CancellationTokenSource localToken) + { + LocalToken = localToken; + } +} \ No newline at end of file diff --git a/mROA/Implementation/InputModule.cs b/mROA/Implementation/InputModule.cs new file mode 100644 index 0000000..aa5bc0c --- /dev/null +++ b/mROA/Implementation/InputModule.cs @@ -0,0 +1,21 @@ +using System.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace mROA.Implementation; + +public class InputModule(IInteractionModule dataSource, IExecuteModule executeModule) + : IInputModule +{ + public void HandleIncomingRequest(object command) + { + + } + + public void PostResponse(ICommandExecution call) + { + var texted = JsonSerializer.Serialize(call); + var binary = Encoding.UTF8.GetBytes(texted); + dataSource.SendTo(call.ClientId, binary); + } +} \ No newline at end of file diff --git a/mROA/Implementation/MethodRepository.cs b/mROA/Implementation/MethodRepository.cs new file mode 100644 index 0000000..ac163ee --- /dev/null +++ b/mROA/Implementation/MethodRepository.cs @@ -0,0 +1,27 @@ +using System.Reflection; + +namespace mROA.Implementation; + +public class MethodRepository : IMethodRepository +{ + private List _methods; + + public MethodInfo GetMethod(int id) + { + if (_methods.Count >= id) + return null; + + return _methods[id]; + } + + public int RegisterMethod(MethodInfo method) + { + _methods.Add(method); + return _methods.Count - 1; + } + + public IEnumerable GetMethods() + { + return _methods; + } +} \ No newline at end of file diff --git a/mROA/Implementation/PrepairedExecutionModule.cs b/mROA/Implementation/PrepairedExecutionModule.cs new file mode 100644 index 0000000..931967b --- /dev/null +++ b/mROA/Implementation/PrepairedExecutionModule.cs @@ -0,0 +1,38 @@ +using System.Reflection; + +namespace mROA.Implementation; + +public class PrepairedExecutionModule( + IMethodRepository methodRepo, + IInputModule inputModule, + IContextRepository contextRepo) + : IExecuteModule +{ + public ICommandExecution Execute(int objectId, int commandId, object parameter) + { + var command = methodRepo.GetMethod(commandId); + if (command == null) + throw new Exception($"Command {commandId} not found"); + + if (command.ReturnType != typeof(Task)) + { + var tokenSource = new CancellationTokenSource(); + var token = tokenSource.Token; + var result = command.Invoke(contextRepo.GetObject(objectId), [parameter, token]) as Task; + + var exec = new AsyncCommandExecution(tokenSource) { CommandId = commandId }; + + result.ContinueWith(task => + { + var result = task.Result; + inputModule.PostResponse(new FinalCommandExecution + { ExecutionId = exec.ExecutionId, Result = result, CommandId = commandId }); + }, token); + + return exec; + } + + var finalResult = command.Invoke(contextRepo.GetObject(objectId), [parameter]); + return new FinalCommandExecution { CommandId = commandId, Result = finalResult }; + } +} \ No newline at end of file