private async Task ReadStreamAsync(Stream stream)
        {
            var encoder = new UTF8Encoding();
            var streamReadcancellationTokenSource = new CancellationTokenSource();

            _log.Debug($"Reading stream ....");

            while (!_cancellationTokenSource.IsCancellationRequested && IsConnected())
            {
                if (stream.CanRead && IsConnected())
                {
                    var buffer = new byte[BufferSize];

                    var timeoutTask    = _wrapperAdapter.TaskDelay(ReadTimeout * 1000);
                    var streamReadTask = stream.ReadAsync(buffer, 0, BufferSize, streamReadcancellationTokenSource.Token);
                    // Creates a task that will complete when any of the supplied tasks have completed.
                    // Returns: A task that represents the completion of one of the supplied tasks. The return task's Result is the task that completed.
                    var finishedTask = await _wrapperAdapter.WhenAny(streamReadTask, timeoutTask);

                    if (finishedTask == timeoutTask)
                    {
                        throw new Exception($"Streaming read time out after {ReadTimeout} seconds.");
                    }

                    int len = streamReadTask.Result;

                    if (len == 0)
                    {
                        throw new Exception($"Streaming end of the file.");
                    }

                    var notificationString = encoder.GetString(buffer, 0, len);
                    _log.Debug($"Read stream encoder buffer: {notificationString}");

                    if (notificationString != KeepAliveResponse && IsConnected())
                    {
                        var lines = notificationString.Split(new[] { "\n\n" }, StringSplitOptions.None);

                        foreach (var line in lines)
                        {
                            try
                            {
                                if (!string.IsNullOrEmpty(line))
                                {
                                    var eventData = _notificationParser.Parse(line);

                                    if (eventData != null)
                                    {
                                        DispatchEvent(eventData);
                                    }
                                }
                            }
                            catch (NotificationErrorException ex)
                            {
                                _log.Debug($"Notification error: {ex.Message}. Status Server: {ex.Notification.StatusCode}.");

                                if (ex.Notification.StatusCode >= 40140 && ex.Notification.StatusCode <= 40149)
                                {
                                    Disconnect(reconnect: true);
                                }
                                else if (ex.Notification.StatusCode >= 40000 && ex.Notification.StatusCode <= 49999)
                                {
                                    Disconnect();
                                }
                            }
                            catch (Exception ex)
                            {
                                _log.Debug($"Error during event parse: {ex.Message}");
                            }
                        }
                    }
                }
            }

            _log.Debug($"Stop read stream");
        }
Esempio n. 2
0
        private async Task ReadStreamAsync(Stream stream, CancellationToken cancellationToken)
        {
            _log.Debug($"Reading stream ....");

            try
            {
                while (!cancellationToken.IsCancellationRequested && (IsConnected() || _firstEvent))
                {
                    if (stream.CanRead && (IsConnected() || _firstEvent))
                    {
                        Array.Clear(_buffer, 0, BufferSize);

                        var timeoutToken   = new CancellationTokenSource();
                        var timeoutTask    = _wrapperAdapter.TaskDelay(ReadTimeoutMs, timeoutToken.Token);
                        var streamReadTask = stream.ReadAsync(_buffer, 0, BufferSize, cancellationToken);
                        // Creates a task that will complete when any of the supplied tasks have completed.
                        // Returns: A task that represents the completion of one of the supplied tasks. The return task's Result is the task that completed.
                        var finishedTask = await _wrapperAdapter.WhenAny(streamReadTask, timeoutTask);

                        try
                        {
                            if (finishedTask == timeoutTask)
                            {
                                throw new ReadStreamException(SSEClientActions.RETRYABLE_ERROR, $"Streaming read time out after {ReadTimeoutMs} seconds.");
                            }

                            int len = streamReadTask.Result;

                            if (len == 0)
                            {
                                throw new ReadStreamException(SSEClientActions.RETRYABLE_ERROR, "Streaming end of the file.");
                            }

                            var notificationString = _encoder.GetString(_buffer, 0, len);
                            _log.Debug($"Read stream encoder buffer: {notificationString}");

                            if (_firstEvent)
                            {
                                ProcessFirtsEvent(notificationString);
                            }

                            if (notificationString != KeepAliveResponse && IsConnected())
                            {
                                var lines = notificationString.Split(_notificationSplitArray, StringSplitOptions.None);

                                foreach (var line in lines)
                                {
                                    if (!string.IsNullOrEmpty(line))
                                    {
                                        var eventData = _notificationParser.Parse(line);

                                        if (eventData != null)
                                        {
                                            if (eventData.Type == NotificationType.ERROR)
                                            {
                                                var notificationError = (NotificationError)eventData;

                                                ProcessErrorNotification(notificationError);
                                            }
                                            else
                                            {
                                                DispatchEvent(eventData);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        finally
                        {
                            _log.Debug("Disposing Stream Read Task...");
                            timeoutToken.Cancel();
                            timeoutToken.Dispose();
                            _wrapperAdapter.TaskWaitAndDispose(timeoutTask, streamReadTask, finishedTask);
                        }
                    }
                }
            }
            catch (ReadStreamException ex)
            {
                _log.Debug("ReadStreamException", ex);
                throw ex;
            }
            catch (Exception ex)
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    _log.Debug("Stream ended abruptly, proceeding to reconnect.", ex);
                    throw new ReadStreamException(SSEClientActions.RETRYABLE_ERROR, ex.Message);
                }

                _log.Debug("Stream Token cancelled.", ex);
            }
            finally
            {
                _log.Debug($"Stop read stream");
            }
        }