/// <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)); }