Ejemplo n.º 1
0
        /// <summary>
        /// http服务启动,初始化代码写在这里
        /// </summary>
        /// <param name="ctsHttp"></param>
        /// <param name="WebManagementPort"></param>
        /// <returns></returns>
        public async Task StartHttpService(CancellationTokenSource ctsHttp, int WebManagementPort)
        {
            try
            {
                HttpListener listener = new HttpListener();
                //缓存所有文件
                var dir   = new DirectoryInfo(BASE_FILE_PATH);
                var files = dir.GetFiles("*.*");
                foreach (var file in files)
                {
                    using (var fs = file.OpenRead())
                    {
                        var mms = new MemoryStream();
                        fs.CopyTo(mms);
                        FilesCache.Add(file.Name, mms);
                    }
                }
                Logger.Debug($"{files.Length} files cached.");

                listener.Prefixes.Add($"http://+:{WebManagementPort}/");
                Logger.Debug("Listening HTTP request on port " + WebManagementPort.ToString() + "...");
                await AcceptHttpRequest(listener, ctsHttp);
            }
            catch (HttpListenerException ex)
            {
                Logger.Debug("Please run this program in administrator mode." + ex);
                Logger.Error(ex.ToString(), ex);
            }
            catch (Exception ex)
            {
                Logger.Debug(ex);
                Logger.Error(ex.ToString(), ex);
            }
            Logger.Debug("Http服务结束。");
        }
Ejemplo n.º 2
0
        private async Task ProcessHeartbeatsCheck(int interval, CancellationTokenSource cts)
        {
            try
            {
                while (!cts.Token.IsCancellationRequested)
                {
                    //Server.Logger.Debug("开始心跳检测");
                    var outTimeClients = ServerContext.Clients.Where(
                        (cli) => DateTimeHelper.TimeRange(cli.LastUpdateTime, DateTime.Now) > interval).ToList();

                    foreach (var client in outTimeClients)
                    {
                        ServerContext.CloseAllSourceByClient(client.ClientID);
                    }
                    //Server.Logger.Debug("结束心跳检测");
                    await Task.Delay(interval);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex.Message, ex);
            }
            finally
            {
                Logger.Debug("fatal error:心跳检测处理异常终止。");
                //TODO 重新开始
            }
        }
Ejemplo n.º 3
0
        private async Task ProcessHttpRequestAsync(HttpListenerContext context)
        {
            try
            {
                var request  = context.Request;
                var response = context.Response;

                response.ContentEncoding = Encoding.UTF8;
                response.ContentType     = "text/html;charset=utf-8";

                //TODO ***通过request来的值进行接口调用

                //getJson
                var json = GetClientsInfoJson();
                await response.OutputStream.WriteAsync(HtmlUtil.GetContent(json.ToString()));

                //await response.OutputStream.WriteAsync(HtmlUtil.GetContent(request.RawUrl));
                response.OutputStream.Close();
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// 重要:连接服务端
        /// </summary>
        /// <returns></returns>
        public async Task ConnectToProvider()
        {
            var appIdIpPortConfig = ClientConfig.Clients;

            ConnnectionManager = ServerConnnectionManager.Create();
            ConnnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected;
            var clientModel = await ConnnectionManager.InitConfig();

            int counter = 0;

            //appid为0时说明没有分配appid,所以需要分配一个
            foreach (var app in appIdIpPortConfig)
            {
                if (app.AppId == 0)
                {
                    app.AppId = clientModel.AppList[counter].AppId;
                    counter++;
                }
            }
            Logger.Debug("****************port list*************");

            foreach (var ap in clientModel.AppList)
            {
                var cApp = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId);
                Logger.Debug(ap.AppId.ToString() + ":  " + ClientConfig.ProviderAddress + ":" + ap.Port.ToString() + "=>" +
                             cApp.IP + ":" + cApp.TargetServicePort);
            }
            Logger.Debug("**************************************");
            Task pollingTask = ConnnectionManager.PollingToProvider();

            try
            {
                await pollingTask;
            }
            catch (Exception ex)
            {
                Logger.Error("Thread:" + Thread.CurrentThread.ManagedThreadId + " crashed.\n", ex);
                throw;
            }

            await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.Token);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// 重要:连接服务端,一般做为入口方法
        /// 该方法主要操作一些配置和心跳
        /// AlwaysReconnect:始终重试,开启此选项,无论何时,一旦程序在连接不上时都会进行重试,否则只在连接成功后的异常中断时才重试。
        /// </summary>
        /// <returns></returns>
        public async Task Start(bool AlwaysReconnect = false)
        {
            if (AlwaysReconnect)
            {
                IsStarted = true;
            }
            var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token;
            //登录功能
            string arrangedToken = Global.NO_TOKEN_STRING;

            while (!oneLiveToken.IsCancellationRequested)
            {
                CANCEL_TOKEN_SRC      = new CancellationTokenSource();
                TRANSFERING_TOKEN_SRC = new CancellationTokenSource();
                HEARTBEAT_TOKEN_SRC   = new CancellationTokenSource();
                _waiter          = new TaskCompletionSource <object>();
                Router.TimeStamp = Guid.NewGuid();

                var appIdIpPortConfig = ClientConfig.Clients;
                int clientId          = 0;

                //0 获取服务器端口配置
                try
                {
                    await InitServerPorts();
                }
                catch (Exception ex)//出错 重连
                {
                    if (IsStarted == false)
                    {
                        StatusChanged(ClientStatus.LoginError, null); return;
                    }
                    else
                    {
                        Logger.Error("获取服务器端口失败:" + ex.Message, ex);

                        await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token);

                        continue;
                    }
                }

                //0.5 处理登录/重登录/匿名登录逻辑
                try
                {
                    //登录
                    if (CurrentLoginInfo != null)
                    {
                        var loginResult = await Login();

                        arrangedToken = loginResult.Item1;
                        clientId      = loginResult.Item2;
                    }
                    else if (File.Exists(NspClientCachePath))
                    { //登录缓存
                        arrangedToken = File.ReadAllText(NspClientCachePath);
                        //TODO 这个token的合法性无法保证,如果服务端删除了用户,而这里缓存还存在,会导致无法登录
                        //TODO ***** 这是个trick:防止匿名用户被服务端踢了之后无限申请新账号
                        //TODO 待解决 版本号无法显示的问题
                        CurrentLoginInfo = null;
                    }
                    else
                    {
                        //匿名登录,未提供登录信息时,使用空用户名密码自动注册并尝试匿名登录
                        Router.Logger.Debug("未提供登录信息,尝试匿名登录");
                        CurrentLoginInfo = new LoginInfo()
                        {
                            UserName = "", UserPwd = ""
                        };
                        var loginResult = await Login();

                        arrangedToken = loginResult.Item1;
                        clientId      = loginResult.Item2;
                        //保存缓存到磁盘
                        File.WriteAllText(NspClientCachePath, arrangedToken);
                    }
                }
                catch (Exception ex)//出错 重连
                {
                    if (IsStarted == false)
                    {
                        StatusChanged(ClientStatus.LoginError, null); return;
                    }
                    else
                    {
                        Logger.Error("启动失败:" + ex.Message, ex);
                        await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token);

                        continue;
                    }
                }
                //1.获取配置
                ConnectionManager = ServerConnectionManager.Create(clientId);
                ConnectionManager.CurrentToken          = arrangedToken;
                ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected;
                ConnectionManager.ServerNoResponse      = DoServerNoResponse; //下钻事件
                ClientModel clientModel = null;                               //
                try
                {
                    //从服务端初始化客户端配置
                    clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    //TODO 状态码:连接失败
                    Router.Logger.Error("连接失败:" + ex.Message, ex);
                    //throw;
                }

                //HasConnected = true;
                if (clientModel != null)
                {
                    int counter = 0;

                    //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个
                    foreach (var app in appIdIpPortConfig)
                    {
                        if (app.AppId == 0)
                        {
                            app.AppId = clientModel.AppList[counter].AppId;
                            counter++;
                        }
                    }
                    Logger.Debug("****************port list*************");
                    List <string> tunnelstrs = new List <string>();
                    foreach (var ap in clientModel.AppList)
                    {
                        var cApp      = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId);
                        var tunnelStr = ap.AppId.ToString() + ":  " + ClientConfig.ProviderAddress + ":" +
                                        ap.Port.ToString() + "=>" +
                                        cApp.IP + ":" + cApp.TargetServicePort;
                        Logger.Debug(tunnelStr);
                        tunnelstrs.Add(tunnelStr);
                    }
                    Logger.Debug("**************************************");
                    _ = ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs);
                    //3.创建心跳连接
                    _ = ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token, _waiter);

                    IsStarted = true;
                    if (await _waiter.Task.ConfigureAwait(false) is Exception exception)
                    {
                        Router.Logger.Debug($"程序异常终止:{exception.Message}。");
                    }
                    else
                    {
                        Router.Logger.Debug($"未知异常。");
                    }
                }
                else
                {
                    Router.Logger.Debug($"程序启动失败。");
                    //如果程序从未启动过就出错,则终止程序,否则重试。
                    if (IsStarted == false)
                    {
                        StatusChanged(ClientStatus.Stopped, null); return;
                    }
                }

                Router.Logger.Debug($"连接故障,尝试关闭连接并重试");
                if (ConnectionManager != null)
                {
                    ConnectionManager.CloseAllConnections();//关闭所有连接
                }
                //出错重试
                await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token);

                //TODO 返回错误码
                //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.CurrentToken).ConfigureAwait(false);
                Router.Logger.Debug($"连接关闭,开启重试");
            }
            //正常终止
            Router.Logger.Debug($"停止重试,循环终止。");
        }
Ejemplo n.º 6
0
        private async Task ProcessHttpRequestAsync(HttpListenerContext context)
        {
            var request  = context.Request;
            var response = context.Response;

            //TODO XX 设置该同源策略为了方便调试,真实项目可以确保同源

#if DEBUG
            response.AddHeader("Access-Control-Allow-Origin", "*");
#endif

            try
            {
                //通过request来的值进行接口调用
                string unit = request.RawUrl.Replace("//", "");

                if (unit == "/")
                {
                    unit = INDEX_PAGE;
                }

                int idx1 = unit.LastIndexOf("#");
                if (idx1 > 0)
                {
                    unit = unit.Substring(0, idx1);
                }
                int idx2 = unit.LastIndexOf("?");
                if (idx2 > 0)
                {
                    unit = unit.Substring(0, idx2);
                }
                int idx3 = unit.LastIndexOf(".");

                //通过后缀获取不同的文件,若无后缀,则调用接口
                if (idx3 > 0)
                {
                    if (!File.Exists(BASE_FILE_PATH + unit))
                    {
                        Server.Logger.Debug($"未找到文件{BASE_FILE_PATH + unit}");
                        return;
                    }
                    //mime类型
                    ProcessMIME(response, unit.Substring(idx3));
                    //TODO 权限控制(只是控制html权限而已)


                    //读文件优先去缓存读
                    MemoryStream memoryStream;
                    if (FilesCache.TryGetValue(unit.TrimStart('/'), out memoryStream))
                    {
                        memoryStream.Position = 0;
                        await memoryStream.CopyToAsync(response.OutputStream);
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(BASE_FILE_PATH + unit, FileMode.Open))
                        {
                            await fs.CopyToAsync(response.OutputStream);
                        }
                    }
                }
                else  //url中没有小数点则是接口
                {
                    unit = unit.Replace("/", "");
                    response.ContentEncoding = Encoding.UTF8;

                    //调用接口 用分布类隔离并且用API特性限定安全
                    object jsonObj;
                    //List<string> qsStrList;
                    int      qsCount    = request.QueryString.Count;
                    object[] parameters = null;
                    if (qsCount > 0)
                    {
                        parameters = new object[request.QueryString.Count];
                        for (int i = 0; i < request.QueryString.Count; i++)
                        {
                            parameters[i] = request.QueryString[i];
                        }
                    }

                    //反射调用API方法
                    MethodInfo method = null;
                    try
                    {
                        method = this.GetType().GetMethod(unit);
                        if (method == null)
                        {
                            //Server.Logger.Debug($"无效的方法名{unit}");
                            throw new Exception($"无效的方法名{unit}");
                        }

                        //TODO 先不校验,方便调试
                        //if (method.GetCustomAttribute<SecureAttribute>() != null)
                        //{
                        //    if (request.Cookies["NSPTK"] == null)
                        //        throw new Exception("用户未登陆。");
                        //    //TODO cookie,根据不同的用户角色分配权限。
                        //    var UserClaims = StringUtil.ConvertStringToTokenClaims(request.Cookies["NSPTK"].Value);
                        //    if (string.IsNullOrEmpty(UserClaims.UserKey))
                        //    {
                        //        throw new Exception("登陆信息异常。");
                        //    }
                        //}

                        if (method.GetCustomAttribute <APIAttribute>() != null)
                        {
                            response.ContentType = "application/json";
                            jsonObj = method.Invoke(this, parameters);
                            await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.Wrap().ToJsonString()));
                        }
                        else if (method.GetCustomAttribute <FormAPIAttribute>() != null)
                        {
                            response.ContentType = "text/html";
                            jsonObj = method.Invoke(this, parameters);
                            await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.ToString()));
                        }
                        else if (method.GetCustomAttribute <ValidateAPIAttribute>() != null)
                        {
                            response.ContentType = "application/json";
                            bool validateResult = (bool)method.Invoke(this, parameters);
                            if (validateResult == true)
                            {
                                await response.OutputStream.WriteAsync(HtmlUtil.GetContent("{\"valid\":true}"));
                            }
                            else
                            {
                                await response.OutputStream.WriteAsync(HtmlUtil.GetContent("{\"valid\":false}"));
                            }
                        }
                        else if (method.GetCustomAttribute <FileAPIAttribute>() != null)
                        {
                            response.ContentType = "application/octet-stream";
                            FileDTO fileDto = method.Invoke(this, parameters) as FileDTO;
                            if (fileDto == null)
                            {
                                throw new Exception("文件返回失败,请查看错误日志。");
                            }

                            response.Headers.Add("Content-Disposition", "attachment;filename=" + fileDto.FileName);
                            //response.OutputStream.(stream);
                            using (fileDto.FileStream)
                            {
                                await fileDto.FileStream.CopyToAsync(response.OutputStream);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex.Message, ex);
                        jsonObj = new Exception(ex.Message + "---" + ex.StackTrace);
                        response.ContentType = "application/json";
                        await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.Wrap().ToJsonString()));
                    }
                    finally
                    {
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }
            finally
            {
                response.OutputStream.Close();
            }
        }
Ejemplo n.º 7
0
        private async Task ProcessHttpRequestAsync(HttpListenerContext context)
        {
            string baseFilePath = "./Extension/HttpServerStaticFiles/";
            var    request      = context.Request;
            var    response     = context.Response;

            //TODO XX 设置该同源策略为了方便调试,请确保web项目也位于locahost5671上
            response.AddHeader("Access-Control-Allow-Origin", "http://localhost:5671");

            try
            {
                //TODO ***通过request来的值进行接口调用
                string unit = request.RawUrl.Replace("//", "");
                int    idx1 = unit.LastIndexOf("#");
                if (idx1 > 0)
                {
                    unit = unit.Substring(0, idx1);
                }
                int idx2 = unit.LastIndexOf("?");
                if (idx2 > 0)
                {
                    unit = unit.Substring(0, idx2);
                }
                int idx3 = unit.LastIndexOf(".");

                //TODO 通过后缀获取不同的文件,若无后缀,则调用接口
                if (idx3 > 0)
                {
                    if (!File.Exists(baseFilePath + unit))
                    {
                        Server.Logger.Debug($"未找到文件{baseFilePath + unit}");
                        return;
                    }
                    //mime类型
                    ProcessMIME(response, unit.Substring(idx3));
                    using (FileStream fs = new FileStream(baseFilePath + unit, FileMode.Open))
                    {
                        await fs.CopyToAsync(response.OutputStream);
                    }
                }
                else
                {
                    unit = unit.Replace("/", "");
                    response.ContentEncoding = Encoding.UTF8;
                    response.ContentType     = "application/json";

                    //TODO XXXXXX 调用接口 接下来要用分布类隔离并且用API特性限定安全
                    object jsonObj;
                    //List<string> qsStrList;
                    int      qsCount    = request.QueryString.Count;
                    object[] parameters = null;
                    if (qsCount > 0)
                    {
                        parameters = new object[request.QueryString.Count];
                        for (int i = 0; i < request.QueryString.Count; i++)
                        {
                            parameters[i] = request.QueryString[i];
                        }
                    }

                    // request.QueryString[0]
                    try
                    {
                        jsonObj = this.GetType().GetMethod(unit).Invoke(this, parameters);
                    }
                    catch (Exception e)
                    {
                        Logger.Error(e.Message, e);
                        jsonObj = e.Message + "---" + e.StackTrace;
                    }

                    //getJson
                    //var json = GetClientsInfoJson();
                    //无返回值则返回默认数据。
                    //if (jsonObj == null) await response.OutputStream.WriteAsync(HtmlUtil.GetContent(""));
                    await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.Wrap().ToJsonString()));

                    //await response.OutputStream.WriteAsync(HtmlUtil.GetContent(request.RawUrl));
                    // response.OutputStream.Close();
                }
                //suffix = unit.Substring(unit.LastIndexOf(".")+1,)
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }
            finally
            {
                response.OutputStream.Close();
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// 重要:连接服务端,一般做为入口方法
        /// 该方法主要操作一些配置和心跳
        /// </summary>
        /// <returns></returns>
        public async Task Start()
        {
            var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token;

            while (!oneLiveToken.IsCancellationRequested)
            {
                CANCEL_TOKEN_SRC      = new CancellationTokenSource();
                TRANSFERING_TOKEN_SRC = new CancellationTokenSource();
                HEARTBEAT_TOKEN_SRC   = new CancellationTokenSource();
                _waiter = new TaskCompletionSource <object>();
                var appIdIpPortConfig = ClientConfig.Clients;
                int clientId          = 0;

                //0.5 如果有文件,取出缓存中的clientid
                try
                {
                    if (File.Exists(NSMART_CLIENT_CACHE_PATH))
                    {
                        using (var stream = File.OpenRead(NSMART_CLIENT_CACHE_PATH))
                        {
                            byte[] bytes = new byte[2];
                            stream.Read(bytes, 0, bytes.Length);
                            clientId = StringUtil.DoubleBytesToInt(bytes);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex.Message, ex);
                }
                //1.获取配置
                ConnectionManager = ServerConnnectionManager.Create(clientId);
                ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected;
                ConnectionManager.ServerNoResponse      = DoServerNoResponse; //下钻事件
                ClientModel clientModel = null;                               //
                try
                {
                    //非第一次则算作重连,发送clientid过去
                    clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    //TODO 状态码:连接失败
                    Router.Logger.Error("连接失败:" + ex.Message, ex);
                    //throw;
                }

                //HasConnected = true;
                if (clientModel != null)
                {
                    int counter = 0;

                    //1.5 写入缓存
                    File.WriteAllBytes(NSMART_CLIENT_CACHE_PATH, StringUtil.IntTo2Bytes(clientModel.ClientId));
                    //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个
                    foreach (var app in appIdIpPortConfig)
                    {
                        if (app.AppId == 0)
                        {
                            app.AppId = clientModel.AppList[counter].AppId;
                            counter++;
                        }
                    }
                    Logger.Debug("****************port list*************");
                    List <string> tunnelstrs = new List <string>();
                    foreach (var ap in clientModel.AppList)
                    {
                        var cApp      = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId);
                        var tunnelStr = ap.AppId.ToString() + ":  " + ClientConfig.ProviderAddress + ":" +
                                        ap.Port.ToString() + "=>" +
                                        cApp.IP + ":" + cApp.TargetServicePort;
                        Logger.Debug(tunnelStr);
                        tunnelstrs.Add(tunnelStr);
                    }
                    Logger.Debug("**************************************");
                    ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs);
                    //3.创建心跳连接
                    ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token);

                    //try
                    //{
                    //    await pollingTask.ConfigureAwait(false);
                    //}
                    //catch (Exception ex)
                    //{
                    //    Logger.Error("Thread:" + Thread.CurrentThread.ManagedThreadId + " crashed.\n", ex);
                    //    throw;
                    //}
                    IsStarted = true;
                    Exception exception = await _waiter.Task.ConfigureAwait(false) as Exception;

                    Router.Logger.Debug($"程序异常终止:{exception.Message}。");
                }
                else
                {
                    Router.Logger.Debug($"程序启动失败。");
                    //如果程序从未启动过就出错,则终止程序,否则重试。
                    if (IsStarted == false)
                    {
                        StatusChanged(ClientStatus.Stopped, null); return;
                    }
                }
                //出错重试
                await Task.Delay(3000, ONE_LIVE_TOKEN_SRC.Token);

                //TODO 返回错误码
                //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.Token).ConfigureAwait(false);
            }
            //正常终止
        }
Ejemplo n.º 9
0
        private async Task ProcessHttpRequestAsync(HttpListenerContext context)
        {
            var request  = context.Request;
            var response = context.Response;

            //TODO XX 设置该同源策略为了方便调试,请确保web项目也位于locahost5671上

#if DEBUG
            response.AddHeader("Access-Control-Allow-Origin", "*");
#endif

            try
            {
                //TODO ***通过request来的值进行接口调用
                string unit = request.RawUrl.Replace("//", "");

                if (unit == "/")
                {
                    unit = INDEX_PAGE;
                }

                int idx1 = unit.LastIndexOf("#");
                if (idx1 > 0)
                {
                    unit = unit.Substring(0, idx1);
                }
                int idx2 = unit.LastIndexOf("?");
                if (idx2 > 0)
                {
                    unit = unit.Substring(0, idx2);
                }
                int idx3 = unit.LastIndexOf(".");

                //TODO 通过后缀获取不同的文件,若无后缀,则调用接口
                if (idx3 > 0)
                {
                    if (!File.Exists(BASE_FILE_PATH + unit))
                    {
                        Server.Logger.Debug($"未找到文件{BASE_FILE_PATH + unit}");
                        return;
                    }
                    //mime类型
                    ProcessMIME(response, unit.Substring(idx3));

                    //读文件优先去缓存读
                    MemoryStream memoryStream;
                    if (FilesCache.TryGetValue(unit.TrimStart('/'), out memoryStream))
                    {
                        memoryStream.Position = 0;
                        await memoryStream.CopyToAsync(response.OutputStream);
                    }
                    else
                    {
                        using (FileStream fs = new FileStream(BASE_FILE_PATH + unit, FileMode.Open))
                        {
                            await fs.CopyToAsync(response.OutputStream);
                        }
                    }
                }
                else
                {
                    unit = unit.Replace("/", "");
                    response.ContentEncoding = Encoding.UTF8;


                    //TODO XXXXXX 调用接口 接下来要用分布类隔离并且用API特性限定安全
                    object jsonObj;
                    //List<string> qsStrList;
                    int      qsCount    = request.QueryString.Count;
                    object[] parameters = null;
                    if (qsCount > 0)
                    {
                        parameters = new object[request.QueryString.Count];
                        for (int i = 0; i < request.QueryString.Count; i++)
                        {
                            parameters[i] = request.QueryString[i];
                        }
                    }

                    // request.QueryString[0]
                    MethodInfo method = null;
                    try
                    {
                        method = this.GetType().GetMethod(unit);
                        if (method == null)
                        {
                            Server.Logger.Debug($"无效的方法名{unit}");
                        }

                        if (method.GetCustomAttribute <APIAttribute>() != null)
                        {
                            response.ContentType = "application/json";
                            jsonObj = method.Invoke(this, parameters);
                            await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.Wrap().ToJsonString()));
                        }
                        else if (method.GetCustomAttribute <FormAPIAttribute>() != null)
                        {
                            response.ContentType = "text/html";
                            jsonObj = method.Invoke(this, parameters);
                            await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.ToString()));
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(ex.Message, ex);
                        jsonObj = new Exception(ex.Message + "---" + ex.StackTrace);
                        response.ContentType = "application/json";
                        await response.OutputStream.WriteAsync(HtmlUtil.GetContent(jsonObj.Wrap().ToJsonString()));
                    }
                }
                //suffix = unit.Substring(unit.LastIndexOf(".")+1,)
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }
            finally
            {
                response.OutputStream.Close();
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// 重要:连接服务端,一般做为入口方法
        /// 该方法主要操作一些配置和心跳
        /// AlwaysReconnect:始终重试,开启此选项,无论何时,一旦程序在连接不上时都会进行重试,否则只在连接成功后的断线时才重试。
        /// </summary>
        /// <returns></returns>
        public async Task Start(bool AlwaysReconnect = false)
        {
            if (AlwaysReconnect)
            {
                IsStarted = true;
            }
            var oneLiveToken = ONE_LIVE_TOKEN_SRC.Token;
            //登陆功能
            string arrangedToken = Global.NO_TOKEN_STRING;

            while (!oneLiveToken.IsCancellationRequested)
            {
                CANCEL_TOKEN_SRC      = new CancellationTokenSource();
                TRANSFERING_TOKEN_SRC = new CancellationTokenSource();
                HEARTBEAT_TOKEN_SRC   = new CancellationTokenSource();
                _waiter = new TaskCompletionSource <object>();
                var appIdIpPortConfig = ClientConfig.Clients;
                int clientId          = 0;

                //0.5 如果有文件,取出缓存中的clientid
                try
                {
                    //登陆缓存
                    if (File.Exists(NSMART_CLIENT_CACHE_PATH))
                    {
                        using (var stream = File.OpenRead(NSMART_CLIENT_CACHE_PATH))
                        {
                            byte[] bytes = new byte[2];
                            stream.Read(bytes, 0, bytes.Length);
                            clientId = StringUtil.DoubleBytesToInt(bytes);
                        }
                    }
                    //登陆
                    if (CurrentLoginInfo != null)
                    {
                        NSPDispatcher disp   = new NSPDispatcher();
                        var           result = await disp.LoginFromClient(CurrentLoginInfo.UserName, CurrentLoginInfo.UserPwd);

                        if (result.State == 1)
                        {
                            Router.Logger.Debug("登陆成功");
                            var data = result.Data;
                            arrangedToken = data.Token;
                            Router.Logger.Debug($"服务端版本号:{data.Version},当前适配版本号{Global.NSmartProxyServerName}");
                            clientId = int.Parse(data.Userid);
                        }
                        else
                        {
                            throw new Exception("登陆失败,服务端返回错误如下:" + result.Msg);
                        }
                    }
                    else
                    {
                        Router.Logger.Debug("为提供登陆信息,尝试匿名登陆");
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error(ex.Message, ex);
                }
                //1.获取配置
                ConnectionManager = ServerConnectionManager.Create(clientId);
                ConnectionManager.CurrentToken          = arrangedToken;
                ConnectionManager.ClientGroupConnected += ServerConnnectionManager_ClientGroupConnected;
                ConnectionManager.ServerNoResponse      = DoServerNoResponse; //下钻事件
                ClientModel clientModel = null;                               //
                try
                {
                    //非第一次则算作重连,发送clientid过去
                    clientModel = await ConnectionManager.InitConfig(this.ClientConfig).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    //TODO 状态码:连接失败
                    Router.Logger.Error("连接失败:" + ex.Message, ex);
                    //throw;
                }

                //HasConnected = true;
                if (clientModel != null)
                {
                    int counter = 0;

                    //1.5 写入缓存
                    File.WriteAllBytes(NSMART_CLIENT_CACHE_PATH, StringUtil.IntTo2Bytes(clientModel.ClientId));
                    //2.分配配置:appid为0时说明没有分配appid,所以需要分配一个
                    foreach (var app in appIdIpPortConfig)
                    {
                        if (app.AppId == 0)
                        {
                            app.AppId = clientModel.AppList[counter].AppId;
                            counter++;
                        }
                    }
                    Logger.Debug("****************port list*************");
                    List <string> tunnelstrs = new List <string>();
                    foreach (var ap in clientModel.AppList)
                    {
                        var cApp      = appIdIpPortConfig.First(obj => obj.AppId == ap.AppId);
                        var tunnelStr = ap.AppId.ToString() + ":  " + ClientConfig.ProviderAddress + ":" +
                                        ap.Port.ToString() + "=>" +
                                        cApp.IP + ":" + cApp.TargetServicePort;
                        Logger.Debug(tunnelStr);
                        tunnelstrs.Add(tunnelStr);
                    }
                    Logger.Debug("**************************************");
                    ConnectionManager.PollingToProvider(StatusChanged, tunnelstrs);
                    //3.创建心跳连接
                    ConnectionManager.StartHeartBeats(Global.HeartbeatInterval, HEARTBEAT_TOKEN_SRC.Token);

                    IsStarted = true;
                    Exception exception = await _waiter.Task.ConfigureAwait(false) as Exception;

                    if (exception != null)
                    {
                        Router.Logger.Debug($"程序异常终止:{exception.Message}。");
                    }
                    else
                    {
                        Router.Logger.Debug($"未知异常。");
                    }
                }
                else
                {
                    Router.Logger.Debug($"程序启动失败。");
                    //如果程序从未启动过就出错,则终止程序,否则重试。
                    if (IsStarted == false)
                    {
                        StatusChanged(ClientStatus.Stopped, null); return;
                    }
                }

                Router.Logger.Debug($"连接故障,尝试关闭连接并重试");
                if (ConnectionManager != null)
                {
                    ConnectionManager.CloseAllConnections();//关闭所有连接
                }
                //出错重试
                await Task.Delay(Global.ClientReconnectInterval, ONE_LIVE_TOKEN_SRC.Token);

                //TODO 返回错误码
                //await Task.Delay(TimeSpan.FromHours(24), CANCEL_TOKEN.CurrentToken).ConfigureAwait(false);
                Router.Logger.Debug($"连接关闭,开启重试");
            }
            //正常终止
            Router.Logger.Debug($"停止重试,循环终止。");
        }
Ejemplo n.º 11
0
 private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
 {
     Logger.Error(e.Exception.ToString(), e.Exception);
 }