private void ConnectAsync(WebSocket ws) { if (ws == null) { return; } if (ws.ReadyState == WebSocketState.Open) { return; } // WebSocketSharp内部限定了连接重试次数,这不符合我们的业务逻辑,这里通过反射赋值使WebSocketSharp的重试次数限制失效。 _retryCountForConnectFieldInfo.SetValue(ws, 1); WsUserName userName = new WsUserName { ClientType = _appType, ClientVersion = EntryAssemblyInfo.CurrentVersionStr, ClientId = NTMinerRegistry.GetClientId(_appType), UserId = _preOuterUserId, IsBinarySupported = true }; string userNameJson = VirtualRoot.JsonSerializer.Serialize(userName); string password = string.Empty; if (_appType == NTMinerAppType.MinerStudio) { password = RpcRoot.RpcUser.Password; } string base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(userNameJson)); password = HashUtil.Sha1(base64String + password); // SetCredentials要求username不能带:号,所以必须编码 ws.SetCredentials(base64String, password, preAuth: true); LastTryOn = DateTime.Now; ws.ConnectAsync(); }
public AbstractWsClient(NTMinerAppType appType) { _appType = appType; _clientId = NTMinerRegistry.GetClientId(appType); VirtualRoot.BuildEventPath <Per1SecondEvent>("重试Ws连接的秒表倒计时", LogEnum.None, typeof(VirtualRoot), PathPriority.Normal, path: message => { if (_nextTrySecondsDelay > 0) { _nextTrySecondsDelay--; } }); VirtualRoot.BuildEventPath <Per10SecondEvent>("周期检查Ws连接", LogEnum.None, typeof(VirtualRoot), PathPriority.Normal, path: message => { if (_ws == null || _ws.ReadyState != WebSocketState.Open) { if (_continueCount >= _failConnCount) { _continueCount = 0; OpenOrCloseWs(); } else { _continueCount++; } } }); // 20秒是个不错的值,即不太频繁,也不太少 VirtualRoot.BuildEventPath <Per20SecondEvent>("周期Ws Ping", LogEnum.None, typeof(VirtualRoot), PathPriority.Normal, path: message => { if (_ws != null && _ws.ReadyState == WebSocketState.Open) { // 或者_ws.IsAlive,因为_ws.IsAlive内部也是一个Ping,所以用Ping从而显式化这里有个网络请求 Task.Factory.StartNew(() => { if (!_ws.Ping()) { _ws.CloseAsync(CloseStatusCode.Away); } }); } }); VirtualRoot.BuildEventPath <AppExitEvent>("退出程序时关闭Ws连接", LogEnum.DevConsole, this.GetType(), PathPriority.Normal, path: message => { _ws?.CloseAsync(CloseStatusCode.Normal, "客户端程序退出"); }); NetworkChange.NetworkAvailabilityChanged += (object sender, NetworkAvailabilityEventArgs e) => { if (e.IsAvailable) { 1.SecondsDelay().ContinueWith(t => { OpenOrCloseWs(isResetFailCount: true); }); } }; /// 1,进程启动后第一次连接时; NeedReWebSocket(); OpenOrCloseWs(); }
public void ReClientIdAsync(NTMinerAppType appType) { RpcRoot.JsonRpc.FirePostAsync( NTKeyword.Localhost, NTKeyword.NTMinerDaemonPort, _controllerName, nameof(INTMinerDaemonController.ReClientId), new Dictionary <string, string> { ["newClientId"] = NTMinerRegistry.GetClientId(appType).ToString() }, data: null, timeountMilliseconds: 3000); }
/// <summary> /// 同步方法 /// </summary> /// <param name="clientId"></param> /// <returns></returns> private static List <UserData> GetUsers() { try { DataRequest <Guid?> request = new DataRequest <Guid?> { Data = NTMinerRegistry.GetClientId() }; using (HttpClient client = new HttpClient()) { client.Timeout = TimeSpan.FromMilliseconds(2000); Task <HttpResponseMessage> message = client.PostAsJsonAsync($"http://{NTMinerRegistry.GetControlCenterHost()}:{VirtualRoot.ControlCenterPort}/api/ControlCenter/Users", request); DataResponse <List <UserData> > response = message.Result.Content.ReadAsAsync <DataResponse <List <UserData> > >().Result; if (response != null && response.Data != null) { return(response.Data); } } } catch (Exception e) { Logger.ErrorDebugLine(e); } return(new List <UserData>()); }
/// <summary> /// 同步方法 /// </summary> /// <param name="clientId"></param> /// <returns></returns> private static List <UserData> GetUsers() { try { DataRequest <Guid?> request = new DataRequest <Guid?> { LoginName = string.Empty, Data = NTMinerRegistry.GetClientId() }; using (HttpClient client = new HttpClient()) { Task <HttpResponseMessage> message = client.PostAsJsonAsync($"http://{NTMinerRegistry.GetControlCenterHost()}:{WebApiConst.ControlCenterPort}/api/ControlCenter/Users", request); DataResponse <List <UserData> > response = message.Result.Content.ReadAsAsync <DataResponse <List <UserData> > >().Result; if (response != null && response.Data != null) { return(response.Data); } } } catch (Exception e) { e = e.GetInnerException(); Logger.ErrorDebugLine(e.Message, e); } return(new List <UserData>()); }
public void GetJsonFileVersionAsync(NTMinerAppType appType, string key, Action <ServerStateResponse> callback) { HashSet <string> macAddresses = new HashSet <string>(); foreach (var localIp in VirtualRoot.LocalIpSet.AsEnumerable().ToArray()) { macAddresses.Add(localIp.MACAddress); } JsonFileVersionRequest request = new JsonFileVersionRequest { Key = key, ClientId = NTMinerRegistry.GetClientId(appType), MACAddress = macAddresses.ToArray() }; RpcRoot.JsonRpc.PostAsync( RpcRoot.OfficialServerHost, RpcRoot.OfficialServerPort, _controllerName, nameof(IAppSettingController.GetServerState), request, callback: (ServerStateResponse response, Exception e) => { if (e != null) { Logger.ErrorDebugLine(e); } if (response == null) { response = ServerStateResponse.Empty; Logger.ErrorWriteLine("询问服务器状态失败,请检查网络。"); } if (response.NeedReClientId) { NTMinerRegistry.ReClientId(ClientAppType.AppType); RpcRoot.Client.NTMinerDaemonService.ReClientIdAsync(appType); Logger.InfoDebugLine("检测到本机标识存在重复,已重新生成"); } callback?.Invoke(response); }, timeountMilliseconds: 10 * 1000); }
/// <summary> /// 这是一次彻底的重连,重新获取服务器地址的重连,以下情况下才会调用该方法: /// 1,进程启动后第一次连接时; /// 2,连不上服务器时; /// 3,收到服务器的WsMessage.ReGetServerAddress类型的消息时; /// </summary> /// <returns></returns> private void NewWebSocket(Action <WebSocket> callback) { RpcRoot.OfficialServer.WsServerNodeService.GetNodeAddressAsync(NTMinerRegistry.GetClientId(_appType), _outerUserId, (response, ex) => { LastTryOn = DateTime.Now; if (!response.IsSuccess()) { IncreaseFailCount(); UpdateNextTrySecondsDelay(); string description; if (response == null || response.ReasonPhrase == null) { description = "网络错误"; } else { description = response.ReadMessage(ex); } UpdateWsStateAsync(description, toOut: false); callback?.Invoke(null); // 退出 return; } string server = response.Data; if (string.IsNullOrEmpty(server)) { IncreaseFailCount(); UpdateNextTrySecondsDelay(); UpdateWsStateAsync("服务器不在线", toOut: false); callback?.Invoke(null); // 退出 return; } var ws = new WebSocket($"ws://{server}/{_appType.GetName()}"); ws.OnOpen += (sender, e) => { ResetFailCount(); UpdateWsStateAsync("连接服务器成功", toOut: false); }; ws.OnMessage += (sender, e) => { if (_ws != ws) { return; } #region if (e.IsPing) { return; } WsMessage message = null; if (e.IsBinary) { message = VirtualRoot.BinarySerializer.Deserialize <WsMessage>(e.RawData); } else // 此时一定IsText,因为取值只有IsBinary、IsPing、IsText这三种 { if (string.IsNullOrEmpty(e.Data) || e.Data[0] != '{' || e.Data[e.Data.Length - 1] != '}') { return; } message = VirtualRoot.JsonSerializer.Deserialize <WsMessage>(e.Data); } if (message == null) { return; } switch (_appType) { case NTMinerAppType.MinerClient: if (message.Type == WsMessage.UpdateAESPassword) { if (message.TryGetData(out AESPassword aesPassword)) { aesPassword.Password = Cryptography.RSAUtil.DecryptString(aesPassword.Password, aesPassword.PublicKey); _aesPassword = aesPassword; } return; } if (_aesPassword == null) { return; } if (message.Sign != message.CalcSign(_aesPassword.Password)) { UpdateWsStateAsync(description: "来自群控的消息签名错误", toOut: true); return; } break;
/// <summary> /// 这是一次彻底的重连,重新获取服务器地址的重连,以下情况下才会调用该方法: /// 1,进程启动后第一次连接时; /// 2,连不上服务器时; /// 3,收到服务器的WsMessage.ReGetServerAddress类型的消息时; /// </summary> /// <returns></returns> private void NewWebSocket() { if (_ws != null) { return; } RpcRoot.OfficialServer.WsServerNodeService.GetNodeAddressAsync(NTMinerRegistry.GetClientId(_appType), _preOuterUserId, (response, ex) => { if (_ws == null) { lock (_wsLocker) { if (_ws == null) { LastTryOn = DateTime.Now; _wsServerIp = string.Empty; #region 网络错误或没有获取到WsServer节点时退出 if (!response.IsSuccess()) { // 没有获取到该矿机的WsServer分片节点,递增失败次数以增大重试延迟周期 IncreaseFailCount(); UpdateNextTrySecondsDelay(); string description; if (response == null || response.ReasonPhrase == null) { description = "网络错误"; } else { description = response.ReadMessage(ex); } UpdateWsStateAsync(description, toOut: false); // 退出 return; } string server = response.Data; if (string.IsNullOrEmpty(server)) { // 没有获取到该矿机的WsServer分片节点,递增失败次数以增大重试延迟周期 IncreaseFailCount(); UpdateNextTrySecondsDelay(); UpdateWsStateAsync("服务器不在线", toOut: false); // 退出 return; } _wsServerIp = server; #endregion var ws = new WebSocket($"ws://{server}/{_appType.GetName()}") { Compression = CompressionMethod.Deflate }; ws.Log.File = System.IO.Path.Combine(TempPath.TempLogsDirFullName, NTKeyword.WebSocketSharpMinerClientLogFileName); ws.Log.Output = WebSocketSharpOutput; ws.OnOpen += new EventHandler(Ws_OnOpen); ws.OnMessage += new EventHandler <MessageEventArgs>(Ws_OnMessage); ws.OnError += new EventHandler <ErrorEventArgs>(Ws_OnError); ws.OnClose += new EventHandler <CloseEventArgs>(Ws_OnClose); ConnectAsync(ws); _ws = ws; } } } }); }