/// <summary> /// Open websocket connection. /// </summary> /// <returns>The async.</returns> /// <param name="secure">If set to <c>true</c> secure.</param> /// <param name="subprotocol">Subprotocol.</param> /// <param name="enforce">If set to <c>true</c> enforce.</param> /// <param name="cancellationToken">Cancellation token.</param> public Task <bool> OpenAsync(bool secure, string subprotocol = null, bool enforce = false, CancellationToken cancellationToken = default(CancellationToken)) { _secure = secure; if (state == Status.Online && !enforce) { AVRealtime.PrintLog("state is Status.Online."); return(Task.FromResult(true)); } if (CurrentConfiguration.RealtimeServer != null) { _wss = CurrentConfiguration.RealtimeServer.ToString(); AVRealtime.PrintLog("use configuration realtime server with url: " + _wss); return(OpenAsync(_wss, subprotocol, enforce)); } var routerUrl = CurrentConfiguration.RTMRouter != null?CurrentConfiguration.RTMRouter.ToString() : (AVClient.CurrentConfiguration.PushServer != null ? AVClient.CurrentConfiguration.PushServer.ToString() : null); return(RouterController.GetAsync(routerUrl, secure, cancellationToken).OnSuccess(r => { var routerState = r.Result; if (routerState == null) { return Task.FromResult(false); } _wss = routerState.server; _secondaryWss = routerState.secondary; state = Status.Connecting; AVRealtime.PrintLog("push router give a url :" + _wss); return OpenAsync(routerState.server, subprotocol, enforce); }).Unwrap()); }
/// <summary> /// 创建 Client /// </summary> /// <param name="clientId"></param> /// <param name="tag"></param> /// <param name="deviceId">设备唯一的 Id。如果是 iOS 设备,需要将 iOS 推送使用的 DeviceToken 作为 deviceId 传入</param> /// <param name="secure">是否强制加密 wss 链接</param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task <AVIMClient> CreateClientAsync(string clientId, string tag = null, string deviceId = null, bool secure = true, CancellationToken cancellationToken = default(CancellationToken)) { lock (mutex) { var client = PreLogIn(clientId, tag, deviceId); AVRealtime.PrintLog("begin OpenAsync."); return(OpenAsync(secure, Subprotocol, true, cancellationToken).OnSuccess(t => { if (!t.Result) { return Task.FromResult <AVIMCommand>(null); } AVRealtime.PrintLog("websocket server connected, begin to open sesstion."); SetNetworkState(); var cmd = new SessionCommand() .UA(VersionString) .Tag(tag) .DeviceId(deviceId) .Option("open") .PeerId(clientId); ToggleNotification(true); return AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)); }).Unwrap().OnSuccess(x => { var cmd = x.Result; if (cmd == null) { return Task.FromResult <Tuple <int, IDictionary <string, object> > >(null); } return this.RunCommandAsync(cmd); }).Unwrap().OnSuccess(s => { if (s.Result == null) { return null; } AVRealtime.PrintLog("sesstion opened."); state = Status.Online; ToggleHeartBeating(true); var response = s.Result.Item2; if (response.ContainsKey("st")) { _sesstionToken = response["st"] as string; } if (response.ContainsKey("stTtl")) { var stTtl = long.Parse(response["stTtl"].ToString()); _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; } AfterLogIn(client); return client; })); } }
/// <summary> /// 自动重连 /// </summary> /// <returns></returns> public Task AutoReconnect() { return(OpenAsync(_wss).ContinueWith(t => { state = Status.Reconnecting; var cmd = new SessionCommand() .UA(VersionString) .Tag(_tag) .R(1) .SessionToken(this._sesstionToken) .Option("open") .PeerId(_clientId); return AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(_clientId)).OnSuccess(_ => { return AVIMCommandRunner.RunCommandAsync(cmd); }).Unwrap(); }).Unwrap().OnSuccess(s => { var result = s.Result; if (result.Item1 == 0) { state = Status.Online; } else { state = Status.Offline; } })); }
private void ReconnectTimer_Elapsed(object sender, TimerEventArgs e) { var _timer = sender as AVTimer; if (state == Status.Offline) { if (_timer != null) { if (_timer.Executed <= this.ReconnectOptions.Retry && CanReconnect) { AutoReconnect(); PrintLog(string.Format("reconnect for {0} times,", _timer.Executed)); _timer.Executed += 1; if (_timer.Executed == 3) { useSecondary = true; } if (_timer.Executed == 6) { reborn = true; } } else { _timer.Stop(); _timer = null; autoReconnectionStarted = false; var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = -1 }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; } } else { if (CanReconnect) { AutoReconnect(); } } } else if (state == Status.Online) { if (_timer != null) { _timer.Stop(); _timer = null; } } }
/// <summary> /// 创建 Client /// </summary> /// <param name="clientId"></param> /// <param name="tag"></param> /// <param name="deviceId">设备唯一的 Id。如果是 iOS 设备,需要将 iOS 推送使用的 DeviceToken 作为 deviceId 传入</param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task <AVIMClient> CreateClient( string clientId, string tag = null, string deviceId = null, CancellationToken cancellationToken = default(CancellationToken)) { _clientId = clientId; _tag = tag; if (_tag != null) { if (deviceId == null) { throw new ArgumentNullException(deviceId, "当 tag 不为空时,必须传入当前设备不变的唯一 id(deviceId)"); } } if (string.IsNullOrEmpty(clientId)) { throw new Exception("当前 ClientId 为空,无法登录服务器。"); } return(OpenAsync(cancellationToken).OnSuccess(t => { ToggleNotification(true); var cmd = new SessionCommand() .UA(VersionString) .Tag(tag) .Argument("deviceId", deviceId) .Option("open") .PeerId(clientId); return AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)).OnSuccess(_ => { return AVIMCommandRunner.RunCommandAsync(cmd); }).Unwrap(); }).Unwrap().OnSuccess(s => { if (s.Exception != null) { var imException = s.Exception.InnerException as AVIMException; } state = Status.Online; var response = s.Result.Item2; if (response.ContainsKey("st")) { _sesstionToken = response["st"] as string; } if (response.ContainsKey("stTtl")) { var stTtl = long.Parse(response["stTtl"].ToString()); _sesstionTokenExpire = DateTime.Now.UnixTimeStampSeconds() + stTtl; } var client = new AVIMClient(clientId, tag, this); return client; })); }
/// <summary> /// Opens WebSocket connection with LeanCloud Push server. /// </summary> /// <returns>The async.</returns> /// <param name="cancellationToken">Cancellation token.</param> public Task OpenAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (state == Status.Online) { return(Task.FromResult(true)); } return(RouterController.GetAsync(cancellationToken).OnSuccess(_ => { _wss = _.Result.server; state = Status.Connecting; return OpenAsync(_.Result.server, cancellationToken); }).Unwrap()); }
private void WebsocketClient_OnClosed(int errorCode, string reason, string detail) { PrintLog(string.Format("websocket closed with code is {0},reason is {1} and detail is {2}", errorCode, reason, detail)); state = Status.Offline; var disconnectEventArgs = new AVIMDisconnectEventArgs(errorCode, reason, detail); m_OnDisconnected?.Invoke(this, disconnectEventArgs); this.WebSocketState = new WebSocketStateOptions() { ClosedCode = errorCode }; }
private void WebsocketClient_OnClosed(int arg1, string arg2, string arg3) { if (State != Status.Closed) { state = Status.Offline; PrintLog(string.Format("websocket closed with code is {0},reason is {1} and detail is {2}", arg1, arg2, arg3)); var args = new AVIMDisconnectEventArgs(arg1, arg2, arg3); m_OnDisconnected?.Invoke(this, args); // 如果断线产生的原因是客户端掉线而不是服务端踢下线,则应该开始自动重连 if (arg1 == 0) { StartAutoReconnect(); } } }
/// <summary> /// 创建 Client /// </summary> /// <param name="clientId"></param> /// <param name="tag"></param> /// <param name="deviceId">设备唯一的 Id。如果是 iOS 设备,需要将 iOS 推送使用的 DeviceToken 作为 deviceId 传入</param> /// <param name="secure">是否强制加密 wss 链接</param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task <AVIMClient> CreateClientAsync(string clientId, string tag = null, string deviceId = null, bool secure = true, CancellationToken cancellationToken = default(CancellationToken)) { lock (mutex) { var client = PreLogIn(clientId, tag, deviceId); AVRealtime.PrintLog("begin OpenAsync."); return(OpenAsync(secure, Subprotocol, cancellationToken).OnSuccess(t => { AVRealtime.PrintLog("OpenAsync OnSuccess. begin send open sesstion cmd."); var cmd = new SessionCommand() .UA(VersionString) .Tag(tag) .DeviceId(deviceId) .Option("open") .PeerId(clientId); ToggleNotification(true); return AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)); }).Unwrap().OnSuccess(x => { var cmd = x.Result; return AVIMCommandRunner.RunCommandAsync(cmd); }).Unwrap().OnSuccess(s => { AVRealtime.PrintLog("sesstion opened."); state = Status.Online; ToggleHeartBeating(_heartBeatingToggle); var response = s.Result.Item2; if (response.ContainsKey("st")) { _sesstionToken = response["st"] as string; } if (response.ContainsKey("stTtl")) { var stTtl = long.Parse(response["stTtl"].ToString()); _sesstionTokenExpire = DateTime.Now.UnixTimeStampSeconds() + stTtl; } return client; })); } }
internal Task LogInAsync(string clientId, string tag = null, string deviceId = null, bool secure = true, CancellationToken cancellationToken = default(CancellationToken)) { lock (mutex) { var cmd = new SessionCommand() .UA(VersionString) .Tag(tag) .DeviceId(deviceId) .Option("open") .PeerId(clientId); var result = AttachSignature(cmd, this.SignatureFactory.CreateConnectSignature(clientId)).OnSuccess(_ => { return(RunCommandAsync(cmd)); }).Unwrap().OnSuccess(t => { AVRealtime.PrintLog("sesstion opened."); if (t.Exception != null) { var imException = t.Exception.InnerException as AVIMException; throw imException; } state = Status.Online; var response = t.Result.Item2; if (response.ContainsKey("st")) { _sesstionToken = response["st"] as string; } if (response.ContainsKey("stTtl")) { var stTtl = long.Parse(response["stTtl"].ToString()); _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; } return(t.Result); }); return(result); } }
internal Task OpenSessionAsync(string clientId, string tag = null, string deviceId = null, string nonce = null, long timestamp = 0, string signature = null, bool secure = true) { var cmd = new SessionCommand() .UA(VersionString) .Tag(tag) .DeviceId(deviceId) .Option("open") .PeerId(clientId) .Argument("n", nonce) .Argument("t", timestamp) .Argument("s", signature); return(RunCommandAsync(cmd).OnSuccess(t => { AVRealtime.PrintLog("sesstion opened."); if (t.Exception != null) { var imException = t.Exception.InnerException as AVIMException; throw imException; } state = Status.Online; var response = t.Result.Item2; if (response.ContainsKey("st")) { _sesstionToken = response["st"] as string; } if (response.ContainsKey("stTtl")) { var stTtl = long.Parse(response["stTtl"].ToString()); _sesstionTokenExpire = DateTime.Now.ToUnixTimeStamp() + stTtl * 1000; } return t.Result; })); }
/// <summary> /// fetch wss address from push router and open the websocket connection. /// </summary> /// <param name="secure">if use ssl encrept</param> /// <param name="subprotocol">subprotocol</param> /// <param name="cancellationToken"></param> /// <returns></returns> public Task OpenAsync(bool secure = true, string subprotocol = null, CancellationToken cancellationToken = default(CancellationToken)) { if (state == Status.Online) { AVRealtime.PrintLog("state is Status.Online."); return(Task.FromResult(true)); } if (CurrentConfiguration.RealtimeServer != null) { AVRealtime.PrintLog("use configuration websocket url:" + _wss); return(OpenAsync(CurrentConfiguration.RealtimeServer.ToString(), subprotocol, cancellationToken)); } return(RouterController.GetAsync(CurrentConfiguration.PushRouterServer.ToString(), secure, cancellationToken).OnSuccess(_ => { _wss = _.Result.server; state = Status.Connecting; AVRealtime.PrintLog("push router give a url :" + _wss); return OpenAsync(_.Result.server, subprotocol, cancellationToken); }).Unwrap()); }
/// <summary> /// 自动重连 /// </summary> /// <returns></returns> Task AutoReconnect() { AVRealtime.PrintLog("AutoReconnect started."); var reconnectingArgs = new AVIMReconnectingEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken }; m_OnReconnecting?.Invoke(this, reconnectingArgs); var tcs = new TaskCompletionSource <bool>(); Task <bool> task; if (reborn) { AVRealtime.PrintLog("both preferred and secondary websockets are expired, so try to request RTM router to get a new pair"); task = OpenAsync(this._secure, Subprotocol, true); } else { var websocketServer = _wss; if (useSecondary) { AVRealtime.PrintLog(string.Format("preferred websocket server ({0}) network broken, take secondary server({1}) :", _wss, _secondaryWss)); websocketServer = _secondaryWss; } task = OpenAsync(websocketServer, Subprotocol, true); } task.ContinueWith(t => { if (t.IsFaulted || t.IsCanceled) { state = Status.Reconnecting; var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 0// network broken. }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; tcs.SetException(t.Exception); throw t.Exception; } else { state = Status.Opened; SetNetworkState(); void onClose(int code, string reason, string detail) { AVRealtime.PrintLog("disconnect when open session"); var ex = new Exception("connection is closed"); tcs.SetException(ex); AVWebSocketClient.OnClosed -= onClose; throw ex; }; AVWebSocketClient.OnClosed += onClose; if (this.IsSesstionTokenExpired) { AVRealtime.PrintLog("session is expired, auto relogin with clientId :" + _clientId); return(this.LogInAsync(_clientId, this._tag, this._deviceId, this._secure).ContinueWith(o => { AVWebSocketClient.OnClosed -= onClose; return !o.IsFaulted; })); } else { var sessionCMD = new SessionCommand().UA(VersionString).R(1); if (string.IsNullOrEmpty(_tag)) { sessionCMD = sessionCMD.Tag(_tag).SessionToken(this._sesstionToken); } var cmd = sessionCMD.Option("open") .PeerId(_clientId); AVRealtime.PrintLog("reopen session with session token :" + _sesstionToken); return(RunCommandAsync(cmd).ContinueWith(o => { AVWebSocketClient.OnClosed -= onClose; return !o.IsFaulted; })); } } }).Unwrap().ContinueWith(s => { if (s.IsFaulted || s.Exception != null) { var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 1 }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; tcs.SetException(s.Exception); } else { var reconnectedArgs = new AVIMReconnectedEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, }; state = Status.Online; m_OnReconnected?.Invoke(this, reconnectedArgs); ToggleNotification(true); ToggleHeartBeating(true); tcs.SetResult(true); } }); return(tcs.Task); }
/// <summary> /// 自动重连 /// </summary> /// <returns></returns> public Task AutoReconnect() { var reconnectingArgs = new AVIMReconnectingEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken }; m_OnReconnecting?.Invoke(this, reconnectingArgs); return(OpenAsync(_wss, Subprotocol).ContinueWith(t => { if (t.IsFaulted || t.Exception != null) { state = Status.Reconnecting; var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 0 // network broken. }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; return Task.FromResult(false); } else { if (t.Result) { state = Status.Opened; if (this.IsSesstionTokenExpired) { AVRealtime.PrintLog("sesstion is expired, auto relogin with clientId :" + _clientId); return this.LogInAsync(_clientId, this._tag, this._deviceId, this._secure).OnSuccess(o => { ClearReconnectTimer(); return true; }); } else { var sessionCMD = new SessionCommand().UA(VersionString).R(1); if (string.IsNullOrEmpty(_tag)) { sessionCMD = sessionCMD.Tag(_tag).SessionToken(this._sesstionToken); } var cmd = sessionCMD.Option("open") .PeerId(_clientId); AVRealtime.PrintLog("reopen sesstion with sesstion token :" + _sesstionToken); return AVIMCommandRunner.RunCommandAsync(cmd).OnSuccess(c => { ClearReconnectTimer(); return true; }); } } else { return Task.FromResult(false); } } }).Unwrap().ContinueWith(s => { if (s.IsFaulted || s.Exception != null) { var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 1 }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; } else { if (s.Result) { autoReconnectionStarted = false; reconnectTimer = null; var reconnectedArgs = new AVIMReconnectedEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, }; state = Status.Online; m_OnReconnected?.Invoke(this, reconnectedArgs); } } })); }
/// <summary> /// Starts manual reconnect. /// </summary> public void StartManualReconnect() { state = Status.Offline; StartAutoReconnect(); }
/// <summary> /// 自动重连 /// </summary> /// <returns></returns> public Task AutoReconnect() { AVRealtime.PrintLog("AutoReconnect started."); var reconnectingArgs = new AVIMReconnectingEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken }; m_OnReconnecting?.Invoke(this, reconnectingArgs); var websocketServer = _wss; if (useSecondary) { websocketServer = _secondaryWss; } Task <bool> task; if (reborn) { AVRealtime.PrintLog("both preferred and secondary websockets are expired, so try to request RTM router to get a new pair"); task = OpenAsync(this._secure, Subprotocol, true); } else { AVRealtime.PrintLog(string.Format("preferred websocket server ({0}) network broken, take secondary server({1}) :", _wss, _secondaryWss)); task = OpenAsync(websocketServer, Subprotocol, true); } return(task.ContinueWith(t => { if (!t.Result) { state = Status.Reconnecting; var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 0 // network broken. }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; return Task.FromResult(false); } else { state = Status.Opened; SetNetworkState(); if (this.IsSesstionTokenExpired) { AVRealtime.PrintLog("sesstion is expired, auto relogin with clientId :" + _clientId); return this.LogInAsync(_clientId, this._tag, this._deviceId, this._secure).OnSuccess(o => { ClearReconnectTimer(); return true; }); } else { var sessionCMD = new SessionCommand().UA(VersionString).R(1); if (string.IsNullOrEmpty(_tag)) { sessionCMD = sessionCMD.Tag(_tag).SessionToken(this._sesstionToken); } var cmd = sessionCMD.Option("open") .PeerId(_clientId); AVRealtime.PrintLog("reopen sesstion with sesstion token :" + _sesstionToken); return RunCommandAsync(cmd).OnSuccess(c => { ClearReconnectTimer(); return true; }); } } }).Unwrap().ContinueWith(s => { if (s.IsFaulted || s.Exception != null) { var reconnectFailedArgs = new AVIMReconnectFailedArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, FailedCode = 1 }; m_OnReconnectFailed?.Invoke(this, reconnectFailedArgs); state = Status.Offline; autoReconnectionStarted = false; } else { if (s.Result) { reconnectTimer = null; var reconnectedArgs = new AVIMReconnectedEventArgs() { ClientId = _clientId, IsAuto = true, SessionToken = _sesstionToken, }; state = Status.Online; autoReconnectionStarted = false; m_OnReconnected?.Invoke(this, reconnectedArgs); } } })); }