/// <summary>
        /// Initiates the request to the EventSource API and parses Server Sent Events received by the API.
        /// </summary>
        /// <returns>A <see cref="System.Threading.Tasks.Task"/> A task that represents the work queued to execute in the ThreadPool.</returns>
        /// <exception cref="InvalidOperationException">The method was called after the connection <see cref="ReadyState"/> was Open or Connecting.</exception>
        public async Task StartAsync()
        {
            bool firstTime = true;

            while (ReadyState != ReadyState.Shutdown)
            {
                if (!firstTime)
                {
                    if (_lastSuccessfulConnectionTime.HasValue)
                    {
                        if (DateTime.Now.Subtract(_lastSuccessfulConnectionTime.Value) >= _configuration.BackoffResetThreshold)
                        {
                            _backOff.ResetReconnectAttemptCount();
                        }
                        _lastSuccessfulConnectionTime = null;
                    }
                    await MaybeWaitWithBackOff();
                }
                firstTime = false;
                try
                {
                    CancellationTokenSource newRequestTokenSource = null;
                    lock (this)
                    {
                        if (_readyState == ReadyState.Shutdown)
                        {
                            // in case Close() was called in between the previous ReadyState check and the creation of the new token
                            return;
                        }

                        newRequestTokenSource = new CancellationTokenSource();
                        _currentRequestToken?.Dispose();
                        _currentRequestToken = newRequestTokenSource;
                    }

                    await ConnectToEventSourceAsync(newRequestTokenSource.Token);
                }
                catch (HttpRequestException e)
                {
                    if (e.Message == Resources.EventSourceService_Read_Timeout)
                    {
                        _logger.InfoFormat("Encountered an error connecting to EventSource: {0}", e, e.Message);
                    }
                    else
                    {
                        _logger.ErrorFormat("Encountered an error connecting to EventSource: {0}", e, e.Message);
                    }
                    _logger.Debug("", e);
                }
                catch (Exception e)
                {
                    _logger.ErrorFormat("Encountered an error connecting to EventSource: {0}", e, e.Message);
                    _logger.Debug("", e);
                }
            }
        }
Beispiel #2
0
        private async Task ConnectToEventSourceAsync(CancellationToken cancellationToken)
        {
            if (ReadyState == ReadyState.Connecting || ReadyState == ReadyState.Open)
            {
                throw new InvalidOperationException(string.Format(Resources.EventSource_Already_Started, ReadyState));
            }

            SetReadyState(ReadyState.Connecting);

            try
            {
                _eventBuffer = new List <string>();

                var svc = GetEventSourceService(_configuration);

                svc.ConnectionOpened += (o, e) => {
                    _backOff.ResetReconnectAttemptCount();
                    SetReadyState(ReadyState.Open, OnOpened);
                };
                svc.ConnectionClosed += (o, e) => { SetReadyState(ReadyState.Closed, OnClosed); };

                await svc.GetDataAsync(
                    ProcessResponseContent,
                    cancellationToken
                    );
            }
            catch (EventSourceServiceCancelledException e)
            {
                CancelCurrentRequest();

                CloseAndRaiseError(e);
            }
            catch (Exception e)
            {
                // If the user called Close(), ReadyState = Shutdown. Don't rethrow.
                if (ReadyState != ReadyState.Shutdown)
                {
                    CloseAndRaiseError(e);

                    throw;
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Initiates the request to the EventSource API and parses Server Sent Events received by the API.
        /// </summary>
        /// <returns>A <see cref="System.Threading.Tasks.Task"/> A task that represents the work queued to execute in the ThreadPool.</returns>
        /// <exception cref="InvalidOperationException">The method was called after the connection <see cref="ReadyState"/> was Open or Connecting.</exception>
        public async Task StartAsync()
        {
            var cancellationToken = _pendingRequest.Token;

            while (!cancellationToken.IsCancellationRequested)
            {
                MaybeWaitWithBackOff();
                try
                {
                    await ConnectToEventSourceAsync(cancellationToken);

                    _backOff.ResetReconnectAttemptCount();
                }
                catch (Exception e)
                {
                    _logger.LogError("Encountered an error connecting to EventSource: {0}", e.Message);
                    _logger.LogDebug(e.ToString());
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Initiates the request to the EventSource API and parses Server Sent Events received by the API.
        /// </summary>
        /// <returns>A <see cref="System.Threading.Tasks.Task"/> A task that represents the work queued to execute in the ThreadPool.</returns>
        /// <exception cref="InvalidOperationException">The method was called after the connection <see cref="ReadyState"/> was Open or Connecting.</exception>
        public async Task StartAsync()
        {
            bool firstTime = true;
            while (ReadyState != ReadyState.Shutdown)
            {
                if (!firstTime)
                {
                    if (_lastSuccessfulConnectionTime.HasValue)
                    {
                        if (DateTime.Now.Subtract(_lastSuccessfulConnectionTime.Value) >= _configuration.BackoffResetThreshold)
                        {
                            _backOff.ResetReconnectAttemptCount();
                        }
                        _lastSuccessfulConnectionTime = null;
                    }
                    await MaybeWaitWithBackOff();
                }
                firstTime = false;

                CancellationTokenSource newRequestTokenSource = null;
                CancellationToken cancellationToken;
                lock (this)
                {
                    if (_readyState == ReadyState.Shutdown)
                    {
                        // in case Close() was called in between the previous ReadyState check and the creation of the new token
                        return;
                    }
                    newRequestTokenSource = new CancellationTokenSource();
                    _currentRequestToken?.Dispose();
                    _currentRequestToken = newRequestTokenSource;
                }

                if (ReadyState == ReadyState.Connecting || ReadyState == ReadyState.Open)
                {
                    throw new InvalidOperationException(string.Format(Resources.EventSource_Already_Started, ReadyState));
                }

                SetReadyState(ReadyState.Connecting);
                cancellationToken = newRequestTokenSource.Token;

                try
                {
                    await ConnectToEventSourceAsync(cancellationToken);

                    // ConnectToEventSourceAsync normally doesn't return, unless it detects that the request has been cancelled.
                    Close(ReadyState.Closed);
                }
                catch (Exception e)
                {
                    CancelCurrentRequest();

                    // If the user called Close(), ReadyState = Shutdown, so errors are irrelevant.
                    if (ReadyState != ReadyState.Shutdown)
                    {
                        Close(ReadyState.Closed);

                        Exception realException = e;
                        if (e is OperationCanceledException oe)
                        {
                            // This exception could either be the result of us explicitly cancelling a request, in which case we don't
                            // need to do anything else, or it could be that the request timed out.
                            if (oe.CancellationToken.IsCancellationRequested)
                            {
                                realException = null;
                            }
                            else
                            {
                                realException = new TimeoutException();
                            }
                        }

                        if (realException != null)
                        {
                            OnError(new ExceptionEventArgs(realException));
                        }
                    }
                }
            }
        }