public void Pipe_DataReceived(PipeConnection connection, int count)
        {
            try
            {
                var req            = RequestBase.Parser.ParseFrom(connection.Buffer, 0, count);
                var resp           = ResponseBase(true);
                var blockSensitive = connection is RemotePipeConnection;

                switch (req.Type)
                {
                case MessageID.UserLogin:
                {
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    var result = Login(req.DataUserLogin.Token).WaitResult();
                    if (result != null)
                    {
                        connection.RespondFailure(result);
                        return;
                    }
                }
                break;

                case MessageID.UserLogout:
                {
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    var result = Logout();
                    if (result != null)
                    {
                        connection.RespondFailure(result);
                        return;
                    }
                }
                break;

                case MessageID.UserInfo:
                    lock (UserInfo)
                    {
                        if (AutoLogin)
                        {
                            resp.DataUser        = UserInfo.Clone();
                            resp.DataUser.Status = UserStatus.Pending;
                        }
                        else
                        {
                            resp.DataUser = UserInfo;
                        }
                    }
                    break;

                case MessageID.LogGet:
                    resp.DataLog = new LogList();
                    lock (LogManager)
                    {
                        resp.DataLog.Data.Add(LogManager);
                    }
                    break;

                case MessageID.LogClear:
                    LogManager.Clear();
                    break;

                case MessageID.ControlExit:
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    Stop();
                    return;

                case MessageID.ControlConfigGet:
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    resp.DataConfig = GetConfig();
                    break;

                case MessageID.ControlConfigSet:
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    if (req.DataConfig.RemoteKeyNew != "")
                    {
                        RemoteManager.EncryptKey = Sodium.PasswordHash.ArgonHashBinary(Encoding.UTF8.GetBytes(req.DataConfig.RemoteKeyNew), RemoteManager.SALT, 3, 268435456, 32);
                    }
                    RemoteManager.Enabled = req.DataConfig.RemoteManagement;
                    if (RemoteManager.Enabled && UserInfo.Status == UserStatus.LoggedIn)
                    {
                        RemoteManager.Start();
                    }
                    else
                    {
                        RemoteManager.Stop();
                    }
                    Natfrp.BypassProxy           = req.DataConfig.BypassProxy;
                    UpdateManager.UpdateInterval = req.DataConfig.UpdateInterval;
                    Save();
                    PushConfig();
                    break;

                case MessageID.ControlCheckUpdate:
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    resp.DataUpdate = UpdateManager.CheckUpdate().WaitResult();
                    break;

                case MessageID.ControlGetUpdate:
                    if (blockSensitive)
                    {
                        connection.RespondFailure("远程控制无法执行该操作");
                        return;
                    }
                    resp.DataUpdate = UpdateManager.Status;
                    break;

                default:
                    // Login required ↓
                    lock (UserInfo)
                    {
                        if (UserInfo.Status != UserStatus.LoggedIn)
                        {
                            connection.RespondFailure("用户未登录");
                            return;
                        }
                    }
                    switch (req.Type)
                    {
                    case MessageID.TunnelList:
                        resp.DataTunnels = new TunnelList();
                        resp.DataTunnels.Tunnels.Add(TunnelManager.Values.Select(t => t.CreateProto()));
                        break;

                    case MessageID.TunnelReload:
                        TunnelManager.UpdateTunnels().Wait();
                        break;

                    case MessageID.TunnelUpdate:
                        lock (TunnelManager)
                        {
                            if (!TunnelManager.TryGetValue(req.DataUpdateTunnel.Id, out Tunnel t))
                            {
                                connection.RespondFailure("隧道不存在");
                                return;
                            }
                            t.Enabled = req.DataUpdateTunnel.Status == 1;
                            TunnelManager.PushOne(t);
                        }
                        break;

                    case MessageID.TunnelDelete:
                        Natfrp.Request <Natfrp.ApiResponse>("delete_tunnel", "tunnel=" + req.DataId).WaitResult();
                        lock (TunnelManager)
                        {
                            TunnelManager.Remove(req.DataId);
                            TunnelManager.Push();
                        }
                        break;

                    case MessageID.TunnelCreate:
                    {
                        var result = Natfrp.Request <Natfrp.CreateTunnel>("create_tunnel", new StringBuilder()
                                                                          .Append("type=").Append(req.DataCreateTunnel.Type)
                                                                          .Append("&name=").Append(req.DataCreateTunnel.Name)
                                                                          .Append("&note=").Append(req.DataCreateTunnel.Note)
                                                                          .Append("&node=").Append(req.DataCreateTunnel.Node)
                                                                          .Append("&local_ip=").Append(req.DataCreateTunnel.LocalAddress)
                                                                          .Append("&local_port=").Append(req.DataCreateTunnel.LocalPort)
                                                                          .Append("&remote_port=").Append(req.DataCreateTunnel.RemotePort).ToString()).WaitResult();
                        var t = TunnelManager.CreateFromApi(result.Data);
                        lock (TunnelManager)
                        {
                            TunnelManager[t.Id] = t;
                            TunnelManager.Push();
                        }
                        resp.Message = "#" + t.Id + " " + t.Name;
                    }
                    break;

                    case MessageID.NodeList:
                        resp.DataNodes = new NodeList();
                        resp.DataNodes.Nodes.Add(NodeManager.Values);
                        break;

                    case MessageID.NodeReload:
                        NodeManager.UpdateNodes().Wait();
                        break;
                    }
                    break;
                }
                connection.SendProto(resp);
            }
            catch (AggregateException e) when(e.InnerExceptions.Count == 1)
            {
                connection.SendProto(ResponseBase(false, e.InnerExceptions[0].ToString()));
            }
            catch (Exception e)
            {
                connection.SendProto(ResponseBase(false, e.ToString()));
            }
        }
        protected async Task <string> Login(string token, bool isAuto = false)
        {
            lock (UserInfo)
            {
                if (UserInfo.Status != UserStatus.NoLogin)
                {
                    return(UserInfo.Status == UserStatus.Pending ? "操作进行中, 请稍候" : "用户已登录");
                }
                if (token.Length != 16)
                {
                    return("Token 无效");
                }
                UserInfo.Status = UserStatus.Pending;
                PushUserInfo();
            }
            LogManager.Log(1, "Service", "开始登录, Token: " + token.Substring(0, 4) + "********" + token.Substring(12));
            try
            {
                Natfrp.Token = token;

                var user = await Natfrp.Request <Natfrp.GetUser>("get_user");

                if (!user.Data.Login)
                {
                    LogManager.Log(3, "Service", "服务器拒绝登录: " + user.Message);
                    Logout(true);
                    return(user.Message);
                }

                lock (UserInfo)
                {
                    UserInfo.Id   = user.Data.Id;
                    UserInfo.Name = user.Data.Name;
                    UserInfo.Meta = user.Data.Meta;

                    UserInfo.Status = UserStatus.LoggedIn;

                    AutoLogin = false;
                }

                Save();

                NodeManager.Clear();
                NodeManager.Start();

                TunnelManager.Clear();
                TunnelManager.Start();

                PushUserInfo();
                LogManager.Log(1, "Service", "用户登录成功");

                RemoteManager.Start();
            }
            catch (Exception e)
            {
                if (isAuto)
                {
                    LogManager.Log(3, "Service", "自动登录失败, 将在稍后重试: " + e.ToString());
                    lock (UserInfo)
                    {
                        UserInfo.Status = UserStatus.NoLogin;
                    }
                    // Don't push here
                }
                else
                {
                    LogManager.Log(3, "Service", "用户登录失败: " + e.ToString());
                    Logout(true);
                }
                return(e.ToString());
            }
            return(null);
        }