// fire and forget private async void DoReconnect() { var reconnectUrl = UrlBuilder.BuildReconnect(_connection, Name, _connectionData); while (TransportHelper.VerifyLastActive(_connection) && _connection.EnsureReconnecting()) { try { await Task.Delay(ReconnectDelay); await PerformConnect(reconnectUrl); break; } catch (OperationCanceledException) { break; } catch (Exception ex) { if (ExceptionHelper.IsRequestAborted(ex)) { break; } _connection.OnError(ex); } } }
// internal for testing internal async Task Reconnect(IConnection connection, string connectionData) { var reconnectUrl = UrlBuilder.BuildReconnect(connection, Name, connectionData); if (ConnectionState.Disconnected == connection.State || !_webSocket.IsConnected) { while (TransportHelper.VerifyLastActive(connection) && connection.EnsureReconnecting() && !_disconnectToken.IsCancellationRequested) { try { await StartWebSocket(connection, reconnectUrl); if (connection.ChangeState(ConnectionState.Reconnecting, ConnectionState.Connected)) { connection.OnReconnected(); } break; } catch (OperationCanceledException) { break; } catch (Exception ex) { connection.OnError(ex); } await Task.Delay(ReconnectDelay); } } }
private async Task DoReconnect() { var reconnectUrl = UrlBuilder.BuildReconnect(connection, Name, connectionData); while (TransportHelper.VerifyLastActive(connection)) { if (connection.EnsureReconnecting()) { try { PerformConnect(reconnectUrl); break; } catch (OperationCanceledException) { break; } catch (Exception ex) { connection.OnError(ex); } await Task.Delay(ReconnectDelay, CancellationToken.None).ConfigureAwait(false); } else { break; } } }
// fire and forget private async void DoReconnect() { try { var reconnectUrl = UrlBuilder.BuildReconnect(_connection, Name, _connectionData); while (TransportHelper.VerifyLastActive(_connection) && _connection.EnsureReconnecting()) { try { await PerformConnect(reconnectUrl, _disconnectToken); break; } catch (OperationCanceledException) { return; } catch (Exception ex) { if (ExceptionHelper.IsRequestAborted(ex)) { return; } _connection.OnError(ex); } await Task.Delay(ReconnectDelay); } var linkedToken = CreateLinkedCancellationToken(); try { await _webSocketHandler.ProcessWebSocketRequestAsync(_webSocket, linkedToken); } catch { // Ignore any errors from ProcessWebSocketRequestAsync just as OnStart does after the init message is received. // Any errors other than one thrown from the final CloseAsync is reported via OnError(Exception). } } catch (Exception ex) { _connection.Trace(TraceLevels.Events, "WS DoReconnect() failed: {0}", ex); } }
private string ResolveUrl(IConnection connection, string connectionData) { string url; if (connection.MessageId == null) { url = UrlBuilder.BuildConnect(connection, Name, connectionData); connection.Trace(TraceLevels.Events, "LP Connect: {0}", url); } else if (IsReconnecting(connection)) { url = UrlBuilder.BuildReconnect(connection, Name, connectionData); connection.Trace(TraceLevels.Events, "LP Reconnect: {0}", url); } else { url = UrlBuilder.BuildPoll(connection, Name, connectionData); connection.Trace(TraceLevels.Events, "LP Poll: {0}", url); } return(url); }
internal void OpenConnection(IConnection connection, string data, CancellationToken disconnectToken, bool reconnecting) { // If we're reconnecting add /connect to the url var url = reconnecting ? UrlBuilder.BuildReconnect(connection, Name, data) : UrlBuilder.BuildConnect(connection, Name, data); connection.Trace(TraceLevels.Events, "SSE: GET {0}", url); var getTask = HttpClient.Get(url, req => { _request = req; _request.Accept = "text/event-stream"; connection.PrepareRequest(_request); }, isLongRunning: true); var requestCancellationRegistration = disconnectToken.SafeRegister(state => { _stop = true; // This will no-op if the request is already finished. ((IRequest)state).Abort(); }, _request); getTask.ContinueWith(task => { if (task.IsFaulted || task.IsCanceled) { var exception = task.IsCanceled ? new OperationCanceledException(Resources.Error_TaskCancelledException) : task.Exception.Unwrap(); if (!reconnecting) { // It shouldn't be possible for Start to have already succeeded at this point. TryFailStart(exception); } else if (!_stop) { // Only raise the error event if the error wasn't raised from Start and we're reconnecting. connection.OnError(exception); Reconnect(connection, data, disconnectToken); } requestCancellationRegistration.Dispose(); } else { // If the disconnect token is canceled the response to the task doesn't matter. if (disconnectToken.IsCancellationRequested) { return; } var response = task.Result; Stream stream = response.GetStream(); var eventSource = new EventSourceStreamReader(connection, stream); eventSource.Opened = () => { // This will noop if we're not in the reconnecting state if (connection.ChangeState(ConnectionState.Reconnecting, ConnectionState.Connected)) { // Raise the reconnect event if the connection comes back up connection.OnReconnected(); } }; eventSource.Message = sseEvent => { if (sseEvent.EventType == EventType.Data && !sseEvent.Data.Equals("initialized", StringComparison.OrdinalIgnoreCase)) { ProcessResponse(connection, sseEvent.Data); } }; eventSource.Closed = exception => { // Make sure to try to fail start even if the disconnectToken tripped and set _stop to true. var startFailed = TryFailStart(exception); if (exception != null && !startFailed) { // Check if the request is aborted if (!ExceptionHelper.IsRequestAborted(exception)) { // Don't raise exceptions if the request was aborted (connection was stopped). connection.OnError(exception); } } requestCancellationRegistration.Dispose(); response.Dispose(); if (_stop) { AbortHandler.CompleteAbort(); } else if (!AbortHandler.TryCompleteAbort() && !startFailed) { // If Abort() was called or Start() failed, don't reconnect. Reconnect(connection, data, disconnectToken); } }; eventSource.Start(); } }); }