You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Zero/ZeroLevel/Services/Network/Utils/Router.cs

436 lines
17 KiB

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<ISocketClient> OnDisconnect = _ => { }; // must be never rised
public event Action<IClient> OnConnect = _ => { }; // must be never rised
#region Routing
private sealed class MRInvoker
{
/// <summary>
/// Creates a compiled expression for a quick method call, returns the identifier of the expression and a delegate for the call.
/// </summary>
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<Invoker>(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<T>(MessageHandler<T> handler)
{
return new MRInvoker
{
_typeReq = typeof(T),
_typeResp = null!,
_instance = handler.Target,
_invoker = CreateCompiledExpression(handler)
};
}
public static MRInvoker Create<Tresponse>(RequestHandler<Tresponse> handler)
{
return new MRInvoker
{
_noArguments = true,
_typeReq = null!,
_typeResp = typeof(Tresponse),
_instance = handler.Target,
_invoker = CreateCompiledExpression(handler)
};
}
public static MRInvoker Create<Trequest, Tresponse>(RequestHandler<Trequest, Tresponse> 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<object> 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<string, string>(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<string, string>(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<string, List<MRInvoker>> _handlers =
new Dictionary<string, List<MRInvoker>>();
private readonly Dictionary<string, MRInvoker> _requestors =
new Dictionary<string, MRInvoker>();
#endregion Routing
#region Invokation
public void HandleMessage(Frame frame, ISocketClient client)
{
try
{
List<MRInvoker> 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<int, byte[]> 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<MRInvoker>());
}
_handlers[inbox].Add(MRInvoker.Create(handler));
return this;
}
public IServer RegisterInbox<T>(string inbox, MessageHandler<T> handler)
{
if (false == _handlers.ContainsKey(inbox))
{
_handlers.Add(inbox, new List<MRInvoker>());
}
_handlers[inbox].Add(MRInvoker.Create<T>(handler));
return this;
}
public IServer RegisterInbox(MessageHandler handler)
{
if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX))
{
_handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List<MRInvoker>());
}
_handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create(handler));
return this;
}
public IServer RegisterInbox<T>(MessageHandler<T> handler)
{
if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX))
{
_handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List<MRInvoker>());
}
_handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create<T>(handler));
return this;
}
public IServer RegisterInboxIfNoExists(string inbox, MessageHandler handler)
{
if (false == _handlers.ContainsKey(inbox))
{
_handlers.Add(inbox, new List<MRInvoker>());
_handlers[inbox].Add(MRInvoker.Create(handler));
}
return this;
}
public IServer RegisterInboxIfNoExists<T>(string inbox, MessageHandler<T> handler)
{
if (false == _handlers.ContainsKey(inbox))
{
_handlers.Add(inbox, new List<MRInvoker>());
_handlers[inbox].Add(MRInvoker.Create<T>(handler));
}
return this;
}
public IServer RegisterInboxIfNoExists(MessageHandler handler)
{
if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX))
{
_handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List<MRInvoker>());
_handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create(handler));
}
return this;
}
public IServer RegisterInboxIfNoExists<T>(MessageHandler<T> handler)
{
if (false == _handlers.ContainsKey(BaseSocket.DEFAULT_MESSAGE_INBOX))
{
_handlers.Add(BaseSocket.DEFAULT_MESSAGE_INBOX, new List<MRInvoker>());
_handlers[BaseSocket.DEFAULT_MESSAGE_INBOX].Add(MRInvoker.Create<T>(handler));
}
return this;
}
#endregion
#region Request handlers registration
public IServer RegisterInbox<Tresponse>(string inbox, RequestHandler<Tresponse> handler)
{
if (false == _requestors.ContainsKey(inbox))
{
_requestors.Add(inbox, MRInvoker.Create<Tresponse>(handler));
}
else
{
throw new Exception($"[SocketExchangeServer] Inbox {inbox} already exists");
}
return this;
}
public IServer RegisterInbox<Trequest, Tresponse>(string inbox, RequestHandler<Trequest, Tresponse> handler)
{
if (false == _requestors.ContainsKey(inbox))
{
_requestors.Add(inbox, MRInvoker.Create<Trequest, Tresponse>(handler));
}
else
{
throw new Exception($"[SocketExchangeServer] Inbox {inbox} already exists");
}
return this;
}
public IServer RegisterInbox<Tresponse>(RequestHandler<Tresponse> handler)
{
if (false == _requestors.ContainsKey(BaseSocket.DEFAULT_REQUEST_INBOX))
{
_requestors.Add(BaseSocket.DEFAULT_REQUEST_INBOX, MRInvoker.Create<Tresponse>(handler));
}
else
{
throw new Exception($"[SocketExchangeServer] Inbox {BaseSocket.DEFAULT_REQUEST_INBOX} already exists");
}
return this;
}
public IServer RegisterInbox<Trequest, Tresponse>(RequestHandler<Trequest, Tresponse> handler)
{
if (false == _requestors.ContainsKey(BaseSocket.DEFAULT_REQUEST_INBOX))
{
_requestors.Add(BaseSocket.DEFAULT_REQUEST_INBOX, MRInvoker.Create<Trequest, Tresponse>(handler));
}
else
{
throw new Exception($"[SocketExchangeServer] Inbox {BaseSocket.DEFAULT_REQUEST_INBOX} already exists");
}
return this;
}
#endregion
public IEnumerable<InboxServiceDescription> CollectInboxInfo()
{
var inboxes = new List<InboxServiceDescription>();
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<ISocketClient> OnDisconnect = _ => { };
public event Action<IClient> OnConnect = _ => { };
public void HandleMessage(Frame frame, ISocketClient client) { }
public void HandleRequest(Frame frame, ISocketClient client, int identity, Action<int, byte[]> handler) { }
public IServer RegisterInbox(string inbox, MessageHandler handler) { return this; }
public IServer RegisterInbox<T>(string inbox, MessageHandler<T> handler) { return this; }
public IServer RegisterInbox(MessageHandler handler) { return this; }
public IServer RegisterInbox<T>(MessageHandler<T> handler) { return this; }
public IServer RegisterInboxIfNoExists(string inbox, MessageHandler handler) { return this; }
public IServer RegisterInboxIfNoExists<T>(string inbox, MessageHandler<T> handler) { return this; }
public IServer RegisterInboxIfNoExists(MessageHandler handler) { return this; }
public IServer RegisterInboxIfNoExists<T>(MessageHandler<T> handler) { return this; }
public IServer RegisterInbox<Tresponse>(string inbox, RequestHandler<Tresponse> handler) { return this; }
public IServer RegisterInbox<Trequest, Tresponse>(string inbox, RequestHandler<Trequest, Tresponse> handler) { return this; }
public IServer RegisterInbox<Tresponse>(RequestHandler<Tresponse> handler) { return this; }
public IServer RegisterInbox<Trequest, Tresponse>(RequestHandler<Trequest, Tresponse> handler) { return this; }
public bool ContainsInbox(string inbox) => false;
public bool ContainsHandlerInbox(string inbox) => false;
public bool ContainsRequestorInbox(string inbox) => false;
public IEnumerable<InboxServiceDescription> CollectInboxInfo() => Enumerable.Empty<InboxServiceDescription>();
}
}

Powered by TurnKey Linux.