private bool Reconnect(string handle, HoxisProtocolArgs args)
        {
            long uid = FF.StringToLong(args["uid"]);
            List <HoxisConnection> workers = HoxisServer.Ins.GetWorkingConnections();

            foreach (HoxisConnection w in workers)
            {
                // If already signed in, response the state to let user choose if reconnecting
                if (w.user == this)
                {
                    continue;
                }
                if (w.user.userID <= 0)
                {
                    continue;
                }
                if (w.user.userID == uid)
                {
                    userID       = w.user.userID;
                    realtimeData = w.user.realtimeData;
                    Continue();
                    if (DebugRecorder.LogEnable(_logger))
                    {
                        _logger.LogInfo("reconnect", "");
                    }
                    HoxisServer.Ins.AffairEntry(C.AFFAIR_RELEASE_CONNECTION, w);
                    return(ResponseSuccess(handle, "ReconnectCb"));
                }
            }
            return(Response(handle, "ReconnectCb", new KVString("code", C.RESP_NO_USER_INFO)));
        }
Example #2
0
        /// <summary>
        /// **WITHIN THREAD**
        /// The entrance of protocol bytes
        /// Called by HoxisClient
        /// </summary>
        /// <param name="data"></param>
        public void ProtocolEntry(byte[] data)
        {
            string        json  = FF.BytesToString(data);
            HoxisProtocol proto = FF.JsonToObject <HoxisProtocol>(json);

            _protoQueue.Enqueue(proto);
        }
        /// <summary>
        /// Fill this HoxisUser with an connected user
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool SignIn(string handle, HoxisProtocolArgs args)
        {
            Ret  ret;
            long uid = FF.StringToLong(args["uid"]);

            if (uid <= 0)
            {
                return(ResponseError(handle, C.RESP_ILLEGAL_ARGUMENT, FF.StringFormat("illegal argument: {0}", args["uid"])));
            }
            userID          = uid;
            connectionState = UserConnectionState.Default;
            if (DebugRecorder.LogEnable(_logger))
            {
                _logger.LogInfo("sign in", "");
            }
            else
            {
                _logger = new DebugRecorder(FF.StringAppend(HoxisServer.basicPath, @"logs\users\", NewUserLogName(uid)), out ret);
                if (ret.code != 0)
                {
                    Console.WriteLine(ret.desc);
                }
                else
                {
                    _logger.Begin();
                    _logger.LogInfo("sign in", "");
                }
            }
            return(ResponseSuccess(handle, "SignInCb"));
        }
        /// <summary>
        /// Post a protocol to client
        /// </summary>
        /// <param name="proto"></param>
        public void ProtocolPost(HoxisProtocol proto)
        {
            string json = FF.ObjectToJson(proto);

            byte[] data = FF.StringToBytes(json);
            OnPost(data);
        }
Example #5
0
        private void ProcessProtocol(object state)
        {
            HoxisProtocol proto = (HoxisProtocol)state;

            OnProtocolEntry(proto);
            switch (proto.type)
            {
            case ProtocolType.Response:
                ReqHandle handle = FF.JsonToObject <ReqHandle>(proto.handle);
                // todo 消除等待
                if (proto.err != C.RESP_SUCCESS)
                {
                    OnResponseError(proto.err, proto.desc); return;
                }
                respCbTable[proto.action.method](proto.action.args);

                break;

            case ProtocolType.Synchronization:
                HoxisAgent agent = GetAgent(proto.sender.aid);
                if (agent != null)
                {
                    agent.CallBehaviour(proto.action);
                }
                break;

            case ProtocolType.Proclamation:

                break;
            }
        }
Example #6
0
        public void SendProtocol()
        {
            Dictionary <string, string> args = new Dictionary <string, string>();

            foreach (KVString kv in arguments)
            {
                args.Add(kv.key, kv.val);
            }
            HoxisProtocol proto = new HoxisProtocol
            {
                type   = protocolType,
                handle = FF.ObjectToJson(new ReqHandle {
                    req = method, ts = SF.GetTimeStamp(TimeUnit.Millisecond)
                }),
                err      = error,
                receiver = new HoxisProtocolReceiver {
                    type = receiverType, uid = receiverUID
                },
                sender = new HoxisProtocolSender {
                    uid = senderUID, aid = senderAgentID, loopback = loopback
                },
                action = new HoxisProtocolAction(method, new HoxisProtocolArgs(args)),
                desc   = description
            };

            HoxisDirector.Ins.ProtocolPost(proto);
        }
        public HoxisServer(string projectArg, string versionArg, bool autoStart = false)
        {
            if (Ins == null)
            {
                Ins = this;
            }

            Ret ret;

            project = projectArg;
            version = versionArg;

            // Init and begin log recording
            _logger = new DebugRecorder(FF.StringAppend(basicPath, @"logs\server.log"), out ret);
            if (ret.code != 0)
            {
                Quit();
            }
            _logger.Begin();
            _logger.LogTitle("David.Claude", project, version);

            // Auto start
            if (autoStart)
            {
                InitializeConfig(out ret);
                if (ret.code != 0)
                {
                    Quit();
                }
                Listen();
                BeginAccept();
                BeginProcess();
                BeginHeartbeatUpdate();
            }
        }
 /// <summary>
 /// Get config of long type
 /// </summary>
 /// <param name="section"></param>
 /// <param name="key"></param>
 /// <param name="ret"></param>
 /// <returns></returns>
 public long GetLong(string section, string key, out Ret ret)
 {
     if (!ContainItem(section, key, out ret))
     {
         return(0);
     }
     return(FF.StringToLong(_config[section][key], out ret));
 }
 /// <summary>
 /// Get config of float type
 /// </summary>
 /// <returns>The float.</returns>
 /// <param name="section">Section.</param>
 /// <param name="key">Key.</param>
 /// <param name="ret">Ret.</param>
 public float GetFloat(string section, string key, out Ret ret)
 {
     if (!ContainItem(section, key, out ret))
     {
         return(0f);
     }
     return(FF.StringToFloat(_config[section][key], out ret));
 }
 /// <summary>
 /// Get config of bool type
 /// </summary>
 /// <returns><c>true</c>, if bool was gotten, <c>false</c> otherwise.</returns>
 /// <param name="section">Section.</param>
 /// <param name="key">Key.</param>
 /// <param name="ret">Ret.</param>
 public bool GetBool(string section, string key, out Ret ret)
 {
     if (!ContainItem(section, key, out ret))
     {
         return(false);
     }
     return(FF.StringToBool(_config[section][key], out ret));
 }
 /// <summary>
 /// Get config of short type
 /// </summary>
 /// <param name="section"></param>
 /// <param name="key"></param>
 /// <param name="ret"></param>
 /// <returns></returns>
 public short GetShort(string section, string key, out Ret ret)
 {
     if (!ContainItem(section, key, out ret))
     {
         return(0);
     }
     return(FF.StringToShort(_config[section][key], out ret));
 }
        /// <summary>
        /// Read the .toml file into _config
        /// </summary>
        /// <param name="path"></param>
        /// <param name="ret"></param>
        public void ReadFile(string path, out Ret ret)
        {
            _config = new Dictionary <string, Dictionary <string, string> >();
            // Is toml file ?
            string[] paths = FF.StringSplit(path, '/');
            string[] name  = FF.StringSplit(FF.LastOfArray(paths), '.');
            if (FF.LastOfArray(name) != "toml")
            {
                ret = new Ret(LogLevel.Error, RET_NOT_TOML, "File:" + path + " isn't .toml");
                return;
            }
            // Does file exist ?
            if (!File.Exists(path))
            {
                ret = new Ret(LogLevel.Error, RET_NO_FILE, "File:" + path + " doesn't exist");
                return;
            }
            // Push toml to config
            string curSec = "";

            string[] lines = File.ReadAllLines(path);
            foreach (string line in lines)
            {
                string lineTrim = line.Trim();
                if (FF.RegexMatch(lineTrim, @"^#.*"))
                {
                    continue;
                }
                string[] vals = FF.RegexGetValue(lineTrim, @"^\[.+\]$", "[", "]");
                if (vals != null)
                {
                    if (vals.Length == 1)
                    {
                        string section = vals[0];
                        if (!_config.ContainsKey(section))
                        {
                            _config.Add(section, new Dictionary <string, string>());
                        }
                        curSec = section;
                        continue;
                    }
                }
                if (curSec == "")
                {
                    continue;
                }
                string[] kv = lineTrim.Split('=');
                if (kv.Length != 2)
                {
                    continue;
                }
                _config[curSec].Add(kv[0].Trim(), kv[1].Trim());
            }
            ret = Ret.ok;
        }
 private bool SetDefaultConnectionState(string handle, HoxisProtocolArgs args)
 {
     if (connectionState == UserConnectionState.Active)
     {
         connectionState = UserConnectionState.Default;
         return(ResponseSuccess(handle, "SetDefaultConnectionStateCb"));
     }
     else if (connectionState == UserConnectionState.Default)
     {
         return(Response(handle, "SetDefaultConnectionStateCb", new KVString("code", C.RESP_SET_DEFAULT_ALREADY)));
     }
     return(ResponseError(handle, C.RESP_SET_STATE_UNABLE, FF.StringFormat("current connection state is {0}", connectionState.ToString())));
 }
Example #14
0
        // Use this for initialization
        void Start()
        {
            HoxisDirector.Ins.onResponseError        += (err, desc) => { LogAffairEntry(FF.StringFormat("response err: {0}, {1}", err, desc), LogLevel.Error); };
            HoxisDirector.Ins.onProtocolEntry        += (proto) => { LogAffairEntry(FF.StringFormat("protocol entry: {0}", FF.ObjectToJson(proto))); };
            HoxisDirector.Ins.onProtocolPost         += (proto) => { LogAffairEntry(FF.StringFormat("protocol post: {0}", FF.ObjectToJson(proto))); };
            HoxisDirector.Ins.onAffairInitError      += (ret) => { LogAffairEntry(ret.desc, LogLevel.Error); };
            HoxisDirector.Ins.onAffairConnected      += () => { LogAffairEntry(FF.StringFormat("connect to {0}", HoxisClient.Ins.serverIP)); };
            HoxisDirector.Ins.onAffairConnectError   += (ret) => { LogAffairEntry(ret.desc, LogLevel.Error); };
            HoxisDirector.Ins.onAffairClosed         += () => { LogAffairEntry("close success"); };
            HoxisDirector.Ins.onAffairClosedError    += (ret) => { LogAffairEntry(ret.desc, LogLevel.Error); };
            HoxisDirector.Ins.onAffairNetworkAnomaly += (ret) => { LogAffairEntry(ret.desc, LogLevel.Error); };

            _logPanel.GetComponent <RectTransform>().localPosition = _logPanelOffPosition;
            _logPanelOn = false;

            HoxisDirector.Ins.AwakeIns();
        }
        //public static void TestRelease(HoxisConnection conn) { Ret ret; lock (conn) _connReception.Release(conn, out ret); }

        #region management

        //public static bool ManageCluster(ManageOperation op, HoxisUser sponsor)
        //{
        //    switch (op)
        //    {
        //        case ManageOperation.Create:
        //            string cid = FF.StringAppend(sponsor.userID.ToString(), "@", SF.GetTimeStamp().ToString());
        //            if (_clusters.ContainsKey(cid)) { Console.WriteLine("[error]Create cluster: cluster {0} already exists", cid); return false; }
        //            lock (_clusters)
        //            {
        //                HoxisCluster hc = new HoxisCluster(cid);
        //                _clusters.Add(cid, hc);
        //                Ret ret;
        //                hc.UserJoin(sponsor, out ret);
        //                if (ret.code != 0) { Console.WriteLine("[warning]Create cluster: {0}", ret.desc); return false; }
        //            }
        //            break;
        //        case ManageOperation.Join:
        //            // todo Call matching sdk, get a cluster
        //            break;
        //        case ManageOperation.Leave:

        //            break;
        //        case ManageOperation.Destroy:

        //            break;
        //    }
        //    return true;
        //}

        #endregion

        private void ProcessAffair(object state)
        {
            KV <int, object> affair = (KV <int, object>)state;

            switch (affair.key)
            {
            case C.AFFAIR_RELEASE_CONNECTION:
                Ret             ret;
                HoxisConnection conn = (HoxisConnection)affair.val;
                lock (conn) { _connReception.Release(conn, out ret); }
                if (ret.code != 0)
                {
                    _logger.LogWarning(ret.desc, "Affair"); return;
                }
                break;
            }
            _logger.LogInfo(FF.StringFormat("{0} processed", affair.key), "Affair", true);
        }
Example #16
0
        public void LogTag(string content, string tag = "", string speaker = "", bool console = false)
        {
            string s;

            if (speaker == "")
            {
                s = FF.StringFormat("[{0}]{1}:  {2}", SF.GetDateTime(), tag, content);
            }
            else
            {
                s = FF.StringFormat("[{0}]{1}:  {2}--->{3}", SF.GetDateTime(), tag, speaker, content);
            }
            _writer.WriteLine(s);
            if (console)
            {
                Console.WriteLine(s);
            }
        }
Example #17
0
        /// <summary>
        /// Rapidly send a request protocol
        /// </summary>
        /// <param name="method"></param>
        /// <param name="kvs"></param>
        public void Request(string method, params KVString[] kvs)
        {
            HoxisProtocol proto = new HoxisProtocol
            {
                type   = ProtocolType.Request,
                handle = FF.ObjectToJson(new ReqHandle {
                    req = method, ts = SF.GetTimeStamp(TimeUnit.Millisecond)
                }),
                err      = "",
                receiver = HoxisProtocolReceiver.undef,
                sender   = HoxisProtocolSender.undef,
                action   = new HoxisProtocolAction(method, kvs),
                desc     = ""
            };

            ProtocolPost(proto);
            // todo wait for response
        }
        public void Continue()
        {
            Ret ret;

            connectionState = UserConnectionState.Active;
            if (!DebugRecorder.LogEnable(_logger))
            {
                _logger = new DebugRecorder(FF.StringAppend(HoxisServer.basicPath, @"logs\users\", NewUserLogName(userID)), out ret);
                if (ret.code != 0)
                {
                    Console.WriteLine(ret.desc);
                }
                else
                {
                    _logger.Begin();
                }
            }
        }
 /// <summary>
 /// Begin accepting socket connection within thread
 /// </summary>
 public void BeginAccept()
 {
     _acceptThread = new Thread(() =>
     {
         while (true)
         {
             Socket socket = _socket.Accept();
             _logger.LogInfo(FF.StringAppend("accept new client: ", socket.RemoteEndPoint.ToString()), "Server", true);
             Ret ret;
             HoxisConnection conn = _connReception.Request(socket, out ret);
             if (ret.code != 0)
             {
                 _logger.LogWarning(ret.desc, socket.RemoteEndPoint.ToString()); continue;
             }
             _logger.LogInfo("request successful", conn.clientIP);
         }
     });
     _acceptThread.Start();
     _logger.LogInfo("accept begin...", "Server", true);
 }
        /// <summary>
        /// Get the connection state if this user has already signed in
        /// </summary>
        /// <param name="handle"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        private bool QueryConnectionState(string handle, HoxisProtocolArgs args)
        {
            long uid = FF.StringToLong(args["uid"]);

            if (uid <= 0)
            {
                return(ResponseError(handle, C.RESP_ILLEGAL_ARGUMENT, FF.StringFormat("illegal argument: {0}", args["uid"])));
            }
            HoxisUser user = HoxisServer.Ins.GetUser(uid);

            if (user == null)
            {
                return(Response(handle, "QueryConnectionStateCb", new KVString("code", C.RESP_NO_USER_INFO)));
            }
            if (user == this)
            {
                return(Response(handle, "QueryConnectionStateCb", new KVString("code", C.RESP_NO_USER_INFO)));
            }
            return(ResponseSuccess(handle, "QueryConnectionStateCb", new KVString("state", user.connectionState.ToString())));
        }
        /// <summary>
        /// Check the request name and time stamp
        /// </summary>
        /// <param name="proto"></param>
        /// <param name="ret"></param>
        public void CheckRequest(HoxisProtocol proto, out Ret ret)
        {
            ReqHandle handle = FF.JsonToObject <ReqHandle>(proto.handle, out ret);

            if (ret.code != 0)
            {
                return;
            }
            // Check if request name matches method name
            if (handle.req != proto.action.method)
            {
                ret = new Ret(LogLevel.Info, 1, "request name doesn't match method name"); return;
            }
            // Check if expired
            long ts   = handle.ts;
            long intv = Math.Abs(SF.GetTimeStamp(TimeUnit.Millisecond) - ts);

            if (intv > requestTTL)
            {
                ret = new Ret(LogLevel.Info, 1, "request is expired"); return;
            }
            ret = Ret.ok;
        }
 /// <summary>
 /// New log name of an user
 /// </summary>
 /// <param name="uid"></param>
 /// <returns></returns>
 public static string NewUserLogName(long uid)
 {
     return(FF.StringAppend(uid.ToString(), "@", SF.GetTimeStamp().ToString(), ".log"));
 }
        /// <summary>
        /// **WITHIN THREAD**
        /// The entrance of protocol bytes
        /// </summary>
        /// <param name="data"></param>
        public void ProtocolEntry(byte[] data)
        {
            string        json  = FF.BytesToString(data);
            HoxisProtocol proto = FF.JsonToObject <HoxisProtocol>(json);

            switch (proto.type)
            {
            case ProtocolType.Synchronization:
                switch (proto.receiver.type)
                {
                case ReceiverType.Cluster:
                    if (realtimeData.parentCluster == null)
                    {
                        return;
                    }
                    realtimeData.parentCluster.ProtocolBroadcast(proto);
                    break;

                case ReceiverType.Team:
                    if (realtimeData.parentTeam == null)
                    {
                        return;
                    }
                    realtimeData.parentTeam.ProtocolBroadcast(proto);
                    break;

                case ReceiverType.User:
                    HoxisUser user = HoxisServer.Ins.GetUser(proto.receiver.uid);
                    // todo send
                    break;
                }
                break;

            case ProtocolType.Request:
                // Request check
                Ret ret;
                CheckRequest(proto, out ret);
                if (ret.code != 0)
                {
                    ResponseError(proto.handle, C.RESP_CHECK_FAILED, ret.desc);
                    return;
                }
                // Check ok
                if (!respTable.ContainsKey(proto.action.method))
                {
                    if (DebugRecorder.LogEnable(_logger))
                    {
                        _logger.LogError(FF.StringFormat("invalid request: {0}", proto.action.method), "", true);
                    }
                    ResponseError(proto.handle, C.RESP_CHECK_FAILED, FF.StringFormat("invalid request: {0}", proto.action.method));
                    return;
                }
                respTable[proto.action.method](proto.handle, proto.action.args);
                break;

            default:
                if (DebugRecorder.LogEnable(_logger))
                {
                    _logger.LogError(FF.StringFormat("invalid protocol type: {0}", proto.type), "");
                }
                break;
            }
        }
        /// <summary>
        /// Init the configuration, such as the ip, port, socket and arguments
        /// </summary>
        /// <param name="configPath"></param>
        public void InitializeConfig(out Ret ret, string configPath = "")
        {
            // Init config
            string path;

            if (configPath != "")
            {
                path = configPath;
            }
            else
            {
                path = FF.StringAppend(basicPath, @"..\..\DacLib\Hoxis\Configs\hoxis_server.toml");
            }
            config = new TomlConfiguration(path, out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server", true); return;
            }
            _logger.LogInfo("read configuration success", "Server");

            // Assign ip, port and init the sokcet
            localIP = SF.GetLocalIP(out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            port = config.GetInt("server", "port", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("ip is {0}, port is {1}", localIP, port.ToString()), "Server");

            // Init connection reception
            maxConn = config.GetInt("server", "max_conn", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _connReception = new CriticalPreformPool <HoxisConnection>(maxConn);
            _logger.LogInfo(FF.StringFormat("max connections is {0}", maxConn), "Server");

            // Init affair queue
            affairQueueCapacity = config.GetInt("server", "affair_queue_capacity", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("affair queue capacity is {0}", affairQueueCapacity), "Server");
            affairQueueProcessQuantity = config.GetShort("server", "affair_queue_process_quantity", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("affair queue process quantity is {0}", affairQueueProcessQuantity), "Server");
            _affairQueue               = new FiniteProcessQueue <KV <int, object> >(affairQueueCapacity, affairQueueProcessQuantity);
            _affairQueue.onProcess    += ProcessAffair;
            affairQueueProcessInterval = config.GetInt("server", "affair_queue_process_interval", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("affair queue process interval is {0}ms", affairQueueProcessInterval), "Server");

            // Init heartbeat update
            heartbeatUpdateInterval = config.GetInt("server", "heartbeat_update_interval", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("heartbeat update interval is {0}ms", heartbeatUpdateInterval), "Server");

            // Init connection
            HoxisConnection.readBufferSize = config.GetInt("conn", "read_buffer_size", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("read buffer size of connection is {0}", HoxisConnection.readBufferSize), "Server");

            // Init cluster
            _clusters            = new Dictionary <string, HoxisCluster>();
            HoxisCluster.maxUser = config.GetInt("cluster", "max_user", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("max users of cluster is {0}", HoxisCluster.maxUser), "Server");

            // Init team
            HoxisTeam.maxUser = config.GetInt("team", "max_user", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("max users of team is {0}", HoxisTeam.maxUser), "Server");

            // Init user
            HoxisUser.requestTTL = config.GetLong("user", "request_ttl", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("request time to live is {0}ms", HoxisUser.requestTTL), "Server");
            HoxisUser.heartbeatTimeout = config.GetInt("user", "heartbeat_timeout", out ret);
            if (ret.code != 0)
            {
                _logger.LogFatal(ret.desc, "Server"); return;
            }
            _logger.LogInfo(FF.StringFormat("heartbeat timeout is {0}ms", HoxisUser.heartbeatTimeout), "Server");

            _logger.LogInfo("init success", "Server", true);
        }