| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 | using System.Collections.Concurrent;using InABox.Core;namespace InABox.Rpc{    public abstract class RpcServerTransport<TConnection> : IPusher, IRpcServerTransport where TConnection : notnull    {        public abstract bool IsSecure();                private ConcurrentDictionary<TConnection, RpcServerSession> _sessions = new ConcurrentDictionary<TConnection, RpcServerSession>();        protected RpcServerSession CreateSession(TConnection connection)        {            var result = new RpcServerSession();            _sessions[connection] = result;            return result;        }        public RpcServerSession? GetSession(TConnection? connection)        {            if (connection == null)                return null;            _sessions.TryGetValue(connection, out RpcServerSession? result);            return result;        }        protected RpcServerSession? DeleteSession(TConnection connection)        {            _sessions.Remove(connection, out RpcServerSession? session);            return session;        }                private Dictionary<string, IRpcCommandHandler> _handlers = new Dictionary<string, IRpcCommandHandler>();        public void AddHandler<TSender, TCommand, TProperties, TResult>(RpcCommandHandler<TSender, TCommand, TProperties, TResult> handler)            where TSender : class            where TCommand : IRpcCommand<TProperties, TResult>            where TProperties : IRpcCommandParameters, new()            where TResult : IRpcCommandResult, new()        {            _handlers[typeof(TCommand).Name] = handler;        }                public abstract void Start();        public abstract void Stop();                public event RpcTransportOpenEvent? OnOpen;        protected void DoOpen(TConnection connection)        {            var session = CreateSession(connection);            OnOpen?.Invoke(this, new RpcTransportOpenArgs(session) );        }        public event RpcTransportCloseEvent? OnClose;        protected void DoClose(TConnection connection, RpcTransportCloseEventType type)        {            var session = DeleteSession(connection);            OnClose?.Invoke(this, new RpcTransportCloseArgs(session, type));        }        public event RpcTransportExceptionEvent? OnException;        protected void DoException(TConnection? connection, Exception e)        {            var session = GetSession(connection);            OnException?.Invoke(this, new RpcTransportExceptionArgs(session, e));        }        public event RpcTransportMessageEvent? BeforeMessage;        protected void DoBeforeMessage(RpcServerSession? session, RpcMessage? message)        {            BeforeMessage?.Invoke(this, new RpcTransportMessageArgs(session,message));        }        public event RpcTransportMessageEvent? AfterMessage;        protected void DoAfterMessage(RpcServerSession? session, RpcMessage? message)        {            AfterMessage?.Invoke(this, new RpcTransportMessageArgs(session,message));        }                /// <summary>        /// Handle a message from a client.        /// </summary>        /// <param name="connection">The client connection.</param>        /// <param name="message">The message to be handled.</param>        /// <returns>The response to be sent back to the client.</returns>        public RpcMessage? DoMessage(TConnection? connection, RpcMessage? message)        {            if(message is null)            {                DoException(connection, new Exception("NULL Message Received"));                return null;            }            var response = new RpcMessage() { Id = message.Id, Command = message.Command };            try            {                var session = GetSession(connection);                DoBeforeMessage(session, message);                if (session != null)                {                    response = new RpcMessage() { Id = message.Id, Command = message.Command };                    if (_handlers.TryGetValue(message.Command, out var command))                    {                        try                        {                            response.Payload = command.Execute(session, message.Payload);                        }                        catch (RpcException err)                        {                            response.Error = err.Error;                        }                    }                    else                    {                        DoException(connection, new Exception("Command Not Found"));                        response.Error = RpcError.COMMANDNOTFOUND;                    }                    DoAfterMessage(session, response);                }                else                {                    DoException(connection, new Exception("Session not Found"));                    response.Error = RpcError.SESSIONNOTFOUND;                }            }            catch(Exception e)            {                DoException(connection, e);                response.Error = RpcError.SERVERERROR;            }            return response;        }        /// <summary>        /// Send a message to a particular client connection.        /// </summary>        /// <param name="connection">The connection to send to.</param>        /// <param name="message">The message to send.</param>        public abstract void Send(TConnection connection, RpcMessage message);        #region Pusher Stuff        public void PushToAll<TPush>(TPush push) where TPush : BaseObject        {            var message = new RpcMessage(Guid.NewGuid(), "Push", RpcPush.Create(push).WriteBinary(BinarySerializationSettings.Latest));            foreach (var connection in _sessions.Keys)            {                Send(connection, message);            }        }        public void PushToSession<TPush>(Guid session, TPush push) where TPush : BaseObject        {            var message = new RpcMessage(Guid.NewGuid(), "Push", RpcPush.Create(push).WriteBinary(BinarySerializationSettings.Latest));            var sessionConnection = _sessions.FirstOrDefault(x => x.Value.ID == session).Key;            if(sessionConnection is not null)            {                Send(sessionConnection, message);            }        }        public void PushToSession(Guid session, Type TPush, BaseObject push)        {            var message = new RpcMessage(Guid.NewGuid(), "Push", new RpcPush            {                Object = push,                Type = TPush            }.WriteBinary(BinarySerializationSettings.Latest));            var sessionConnection = _sessions.FirstOrDefault(x => x.Value.ID == session).Key;            if (sessionConnection is not null)            {                Send(sessionConnection, message);            }        }        public IEnumerable<Guid> GetUserSessions(Guid user) =>            _sessions.Values.Where(x => x.UserGuid == user).Select(x => x.ID);        public IEnumerable<Guid> GetSessions(Platform platform) =>            _sessions.Values.Where(x => x.Platform == platform).Select(x => x.ID);        #endregion    }}
 |