using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using ZeroLevel.Services.Invokation; using ZeroLevel.Services.Serialization; namespace ZeroLevel.Network { internal sealed class Router : IRouter { public event Action OnDisconnect = _ => { }; // must be never rised public event Action OnConnect = _ => { }; // must be never rised #region Routing private sealed class MRInvoker { /// /// Creates a compiled expression for a quick method call, returns the identifier of the expression and a delegate for the call. /// private static Invoker CreateCompiledExpression(MethodInfo method) { var targetArg = Expression.Parameter(typeof(object)); // Target var argsArg = Expression.Parameter(typeof(object[])); // Method's args var parameters = method.GetParameters(); Expression body = Expression.Call( method.IsStatic ? null : Expression.Convert(targetArg, method.DeclaringType), // Method's type method, parameters.Select((p, i) => Expression.Convert(Expression.ArrayIndex(argsArg, Expression.Constant(i)), p.ParameterType))); if (body.Type == typeof(void)) body = Expression.Block(body, Expression.Constant(null)); else if (body.Type.IsValueType) body = Expression.Convert(body, typeof(object)); return Expression.Lambda(body, targetArg, argsArg).Compile(); } private static Invoker CreateCompiledExpression(Delegate handler) { return CreateCompiledExpression(handler.GetMethodInfo()); } private object _instance; private Invoker _invoker; private Type _typeReq; private Type _typeResp; private bool _noArguments = false; public static MRInvoker Create(MessageHandler handler) { return new MRInvoker { _noArguments = true, _typeReq = null, _typeResp = null, _instance = handler.Target, _invoker = CreateCompiledExpression(handler) }; } public static MRInvoker Create(MessageHandler handler) { return new MRInvoker { _typeReq = typeof(T), _typeResp = null, _instance = handler.Target, _invoker = CreateCompiledExpression(handler) }; } public static MRInvoker Create(RequestHandler handler) { return new MRInvoker { _noArguments = true, _typeReq = null, _typeResp = typeof(Tresponse), _instance = handler.Target, _invoker = CreateCompiledExpression(handler) }; } public static MRInvoker Create(RequestHandler handler) { return new MRInvoker { _typeReq = typeof(Trequest), _typeResp = typeof(Tresponse), _instance = handler.Target, _invoker = CreateCompiledExpression(handler) }; } public object Invoke(byte[] data, ISocketClient client) { if (_typeResp == null) { var incoming = (_typeReq == typeof(byte[])) ? data : MessageSerializer.DeserializeCompatible(_typeReq, data); if (_noArguments) { this._invoker.Invoke(this._instance, new object[] { client }); } else { this._invoker.Invoke(this._instance, new object[] { client, incoming }); } } else if (_typeReq == null) { return this._invoker.Invoke(this._instance, new object[] { client }); } else { var incoming = (_typeReq == typeof(byte[])) ? data : MessageSerializer.DeserializeCompatible(_typeReq, data); return this._invoker.Invoke(this._instance, new object[] { client, incoming }); } return null; } } private readonly Dictionary> _handlers = new Dictionary>(); private readonly Dictionary _requestors = new Dictionary(); #endregion Routing #region Invokation public void HandleMessage(Frame frame, ISocketClient client) { try { if (_handlers.ContainsKey(frame.Inbox)) { foreach (var handler in _handlers[frame.Inbox]) { try { handler.Invoke(frame.Payload, client); } catch (Exception ex) { Log.SystemError(ex, $"[ExRouter] Fault handle incomind message"); } } } } catch (Exception ex) { Log.SystemError(ex, $"[ExRouter] Fault handle incomind message"); } } public byte[] HandleRequest(Frame frame, ISocketClient client) { try { if (_requestors.ContainsKey(frame.Inbox)) { return MessageSerializer.SerializeCompatible(_requestors[frame.Inbox].Invoke(frame.Payload, client)); } else { Log.SystemWarning($"[ExRouter] Not found inbox '{frame.Inbox}' for incoming request"); } } catch (Exception ex) { Log.SystemError(ex, $"[ExRouter] Fault handle incomind request"); } return null; } #endregion Invokation public bool ContainsInbox(string inbox) { return _handlers.ContainsKey(inbox) || _requestors.ContainsKey(inbox); } public bool ContainsHandlerInbox(string inbox) { return _handlers.ContainsKey(inbox); } public bool ContainsRequestorInbox(string inbox) { return _requestors.ContainsKey(inbox); } #region Message handlers registration public IServer RegisterInbox(string inbox, MessageHandler handler) { if (false == _handlers.ContainsKey(inbox)) { _handlers.Add(inbox, new List()); } _handlers[inbox].Add(MRInvoker.Create(handler)); return this; } public IServer RegisterInbox(string inbox, MessageHandler handler) { if (false == _handlers.ContainsKey(inbox)) { _handlers.Add(inbox, new List()); } _handlers[inbox].Add(MRInvoker.Create(handler)); return this; } public IServer RegisterInbox(MessageHandler handler) { if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX)) { _handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List()); } _handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create(handler)); return this; } public IServer RegisterInbox(MessageHandler handler) { if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX)) { _handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List()); } _handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create(handler)); return this; } #endregion #region Request handlers registration public IServer RegisterInbox(string inbox, RequestHandler handler) { if (false == _requestors.ContainsKey(inbox)) { _requestors.Add(inbox, MRInvoker.Create(handler)); } else { throw new Exception($"[SocketExchangeServer] Inbox {inbox} already exists"); } return this; } public IServer RegisterInbox(string inbox, RequestHandler handler) { if (false == _requestors.ContainsKey(inbox)) { _requestors.Add(inbox, MRInvoker.Create(handler)); } else { throw new Exception($"[SocketExchangeServer] Inbox {inbox} already exists"); } return this; } public IServer RegisterInbox(RequestHandler handler) { if (false == _requestors.ContainsKey(BaseSocket.DEFAULT_REQUEST_INBOX)) { _requestors.Add(BaseSocket.DEFAULT_REQUEST_INBOX, MRInvoker.Create(handler)); } else { throw new Exception($"[SocketExchangeServer] Inbox {BaseSocket.DEFAULT_REQUEST_INBOX} already exists"); } return this; } public IServer RegisterInbox(RequestHandler handler) { if (false == _requestors.ContainsKey(BaseSocket.DEFAULT_REQUEST_INBOX)) { _requestors.Add(BaseSocket.DEFAULT_REQUEST_INBOX, MRInvoker.Create(handler)); } else { throw new Exception($"[SocketExchangeServer] Inbox {BaseSocket.DEFAULT_REQUEST_INBOX} already exists"); } return this; } #endregion } internal sealed class NullRouter : IRouter { public event Action OnDisconnect = _ => { }; public event Action OnConnect = _ => { }; public void HandleMessage(Frame frame, ISocketClient client) { } public byte[] HandleRequest(Frame frame, ISocketClient client) { return null; } public IServer RegisterInbox(string inbox, MessageHandler handler) { return this; } public IServer RegisterInbox(string inbox, MessageHandler handler) { return this; } public IServer RegisterInbox(MessageHandler handler) { return this; } public IServer RegisterInbox(MessageHandler handler) { return this; } public IServer RegisterInbox(string inbox, RequestHandler handler) { return this; } public IServer RegisterInbox(string inbox, RequestHandler handler) { return this; } public IServer RegisterInbox(RequestHandler handler) { return this; } public IServer RegisterInbox(RequestHandler handler) { return this; } public bool ContainsInbox(string inbox) => false; public bool ContainsHandlerInbox(string inbox) => false; public bool ContainsRequestorInbox(string inbox) => false; } }