public override async Task OpenAsync(CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, cancellationToken, $"{nameof(OpenAsync)}"); } try { cancellationToken.ThrowIfCancellationRequested(); await _amqpUnit.OpenAsync(_operationTimeout).ConfigureAwait(false); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { Exception newException = AmqpClientHelper.ToIotHubClientContract(exception); if (newException != exception) { throw newException; } else { // Maintain the original stack. throw; } } finally { if (Logging.IsEnabled) { Logging.Exit(this, cancellationToken, $"{nameof(OpenAsync)}"); } } }
public override async Task SendTwinPatchAsync(TwinCollection reportedProperties, CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, reportedProperties, cancellationToken, $"{nameof(SendTwinPatchAsync)}"); } try { await EnableTwinPatchAsync(cancellationToken).ConfigureAwait(false); var body = JsonConvert.SerializeObject(reportedProperties); var bodyStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(body)); var amqpMessage = AmqpMessage.Create(bodyStream, true); amqpMessage.MessageAnnotations.Map["operation"] = "PATCH"; amqpMessage.MessageAnnotations.Map["resource"] = "/properties/reported"; amqpMessage.MessageAnnotations.Map["version"] = null; var response = await RoundTripTwinMessage(amqpMessage, cancellationToken).ConfigureAwait(false); VerifyResponseMessage(response); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } finally { if (Logging.IsEnabled) { Logging.Exit(this, reportedProperties, cancellationToken, $"{nameof(SendTwinPatchAsync)}"); } } }
public override async Task <Twin> SendTwinGetAsync(CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, cancellationToken, $"{nameof(SendTwinGetAsync)}"); } try { await EnableTwinPatchAsync(cancellationToken).ConfigureAwait(false); AmqpMessage amqpMessage = AmqpMessage.Create(); amqpMessage.MessageAnnotations.Map["operation"] = "GET"; var response = await RoundTripTwinMessage(amqpMessage, cancellationToken).ConfigureAwait(false); return(TwinFromResponse(response)); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } finally { if (Logging.IsEnabled) { Logging.Exit(this, cancellationToken, $"{nameof(SendTwinGetAsync)}"); } } }
public override async Task EnableTwinPatchAsync(CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, cancellationToken, $"{nameof(EnableTwinPatchAsync)}"); } try { cancellationToken.ThrowIfCancellationRequested(); await _amqpUnit.EnsureTwinLinksAreOpenedAsync(_operationTimeout).ConfigureAwait(false); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } finally { if (Logging.IsEnabled) { Logging.Exit(this, cancellationToken, $"{nameof(EnableTwinPatchAsync)}"); } } }
public override async Task <Message> ReceiveAsync(TimeSpan timeout, CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, timeout, cancellationToken, $"{nameof(ReceiveAsync)}"); } Message message = null; while (true) { cancellationToken.ThrowIfCancellationRequested(); try { message = await _amqpUnit.ReceiveMessageAsync(timeout).ConfigureAwait(false); if (message != null) { break; } } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } } if (Logging.IsEnabled) { Logging.Exit(this, timeout, cancellationToken, $"{nameof(ReceiveAsync)}"); } return(message); }
private async Task DisposeMessageAsync(string lockToken, Outcome outcome, CancellationToken cancellationToken) { Outcome disposeOutcome; try { // Currently, the same mechanism is used for sending feedback for C2D messages and events received by modules. // However, devices only support C2D messages (they cannot receive events), and modules only support receiving events // (they cannot receive C2D messages). So we use this to distinguish whether to dispose the message (i.e. send outcome on) // the DeviceBoundReceivingLink or the EventsReceivingLink. // If this changes (i.e. modules are able to receive C2D messages, or devices are able to receive telemetry), this logic // will have to be updated. disposeOutcome = await _amqpUnit.DisposeMessageAsync(lockToken, outcome, _operationTimeout).ConfigureAwait(false); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } if (disposeOutcome.DescriptorCode != Accepted.Code) { if (disposeOutcome.DescriptorCode == Rejected.Code) { var rejected = (Rejected)disposeOutcome; // Special treatment for NotFound amqp rejected error code in case of DisposeMessage if (rejected.Error != null && rejected.Error.Condition.Equals(AmqpErrorCode.NotFound)) { Error error = new Error { Condition = IotHubAmqpErrorCode.MessageLockLostError }; throw AmqpErrorMapper.ToIotHubClientContract(error); } } throw AmqpErrorMapper.GetExceptionFromOutcome(disposeOutcome); } }