using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using ZeroLevel.Network.SDL; using ZeroLevel.Services.Invokation; using ZeroLevel.Services.Serialization; namespace ZeroLevel.Network { public 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 void Invoke(byte[] data, ISocketClient client) { if (_typeResp == null!) { if (_noArguments) { this._invoker.Invoke(this._instance, new object[] { client }); } else { var incoming = (_typeReq == typeof(byte[])) ? data : MessageSerializer.DeserializeCompatible(_typeReq, data); this._invoker.Invoke(this._instance, new object[] { client, incoming }); } } } public void Invoke(byte[] data, ISocketClient client, Action callback) { if (_typeReq == null!) { callback(this._invoker.Invoke(this._instance, new object[] { client })); } else { var incoming = (_typeReq == typeof(byte[])) ? data : MessageSerializer.DeserializeCompatible(_typeReq, data); callback(this._invoker.Invoke(this._instance, new object[] { client, incoming })); } } public InboxServiceDescription GetDescription(string name) { return new InboxServiceDescription { Name = name, InboxKind = DetectKind(), Target = _instance?.GetType()?.Name!, IncomingType = GetIncomingTypeDescription(), OutcomingType = GetOutcomingTypeDescription() }; } private InboxType GetIncomingTypeDescription() { if (_typeReq == null!) return null!; return new InboxType { Name = _typeReq.FullName, Fields = _typeReq .GetMembers(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance) .Where(m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property) .Select(f => new KeyValuePair(f.Name, (f.MemberType == MemberTypes.Property) ? (f as PropertyInfo)!.PropertyType.FullName : (f as FieldInfo)!.FieldType.FullName)) .ToDictionary(pair => pair.Key, pair => pair.Value) }; } private InboxType GetOutcomingTypeDescription() { if (_typeResp == null!) return null!; return new InboxType { Name = _typeResp.FullName, Fields = _typeResp .GetMembers(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Instance) .Where(m => m.MemberType == MemberTypes.Field || m.MemberType == MemberTypes.Property) .Select(f => new KeyValuePair(f.Name, (f.MemberType == MemberTypes.Property) ? (f as PropertyInfo)!.PropertyType.FullName : (f as FieldInfo)!.FieldType.FullName)) .ToDictionary(pair => pair.Key, pair => pair.Value) }; } private InboxKind DetectKind() { if (_typeResp == null!) { return _noArguments ? InboxKind.HandlerNoArgs : InboxKind.Handler; } return _noArguments ? InboxKind.ReqeustorNoArgs : InboxKind.Reqeustor; } } private readonly Dictionary> _handlers = new Dictionary>(); private readonly Dictionary _requestors = new Dictionary(); #endregion Routing #region Invokation public void HandleMessage(Frame frame, ISocketClient client) { try { List invokers; if (_handlers.TryGetValue(frame.Inbox, out invokers)) { foreach (var invoker in invokers) { try { invoker.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 void HandleRequest(Frame frame, ISocketClient client, int identity, Action handler) { try { MRInvoker invoker; if (_requestors.TryGetValue(frame.Inbox, out invoker)) { invoker.Invoke(frame.Payload, client , result => { handler(identity, MessageSerializer.SerializeCompatible(result)); }); } else { Log.SystemWarning($"[ExRouter] Not found inbox '{frame.Inbox}' for incoming request"); } } catch (Exception ex) { Log.SystemError(ex, $"[ExRouter] Fault handle incomind request"); } } #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; } public IServer RegisterInboxIfNoExists(string inbox, MessageHandler handler) { if (false == _handlers.ContainsKey(inbox)) { _handlers.Add(inbox, new List()); _handlers[inbox].Add(MRInvoker.Create(handler)); } return this; } public IServer RegisterInboxIfNoExists(string inbox, MessageHandler handler) { if (false == _handlers.ContainsKey(inbox)) { _handlers.Add(inbox, new List()); _handlers[inbox].Add(MRInvoker.Create(handler)); } return this; } public IServer RegisterInboxIfNoExists(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 RegisterInboxIfNoExists(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 public IEnumerable CollectInboxInfo() { var inboxes = new List(); foreach (var handlers in _handlers) { foreach (var handler in handlers.Value) { inboxes.Add(handler.GetDescription(handlers.Key)); } } foreach (var requestor in _requestors) { inboxes.Add(requestor.Value.GetDescription(requestor.Key)); } return inboxes; } } internal sealed class NullRouter : IRouter { public event Action OnDisconnect = _ => { }; public event Action OnConnect = _ => { }; public void HandleMessage(Frame frame, ISocketClient client) { } public void HandleRequest(Frame frame, ISocketClient client, int identity, Action handler) { } 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 RegisterInboxIfNoExists(string inbox, MessageHandler handler) { return this; } public IServer RegisterInboxIfNoExists(string inbox, MessageHandler handler) { return this; } public IServer RegisterInboxIfNoExists(MessageHandler handler) { return this; } public IServer RegisterInboxIfNoExists(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; public IEnumerable CollectInboxInfo() => Enumerable.Empty(); } }