diff --git a/src/DtronixMessageQueue/DtronixMessageQueue.csproj b/src/DtronixMessageQueue/DtronixMessageQueue.csproj
index 2060450..8256e82 100644
--- a/src/DtronixMessageQueue/DtronixMessageQueue.csproj
+++ b/src/DtronixMessageQueue/DtronixMessageQueue.csproj
@@ -69,6 +69,7 @@
+
diff --git a/src/DtronixMessageQueue/Rpc/MessageHandlers/RpcCallMessageHandler.cs b/src/DtronixMessageQueue/Rpc/MessageHandlers/RpcCallMessageHandler.cs
index 417c012..2a6fcfc 100644
--- a/src/DtronixMessageQueue/Rpc/MessageHandlers/RpcCallMessageHandler.cs
+++ b/src/DtronixMessageQueue/Rpc/MessageHandlers/RpcCallMessageHandler.cs
@@ -21,9 +21,11 @@ public class RpcCallMessageHandler : MessageHandler
/// Contains all services that can be remotely executed on this session.
///
- public readonly Dictionary> Services =
+ private readonly Dictionary> _services =
new Dictionary>();
+
+
///
/// Proxy objects to be invoked on this session and proxied to the recipient session.
///
@@ -50,6 +52,17 @@ public RpcCallMessageHandler(TSession session) : base(session)
Handlers.Add((byte) RpcCallMessageAction.MethodReturn, ProcessRpcReturnAction);
}
+ public void AddService(T instance) where T : IRemoteService
+ {
+ _services.Add(instance.Name, instance);
+ var methods = instance.GetType().GetMethods();
+ }
+
+ ///
+ /// Cancels the specified action.
+ ///
+ /// byte associated with the RpcCallMessageAction enum.>
+ /// Message containing the cancellation information.
public void MethodCancelAction(byte actionId, MqMessage message)
{
var cancellationId = message[0].ReadUInt16(0);
@@ -87,13 +100,13 @@ private void ProcessRpcCallAction(byte actionId, MqMessage message)
var recArgumentCount = serialization.MessageReader.ReadByte();
// Verify that the requested service exists.
- if (Services.ContainsKey(recServiceName) == false)
+ if (_services.ContainsKey(recServiceName) == false)
{
throw new Exception($"Service '{recServiceName}' does not exist.");
}
// Get the service from the instance list.
- var service = Services[recServiceName];
+ var service = _services[recServiceName];
// Get the actual method. TODO: Might want to cache this for performance purposes.
var methodInfo = service.GetType().GetMethod(recMethodName);
diff --git a/src/DtronixMessageQueue/Rpc/RpcRemoteService.cs b/src/DtronixMessageQueue/Rpc/RpcRemoteService.cs
new file mode 100644
index 0000000..39b3ad0
--- /dev/null
+++ b/src/DtronixMessageQueue/Rpc/RpcRemoteService.cs
@@ -0,0 +1,22 @@
+namespace DtronixMessageQueue.Rpc
+{
+ ///
+ /// Represents a remote service accessible through a RpcProxy object.
+ ///
+ /// Session type.
+ /// Configuration type.
+ public abstract class RpcRemoteService
+ where TSession : RpcSession, new()
+ where TConfig : RpcConfig
+ {
+ ///
+ /// Name of this service.
+ ///
+ public abstract string Name { get; }
+
+ ///
+ /// Session for this service instance.
+ ///
+ public TSession Session { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/DtronixMessageQueue/Rpc/RpcSession.cs b/src/DtronixMessageQueue/Rpc/RpcSession.cs
index 3e1e4cd..1057878 100644
--- a/src/DtronixMessageQueue/Rpc/RpcSession.cs
+++ b/src/DtronixMessageQueue/Rpc/RpcSession.cs
@@ -388,8 +388,8 @@ public T GetProxy() where T : IRemoteService
/// Instance to execute methods on.
public void AddService(T instance) where T : IRemoteService
{
- RpcCallHandler.Services.Add(instance.Name, instance);
- instance.Session = (TSession) this;
+ instance.Session = (TSession)this;
+ RpcCallHandler.AddService(instance);
}
}
}
\ No newline at end of file
diff --git a/src/DtronixMessageQueue/Rpc/ServiceMethodCache.cs b/src/DtronixMessageQueue/Rpc/ServiceMethodCache.cs
new file mode 100644
index 0000000..68f42c6
--- /dev/null
+++ b/src/DtronixMessageQueue/Rpc/ServiceMethodCache.cs
@@ -0,0 +1,199 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DtronixMessageQueue.Rpc
+{
+ public class ServiceMethodCache
+ where TSession : RpcSession, new()
+ where TConfig : RpcConfig
+ {
+
+ private delegate object InvokeHandler(object target, object[] paramters);
+
+
+ private Dictionary> _serviceMethods =
+ new Dictionary>();
+
+ public ServiceMethodCache()
+ {
+
+ }
+
+ public void AddService(T instance) where T : IRemoteService
+ {
+ // If this service has already been registered, do nothing.
+ if (_serviceMethods.ContainsKey(instance.Name))
+ return;
+
+ var methods = new
+
+ // Get all the public methods for this
+ var methods = instance.GetType().GetMethods();
+
+ foreach (var methodInfo in methods)
+ {
+ methodInfo.Name
+ }
+ }
+
+ public void Invoke(string service, string method, object serviceTarget, object[] parameters)
+ {
+
+ }
+
+ private class ServiceMethodInfo
+ {
+ public MethodInfo MethodInfo;
+ public Type[] ParameterTypes;
+ public bool hasCancellation;
+ }
+
+ ///
+ /// Black magic box to create IL code invoker.
+ ///
+ /// Method to create an invoker for.
+ /// Invoker delegate crafted for the specified method.
+ ///
+ /// https://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker?msg=1555655#xx1555655xx
+ ///
+ private static InvokeHandler GetMethodInvoker(MethodInfo methodInfo)
+ {
+ if (methodInfo == null)
+ throw new ArgumentNullException(nameof(methodInfo), "Passed method must not be null.");
+
+ var dynamicMethod = new DynamicMethod(string.Empty, typeof(object),
+ new[] { typeof(object), typeof(object[]) }, methodInfo.DeclaringType.Module);
+
+ var il = dynamicMethod.GetILGenerator();
+ var ps = methodInfo.GetParameters();
+ var paramTypes = new Type[ps.Length];
+
+ for (var i = 0; i < paramTypes.Length; i++)
+ {
+ if (ps[i].ParameterType.IsByRef)
+ paramTypes[i] = ps[i].ParameterType.GetElementType();
+ else
+ paramTypes[i] = ps[i].ParameterType;
+ }
+
+ var locals = new LocalBuilder[paramTypes.Length];
+
+ for (var i = 0; i < paramTypes.Length; i++)
+ locals[i] = il.DeclareLocal(paramTypes[i], true);
+
+ for (var i = 0; i < paramTypes.Length; i++)
+ {
+ il.Emit(OpCodes.Ldarg_1);
+ EmitFastInt(il, i);
+ il.Emit(OpCodes.Ldelem_Ref);
+ EmitCastToReference(il, paramTypes[i]);
+ il.Emit(OpCodes.Stloc, locals[i]);
+ }
+
+ if (!methodInfo.IsStatic)
+ il.Emit(OpCodes.Ldarg_0);
+
+ for (var i = 0; i < paramTypes.Length; i++)
+ il.Emit(ps[i].ParameterType.IsByRef ? OpCodes.Ldloca_S : OpCodes.Ldloc, locals[i]);
+
+ il.EmitCall(methodInfo.IsStatic ? OpCodes.Call : OpCodes.Callvirt, methodInfo, null);
+
+
+ if (methodInfo.ReturnType == typeof(void))
+ il.Emit(OpCodes.Ldnull);
+ else
+ EmitBoxIfNeeded(il, methodInfo.ReturnType);
+
+ for (var i = 0; i < paramTypes.Length; i++)
+ {
+ if (!ps[i].ParameterType.IsByRef)
+ continue;
+
+ il.Emit(OpCodes.Ldarg_1);
+ EmitFastInt(il, i);
+ il.Emit(OpCodes.Ldloc, locals[i]);
+
+ if (locals[i].LocalType.IsValueType)
+ il.Emit(OpCodes.Box, locals[i].LocalType);
+
+ il.Emit(OpCodes.Stelem_Ref);
+ }
+
+ il.Emit(OpCodes.Ret);
+ var invoker = (InvokeHandler)dynamicMethod.CreateDelegate(typeof(InvokeHandler));
+ return invoker;
+ }
+
+ private static void EmitCastToReference(ILGenerator il, System.Type type)
+ {
+ il.Emit(type.IsValueType ? OpCodes.Unbox_Any : OpCodes.Castclass, type);
+ }
+
+ private static void EmitBoxIfNeeded(ILGenerator il, System.Type type)
+ {
+ if (type.IsValueType)
+ {
+ il.Emit(OpCodes.Box, type);
+ }
+ }
+
+ private static void EmitFastInt(ILGenerator il, int value)
+ {
+ switch (value)
+ {
+ case -1:
+ il.Emit(OpCodes.Ldc_I4_M1);
+ return;
+ case 0:
+ il.Emit(OpCodes.Ldc_I4_0);
+ return;
+ case 1:
+ il.Emit(OpCodes.Ldc_I4_1);
+ return;
+ case 2:
+ il.Emit(OpCodes.Ldc_I4_2);
+ return;
+ case 3:
+ il.Emit(OpCodes.Ldc_I4_3);
+ return;
+ case 4:
+ il.Emit(OpCodes.Ldc_I4_4);
+ return;
+ case 5:
+ il.Emit(OpCodes.Ldc_I4_5);
+ return;
+ case 6:
+ il.Emit(OpCodes.Ldc_I4_6);
+ return;
+ case 7:
+ il.Emit(OpCodes.Ldc_I4_7);
+ return;
+ case 8:
+ il.Emit(OpCodes.Ldc_I4_8);
+ return;
+ }
+
+ if (value > -129 && value < 128)
+ {
+ il.Emit(OpCodes.Ldc_I4_S, (SByte)value);
+ }
+ else
+ {
+ il.Emit(OpCodes.Ldc_I4, value);
+ }
+ }
+
+
+ }
+
+
+
+
+
+
+}