/// <summary>
 /// Invoke method on proxy
 /// </summary>
 /// <param name="proxy"></param>
 /// <param name="request"></param>
 /// <param name="ct"></param>
 /// <returns></returns>
 public async Task <Message> CallAsync(INameRecord proxy, Message request, TimeSpan timeout,
                                       CancellationToken ct)
 {
     using (var invoker = new IoTHubInvoker(_hubConnectionString)) {
         return(await invoker.CallAsync(proxy, request, timeout, ct));
     }
 }
        /// <summary>
        /// Create send action block.
        /// </summary>
        private void CreateSendBlock()
        {
            _sender = new IoTHubInvoker(_hubConnectionString);
            _send   = new ActionBlock <Message>(async(message) => {
                if (message.TypeId != MessageContent.Data)
                {
                    // No sending of anything but data
                    return;
                }
                message.Source = _streamId;
                message.Target = _remoteId;
                try {
                    ((DataMessage)message.Content).SequenceNumber = _nextSendSequenceNumber++;

                    //
                    // Try send - exceptions except for proxynotfound (proxy gone!) are retried
                    // 20 times with exponential increase (3 ms), or until send timeout expires.
                    //
                    var response = await _sender.TryCallWithRetryAsync(
                        _link, message, TimeSpan.FromMilliseconds(_pollTimeout * 2),
                        kMaxSendAttempts, _open.Token).ConfigureAwait(false);

                    if (!_open.IsCancellationRequested)
                    {
                        if (response.Error != (int)SocketError.Success)
                        {
                            throw new SocketException("Failure during send.",
                                                      (SocketError)response.Error);
                        }
                        if (response.TypeId != MessageContent.Poll)
                        {
                            await _receive.SendAsync(response).ConfigureAwait(false);
                        }
                    }
                }
                catch (OperationCanceledException) {
                }
                catch (Exception e) {
                    ProxyEventSource.Log.HandledExceptionAsError(this, e);
                    throw;
                }
                finally {
                    message.Dispose();
                }
            },
                                                new ExecutionDataflowBlockOptions {
                NameFormat                = "Send (in Stream) Id={1}",
                EnsureOrdered             = true,
                BoundedCapacity           = 1,
                MaxDegreeOfParallelism    = 1,
                MaxMessagesPerTask        = DataflowBlockOptions.Unbounded,
                CancellationToken         = _open.Token,
                SingleProducerConstrained = true
            });
        }
        /// <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));
        }