예제 #1
0
        /// <summary>
        /// Send consumer, reading messages one by one from stream and writes
        /// to websocket stream.
        /// </summary>
        /// <returns></returns>
        protected virtual async Task SendConsumerAsync(ICodecStream <S> codec)
        {
            if (_lastMessage == null)
            {
                _lastMessage = Message.Create(StreamId, _remoteId,
                                              PollRequest.Create((ulong)_timeout.TotalMilliseconds));
            }
            while (!_open.IsCancellationRequested)
            {
                try {
                    if (_lastMessage == null)
                    {
                        if (_send.Completion.IsCompleted)
                        {
                            // Pipeline closed, close the connection
                            _receive.Complete();
                            _open.Cancel();
                            break;
                        }
                        try {
                            _lastMessage = await _send.ReceiveAsync(_timeout,
                                                                    _open.Token).ConfigureAwait(false);

                            if (_lastMessage.Content is DataMessage data)
                            {
                                data.SequenceNumber = _nextSendSequenceNumber++;
                            }
                        }
                        catch (TimeoutException) {
                            _lastMessage = Message.Create(StreamId, _remoteId,
                                                          PollRequest.Create((ulong)_timeout.TotalMilliseconds));
                        }
                        catch (OperationCanceledException) when(!_open.IsCancellationRequested)
                        {
                            _lastMessage = Message.Create(StreamId, _remoteId,
                                                          PollRequest.Create((ulong)_timeout.TotalMilliseconds));
                        }
                    }
                    await codec.WriteAsync(_lastMessage, _open.Token).ConfigureAwait(false);

                    await codec.Stream.FlushAsync(_open.Token).ConfigureAwait(false);

                    _lastMessage.Dispose();
                    _lastMessage = null;
                }
                catch (OperationCanceledException) {
                    break;
                }
                catch (Exception e) {
                    ProxyEventSource.Log.StreamException(this, codec.Stream, e);
                    break;
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Open stream
        /// </summary>
        /// <param name="ct"></param>
        /// <returns></returns>
        public Task <IMessageStream> OpenAsync(CancellationToken ct)
        {
            CreateReceiveBlock();
            CreateSendBlock();

            // Start producer receiving from poll
            _receiveTask = Task.Factory.StartNew(async() => {
                var sendTimeout = TimeSpan.FromMilliseconds(_pollTimeout * 2);
                var receiver    = new IoTHubInvoker(_hubConnectionString);
                try {
                    ulong nextSequenceNumber = 0;
                    while (true)
                    {
                        using (var request = Message.Create(_streamId, _remoteId,
                                                            PollRequest.Create(_pollTimeout, nextSequenceNumber))) {
                            var response = await receiver.TryCallAsync(
                                _link, request, sendTimeout, _open.Token).ConfigureAwait(false);
                            //
                            // Poll receives back a timeout error in case no data was available
                            // within the requested timeout. This is decoupled from the consumers
                            // that time out on their cancellation tokens.
                            //
                            if (response != null && response.Error != (int)SocketError.Timeout)
                            {
                                if (!await _receive.SendAsync(response).ConfigureAwait(false))
                                {
                                    break;
                                }
                                nextSequenceNumber++;
                            }
                        }
                        // Continue polling until closed in which case we complete receive
                        _open.Token.ThrowIfCancellationRequested();
                    }
                }
                catch (OperationCanceledException) {
                }
                catch (Exception e) {
                    ProxyEventSource.Log.HandledExceptionAsError(this, e);
                    throw;
                }
                finally {
                    receiver.Dispose();
                }
            }, _open.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default).Unwrap();

            return(Task.FromResult((IMessageStream)this));
        }
예제 #3
0
        protected override async Task SendConsumerAsync(
            ICodecStream <HybridConnectionStream> codec)
        {
            while (!_open.IsCancellationRequested)
            {
                try {
                    if (_lastMessage == null)
                    {
                        if (_send.Completion.IsCompleted)
                        {
                            // Pipeline closed, close the connection
                            _receive.Complete();
                            _open.Cancel();
                            break;
                        }
                        try {
                            _lastMessage = await _send.ReceiveAsync(_timeout,
                                                                    _open.Token).ConfigureAwait(false);

                            var data = _lastMessage.Content as DataMessage;
                            if (data != null)
                            {
                                data.SequenceNumber = _nextSendSequenceNumber++;
                            }
                        }
                        catch (TimeoutException) {
                            _lastMessage = Message.Create(StreamId, _remoteId,
                                                          PollRequest.Create((ulong)_timeout.TotalMilliseconds));
                        }
                        catch (OperationCanceledException) when(!_open.IsCancellationRequested)
                        {
                            _lastMessage = Message.Create(StreamId, _remoteId,
                                                          PollRequest.Create((ulong)_timeout.TotalMilliseconds));
                        }
                    }
                    //
                    // Every write on the hybrid connection stream right now results in a binary
                    // message not an individual fragment.
                    // when using the codec directly on the stream then the first write confuses the
                    // proxy decoder, which assumes a websocket message contains an entire message.
                    // Override here to buffer the entire message in a memory stream before writing.
                    //
                    using (var mem = new MemoryStream()) {
                        _lastMessage.Encode(mem, CodecId.Mpack);
                        var buffered = mem.ToArray();
                        await codec.Stream.WriteAsync(
                            buffered, 0, buffered.Length, _open.Token).ConfigureAwait(false);
                    }
                    await codec.Stream.FlushAsync(_open.Token).ConfigureAwait(false);

                    _lastMessage.Dispose();
                    _lastMessage = null;
                }
                catch (OperationCanceledException) {
                    break;
                }
                catch (Exception e) {
                    ProxyEventSource.Log.StreamException(this, codec.Stream, e);
                    break;
                }
            }
        }