public async Task <SendingAmqpLink> CreateSendingLinkAsync(string path, TimeSpan timeout) { var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session; if (!_faultTolerantSession.TryGetOpenedObject(out session)) { session = await _faultTolerantSession.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); } var linkAddress = ConnectionString.BuildLinkAddress(path); var linkSettings = new AmqpLinkSettings { Role = false, InitialDeliveryCount = 0, Target = new Target { Address = linkAddress.AbsoluteUri }, SndSettleMode = null, // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) RcvSettleMode = null, // (byte)ReceiverSettleMode.First (null as it is the default and to avoid bytes on the wire) LinkName = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture), // Use a human readable link name to help with debugging }; SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime()); var link = new SendingAmqpLink(linkSettings); link.AttachTo(session); await OpenLinkAsync(link, timeoutHelper.RemainingTime()).ConfigureAwait(false); return(link); }
private async Task EnableSendingLinkAsync(CancellationToken cancellationToken) { SendingAmqpLink methodSendingLink = await this.GetMethodSendingLinkAsync(cancellationToken); this.SafeAddClosedSendingLinkHandler = this.linkClosedListener; methodSendingLink.SafeAddClosed((o, ea) => this.SafeAddClosedSendingLinkHandler(o, ea)); }
/// <summary> /// Opens an AMQP link for use with producer operations. /// </summary> /// <param name="entityPath"></param> /// <param name="viaEntityPath">The entity path to route the message through. Useful when using transactions.</param> /// <param name="timeout">The timeout to apply when creating the link.</param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// /// <returns>A link for use with producer operations.</returns> /// public virtual async Task <SendingAmqpLink> OpenSenderLinkAsync( string entityPath, string viaEntityPath, TimeSpan timeout, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); var stopWatch = Stopwatch.StartNew(); AmqpConnection connection = await ActiveConnection.GetOrCreateAsync(timeout).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); SendingAmqpLink link = await CreateSendingLinkAsync( entityPath, viaEntityPath, connection, timeout.CalculateRemaining(stopWatch.Elapsed), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); await OpenAmqpObjectAsync(link, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); stopWatch.Stop(); return(link); }
public DuplexAmqpLink(AmqpSession session, AmqpLinkSettings settings) : base("duplex") { AmqpTrace.Provider.AmqpLogOperationInformational(this, TraceOperation.Create, "Create"); var senderSettings = new AmqpLinkSettings { Role = false, LinkName = settings.LinkName + ":out", SettleType = settings.SettleType, Source = new Source(), TotalLinkCredit = settings.TotalLinkCredit, AutoSendFlow = settings.AutoSendFlow, Target = settings.Target, Properties = settings.Properties }; this.sender = new SendingAmqpLink(session, senderSettings); var receiverSettings = new AmqpLinkSettings { Role = true, LinkName = settings.LinkName + ":in", SettleType = settings.SettleType, Source = settings.Source, TotalLinkCredit = settings.TotalLinkCredit, AutoSendFlow = settings.AutoSendFlow, Target = new Target(), Properties = settings.Properties }; this.receiver = new ReceivingAmqpLink(session, receiverSettings); this.receiver.SetTotalLinkCredit(receiverSettings.TotalLinkCredit, true); // WHY set both here AND on settings? Follow up with Xin. this.sender.SafeAddClosed(this.OnLinkClosed); this.receiver.SafeAddClosed(this.OnLinkClosed); }
public async override Task SendAsync(string deviceId, Message message, TimeSpan?timeout = null) { if (string.IsNullOrWhiteSpace(deviceId)) { throw new ArgumentNullException(nameof(deviceId)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } timeout ??= OperationTimeout; using AmqpMessage amqpMessage = message.ToAmqpMessage(); amqpMessage.Properties.To = "/devices/" + WebUtility.UrlEncode(deviceId) + "/messages/deviceBound"; try { SendingAmqpLink sendingLink = await GetSendingLinkAsync().ConfigureAwait(false); Outcome outcome = await sendingLink .SendMessageAsync(amqpMessage, IotHubConnection.GetNextDeliveryTag(ref _sendingDeliveryTag), AmqpConstants.NullBinary, timeout.Value) .ConfigureAwait(false); if (outcome.DescriptorCode != Accepted.Code) { throw AmqpErrorMapper.GetExceptionFromOutcome(outcome); } } catch (Exception ex) when(!(ex is TimeoutException) && !ex.IsFatal()) { throw AmqpClientHelper.ToIotHubClientContract(ex); } }
async Task <SendingAmqpLink> CreateTwinSendingLinkAsync(TimeSpan timeout, CancellationToken cancellationToken) { string path = this.BuildPath(CommonConstants.DeviceTwinPathTemplate, CommonConstants.ModuleTwinPathTemplate); SendingAmqpLink twinSendingLink = await this.IotHubConnection.CreateSendingLinkAsync(path, this.iotHubConnectionString, this.twinConnectionCorrelationId, IotHubConnection.SendingLinkType.Twin, timeout, this.productInfo, cancellationToken).ConfigureAwait(false); MyStringCopy(twinSendingLink.Name, out twinSendingLinkName); twinSendingLink.SafeAddClosed(async(o, ea) => await Task.Run(async() => { foreach (var entry in twinResponseCompletions) { TaskCompletionSource <AmqpMessage> task; if (this.twinResponseCompletions.TryRemove(entry.Key, out task)) { task.SetCanceled(); } OnAmqpConnectionClose(o, ea); } } ).ConfigureAwait(false)); return(twinSendingLink); }
/// <summary> /// Creates the AMQP link to be used for producer-related operations and ensures /// that the corresponding state for the producer has been updated based on the link /// configuration. /// </summary> /// /// <param name="timeout">The timeout to apply when creating the link.</param> /// <param name="cancellationToken">The cancellation token to consider when creating the link.</param> /// /// <returns>The AMQP link to use for producer-related operations.</returns> /// /// <remarks> /// This method will modify class-level state, setting those attributes that depend on the AMQP /// link configuration. There exists a benign race condition in doing so, as there may be multiple /// concurrent callers. In this case, the attributes may be set multiple times but the resulting /// value will be the same. /// </remarks> /// protected virtual async Task <SendingAmqpLink> CreateLinkAndEnsureSenderStateAsync( TimeSpan timeout, CancellationToken cancellationToken) { SendingAmqpLink link = await _connectionScope.OpenSenderLinkAsync( _entityPath, timeout, cancellationToken).ConfigureAwait(false); if (!MaximumMessageSize.HasValue) { // This delay is necessary to prevent the link from causing issues for subsequent // operations after creating a batch. Without it, operations using the link consistently // timeout. The length of the delay does not appear significant, just the act of introducing // an asynchronous delay. // // For consistency the value used by the legacy Service Bus client has been brought forward and // used here. await Task.Delay(15, cancellationToken).ConfigureAwait(false); MaximumMessageSize = (long)link.Settings.MaxMessageSize; } return(link); }
async Task <SendingAmqpLink> CreateTwinSendingLinkAsync(TimeSpan timeout, CancellationToken cancellationToken) { string path = string.Format(CultureInfo.InvariantCulture, CommonConstants.DeviceTwinPathTemplate, System.Net.WebUtility.UrlEncode(this.deviceId)); SendingAmqpLink twinSendingLink = await this.IotHubConnection.CreateSendingLinkAsync(path, this.iotHubConnectionString, this.twinConnectionCorrelationId, IotHubConnection.SendingLinkType.Twin, timeout, cancellationToken); MyStringCopy(twinSendingLink.Name, out twinSendingLinkName); this.SafeAddClosedTwinSendingLinkHandler = this.linkClosedListener; twinSendingLink.SafeAddClosed(async(o, ea) => await Task.Run(async() => { await this.SafeAddClosedTwinSendingLinkHandler( o, new ConnectionEventArgs { ConnectionType = ConnectionType.AmqpTwinSending, ConnectionStatus = ConnectionStatus.Disconnected_Retrying, ConnectionStatusChangeReason = ConnectionStatusChangeReason.No_Network }); foreach (var entry in twinResponseCompletions) { TaskCompletionSource <AmqpMessage> task; if (this.twinResponseCompletions.TryRemove(entry.Key, out task)) { task.SetCanceled(); } } } )); return(twinSendingLink); }
private async Task <AmqpMessage> RoundTripTwinMessage(AmqpMessage amqpMessage, CancellationToken cancellationToken) { string correlationId = Guid.NewGuid().ToString(); AmqpMessage response = null; try { Outcome outcome; SendingAmqpLink eventSendingLink = await this.GetTwinSendingLinkAsync(cancellationToken); amqpMessage.Properties.CorrelationId = correlationId; this.twinResponseCompletions[correlationId] = new TaskCompletionSource <AmqpMessage>(); outcome = await eventSendingLink.SendMessageAsync(amqpMessage, new ArraySegment <byte>(Guid.NewGuid().ToByteArray()), AmqpConstants.NullBinary, this.operationTimeout); if (outcome.DescriptorCode != Accepted.Code) { throw AmqpErrorMapper.GetExceptionFromOutcome(outcome); } response = await this.twinResponseCompletions[correlationId].Task; } finally { TaskCompletionSource <AmqpMessage> throwAway; this.twinResponseCompletions.TryRemove(correlationId, out throwAway); } return(response); }
public AmqpLink CreateLink(AmqpSession session, AmqpLinkSettings settings) { bool isReceiver = settings.Role.Value; AmqpLink link; if (isReceiver) { if (settings.Target is Target && ((Target)settings.Target).Dynamic()) { string name = string.Format("$dynamic.{0}", Interlocked.Increment(ref this.dynamicId)); this.queues.Add(name, new TestQueue(this)); ((Target)settings.Target).Address = name; } link = new ReceivingAmqpLink(session, settings); } else { if (((Source)settings.Source).Dynamic()) { string name = string.Format("$dynamic.{0}", Interlocked.Increment(ref this.dynamicId)); this.queues.Add(name, new TestQueue(this)); ((Source)settings.Source).Address = name; } link = new SendingAmqpLink(session, settings); } return(link); }
async Task <Outcome> SendAmqpMethodResponseAsync(AmqpMessage amqpMessage, CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, amqpMessage, cancellationToken, $"{nameof(AmqpTransportHandler)}.{nameof(SendAmqpMethodResponseAsync)}"); } Outcome outcome; try { SendingAmqpLink methodRespSendingLink = await this.GetMethodSendingLinkAsync(cancellationToken).ConfigureAwait(false); outcome = await methodRespSendingLink.SendMessageAsync(amqpMessage, new ArraySegment <byte>(Guid.NewGuid().ToByteArray()), AmqpConstants.NullBinary, this.operationTimeout).ConfigureAwait(false); } catch (Exception exception) when(!exception.IsFatal() && !(exception is OperationCanceledException)) { throw AmqpClientHelper.ToIotHubClientContract(exception); } finally { if (Logging.IsEnabled) { Logging.Exit(this, amqpMessage, cancellationToken, $"{nameof(AmqpTransportHandler)}.{nameof(SendAmqpMethodResponseAsync)}"); } } return(outcome); }
public async Task DisableMethodsAsync(TimeSpan timeout) { if (Logging.IsEnabled) Logging.Enter(this, timeout, $"{nameof(DisableMethodsAsync)}"); Debug.Assert(_methodSendingLink != null); Debug.Assert(_methodReceivingLink != null); try { ICollection<Task> tasks = new List<Task>(); if (_methodReceivingLink != null) { tasks.Add(_methodReceivingLink.CloseAsync(timeout)); } if (_methodSendingLink != null) { tasks.Add(_methodSendingLink.CloseAsync(timeout)); } if (tasks.Count > 0) { await Task.WhenAll(tasks).ConfigureAwait(false); _methodReceivingLink = null; _methodSendingLink = null; } } finally { if (Logging.IsEnabled) Logging.Exit(this, timeout, $"{nameof(DisableMethodsAsync)}"); } }
public override async Task <Twin> SendTwinGetAsync(CancellationToken cancellationToken) { Outcome outcome; try { await EnableTwinAsync(cancellationToken); SendingAmqpLink eventSendingLink = await this.GetTwinSendingLinkAsync(cancellationToken); // This is test code and will be re-written in future commits AmqpMessage getTwinMessage = AmqpMessage.Create(); string getCorrelationId = Guid.NewGuid().ToString(); getTwinMessage.Properties.CorrelationId = getCorrelationId; getTwinMessage.MessageAnnotations.Map["operation"] = "GET"; outcome = await eventSendingLink.SendMessageAsync(getTwinMessage, new ArraySegment <byte>(Guid.NewGuid().ToByteArray()), AmqpConstants.NullBinary, this.operationTimeout); } catch (Exception exception) { if (exception.IsFatal()) { throw; } throw AmqpClientHelper.ToIotHubClientContract(exception); } return(null); }
public async Task<SendingAmqpLink> CreateSendingLinkAsync(string path, IotHubConnectionString connectionString, TimeSpan timeout) { this.OnCreateSendingLink(connectionString); var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session; if (!this.FaultTolerantSession.TryGetOpenedObject(out session)) { session = await this.FaultTolerantSession.GetOrCreateAsync(timeoutHelper.RemainingTime()); } var linkAddress = this.BuildLinkAddress(connectionString, path); var linkSettings = new AmqpLinkSettings() { Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = linkAddress.AbsoluteUri }, SndSettleMode = null, // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) RcvSettleMode = null, // (byte)ReceiverSettleMode.First (null as it is the default and to avoid bytes on the wire) LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debugging }; SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime()); var link = new SendingAmqpLink(linkSettings); link.AttachTo(session); var audience = this.BuildAudience(connectionString, path); await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime()); return link; }
// This call is executed over AMQP. public override async Task SendAsync(string deviceId, string moduleId, Message message) { Logging.Enter(this, $"Sending message with Id [{message?.MessageId}] for device {deviceId}, module {moduleId}", nameof(SendAsync)); if (string.IsNullOrWhiteSpace(deviceId)) { throw new ArgumentNullException(nameof(deviceId)); } if (string.IsNullOrWhiteSpace(moduleId)) { throw new ArgumentNullException(nameof(moduleId)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (_clientOptions?.SdkAssignsMessageId == SdkAssignsMessageId.WhenUnset && message.MessageId == null) { message.MessageId = Guid.NewGuid().ToString(); } if (message.IsBodyCalled) { message.ResetBody(); } using AmqpMessage amqpMessage = MessageConverter.MessageToAmqpMessage(message); amqpMessage.Properties.To = "/devices/" + WebUtility.UrlEncode(deviceId) + "/modules/" + WebUtility.UrlEncode(moduleId) + "/messages/deviceBound"; try { SendingAmqpLink sendingLink = await GetSendingLinkAsync().ConfigureAwait(false); Outcome outcome = await sendingLink .SendMessageAsync( amqpMessage, IotHubConnection.GetNextDeliveryTag(ref _sendingDeliveryTag), AmqpConstants.NullBinary, OperationTimeout) .ConfigureAwait(false); Logging.Info(this, $"Outcome was: {outcome?.DescriptorName}", nameof(SendAsync)); if (outcome.DescriptorCode != Accepted.Code) { throw AmqpErrorMapper.GetExceptionFromOutcome(outcome); } } catch (Exception ex) when(!ex.IsFatal()) { Logging.Error(this, $"{nameof(SendAsync)} threw an exception: {ex}", nameof(SendAsync)); throw AmqpClientHelper.ToIotHubClientContract(ex); } finally { Logging.Exit(this, $"Sending message with Id [{message?.MessageId}] for device {deviceId}, module {moduleId}", nameof(SendAsync)); } }
async Task <SendingAmqpLink> CreateLinkAsync(TimeSpan timeout) { MessagingEventSource.Log.AmqpSendLinkCreateStart(this.ClientId, this.EntityType, this.Path); AmqpLinkSettings linkSettings = new AmqpLinkSettings { Role = false, InitialDeliveryCount = 0, Target = new Target { Address = this.Path }, Source = new Source { Address = this.ClientId }, }; if (this.EntityType != null) { linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, (int)this.EntityType); } AmqpSendReceiveLinkCreator sendReceiveLinkCreator = new AmqpSendReceiveLinkCreator(this.Path, this.ServiceBusConnection, new[] { ClaimConstants.Send }, this.CbsTokenProvider, linkSettings); SendingAmqpLink sendingAmqpLink = (SendingAmqpLink)await sendReceiveLinkCreator.CreateAndOpenAmqpLinkAsync().ConfigureAwait(false); MessagingEventSource.Log.AmqpSendLinkCreateStop(this.ClientId); return(sendingAmqpLink); }
protected override async Task OnSendAsync(IEnumerable <BrokeredMessage> brokeredMessages) { TimeoutHelper timeoutHelper = new TimeoutHelper(this.OperationTimeout, true); using (AmqpMessage amqpMessage = AmqpMessageConverter.BrokeredMessagesToAmqpMessage(brokeredMessages, true)) { SendingAmqpLink amqpLink = await this.SendLinkManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false); if (amqpLink.Settings.MaxMessageSize.HasValue) { ulong size = (ulong)amqpMessage.SerializedMessageSize; if (size > amqpLink.Settings.MaxMessageSize.Value) { // TODO: Add MessageSizeExceededException throw new NotImplementedException("MessageSizeExceededException: " + Resources.AmqpMessageSizeExceeded.FormatForUser(amqpMessage.DeliveryId.Value, size, amqpLink.Settings.MaxMessageSize.Value)); ////throw Fx.Exception.AsError(new MessageSizeExceededException( ////Resources.AmqpMessageSizeExceeded.FormatForUser(amqpMessage.DeliveryId.Value, size, amqpLink.Settings.MaxMessageSize.Value))); } } Outcome outcome = await amqpLink.SendMessageAsync(amqpMessage, this.GetNextDeliveryTag(), AmqpConstants.NullBinary, timeoutHelper.RemainingTime()).ConfigureAwait(false); if (outcome.DescriptorCode != Accepted.Code) { Rejected rejected = (Rejected)outcome; throw Fx.Exception.AsError(AmqpExceptionHelper.ToMessagingContract(rejected.Error)); } } }
public AmqpLink CreateLink(AmqpSession session, AmqpLinkSettings settings) { AmqpLink link; if (settings.Role.Value) { var receiver = new ReceivingAmqpLink(session, settings); receiver.RegisterMessageListener(m => { this.messages.Enqueue(m.Clone()); receiver.AcceptMessage(m, true, true); m.Dispose(); }); link = receiver; } else { var sender = new SendingAmqpLink(session, settings); sender.RegisterCreditListener((credit, drain, tx) => { AmqpMessage message = this.messages.Dequeue(); message.DeliveryAnnotations.Map["x-opt-sequence-number"] = 1; sender.SendMessageNoWait(message, EmptyBinary, NullBinary); }); sender.RegisterDispositionListener(d => { sender.DisposeDelivery(d, true, d.State); }); link = sender; } return(link); }
public async Task EnsureTwinLinksAreOpenedAsync(TimeSpan timeout) { if (Volatile.Read(ref _twinLinksOpened) == true) return; if (Logging.IsEnabled) Logging.Enter(this, timeout, $"{nameof(EnsureTwinLinksAreOpenedAsync)}"); try { await _twinLinksLock.WaitAsync().ConfigureAwait(false); if (_twinLinksOpened) return; Debug.Assert(_twinSendingLink == null); Debug.Assert(_twinReceivingLink == null); string correlationIdSuffix = Guid.NewGuid().ToString(); Task<ReceivingAmqpLink> receiveLinkCreator = AmqpLinkHelper.OpenTwinReceiverLinkAsync( _deviceIdentity, _amqpSession, correlationIdSuffix, timeout); Task<SendingAmqpLink> sendingLinkCreator = AmqpLinkHelper.OpenTwinSenderLinkAsync( _deviceIdentity, _amqpSession, correlationIdSuffix, timeout); await Task.WhenAll(receiveLinkCreator, sendingLinkCreator).ConfigureAwait(false); _twinSendingLink = sendingLinkCreator.Result; _twinSendingLink.Closed += OnLinkDisconnected; _twinReceivingLink = receiveLinkCreator.Result; _twinReceivingLink.RegisterMessageListener(OnDesiredPropertyReceived); _twinReceivingLink.Closed += OnLinkDisconnected; _twinLinksOpened = true; if (Logging.IsEnabled) Logging.Associate(this, this, _twinReceivingLink, $"{nameof(EnsureTwinLinksAreOpenedAsync)}"); if (Logging.IsEnabled) Logging.Associate(this, this, _twinSendingLink, $"{nameof(EnsureTwinLinksAreOpenedAsync)}"); } catch (Exception ex) when (!ex.IsFatal()) { _twinReceivingLink?.Abort(); _twinSendingLink?.Abort(); _twinReceivingLink = null; _twinSendingLink = null; throw; } finally { _twinLinksLock.Release(); if (Logging.IsEnabled) Logging.Exit(this, timeout, $"{nameof(EnsureTwinLinksAreOpenedAsync)}"); } }
private async Task EnableMethodSendingLinkAsync(CancellationToken cancellationToken) { SendingAmqpLink methodSendingLink = await this.GetMethodSendingLinkAsync(cancellationToken); this.SafeAddClosedMethodSendingLinkHandler = this.linkClosedListener; methodSendingLink.SafeAddClosed((o, ea) => this.SafeAddClosedMethodSendingLinkHandler(o, new ConnectionEventArgs { ConnectionKey = ConnectionKeys.AmqpMessaging, ConnectionStatus = ConnectionStatus.Disconnected_Retrying })); }
AmqpLink ILinkFactory.CreateLink(AmqpSession session, AmqpLinkSettings settings) { try { this.ValidateLinkSettings(settings); // Override AmqpLinkSetting MaxMessageSize to restrict it to Constants.AmqpMaxMessageSize if (settings.MaxMessageSize == null || settings.MaxMessageSize == 0 || settings.MaxMessageSize > Constants.AmqpMaxMessageSize) { settings.MaxMessageSize = Constants.AmqpMaxMessageSize; } AmqpLink amqpLink; IAmqpLink wrappingAmqpLink; string linkAddress; if (settings.IsReceiver()) { amqpLink = new ReceivingAmqpLink(session, settings); wrappingAmqpLink = new EdgeReceivingAmqpLink((ReceivingAmqpLink)amqpLink); linkAddress = ((Target)settings.Target).Address.ToString(); } else { amqpLink = new SendingAmqpLink(session, settings); wrappingAmqpLink = new EdgeSendingAmqpLink((SendingAmqpLink)amqpLink); linkAddress = ((Source)settings.Source).Address.ToString(); } // TODO: implement the rules below // Link address may be of the forms: // // amqp[s]://my.servicebus.windows.net/a/b <-- FQ address where host name should match connection remote host name // amqp[s]:a/b <-- path relative to hostname specified in OPEN // a/b <-- pre-global addressing style path relative to hostname specified in OPEN // /a/b <-- same as above Uri linkUri; if (!linkAddress.StartsWith(Constants.AmqpsScheme, StringComparison.OrdinalIgnoreCase)) { string host = session.Connection.Settings.RemoteHostName; linkUri = new Uri("amqps://" + host + linkAddress.EnsureStartsWith('/')); } else { linkUri = new Uri(linkAddress, UriKind.RelativeOrAbsolute); } ILinkHandler linkHandler = this.linkHandlerProvider.Create(wrappingAmqpLink, linkUri); amqpLink.Settings.AddProperty(LinkHandlerPropertyKey, linkHandler); return(amqpLink); } catch (Exception e) when(!ExceptionEx.IsFatal(e)) { // Don't throw here because we cannot provide error info. Instead delay and throw from Link.Open. return(new FaultedLink(e, session, settings)); } }
public Consumer(TestQueue queue, SendingAmqpLink link, int id) { this.queue = queue; this.link = link; this.id = id; this.link.Closed += new EventHandler(link_Closed); this.link.RegisterCreditListener(this.OnCredit); this.link.RegisterDispositionListener(this.OnDispose); }
private async Task EnableTwinSendingLinkAsync(CancellationToken cancellationToken) { SendingAmqpLink twinSendingLink = await this.GetTwinSendingLinkAsync(cancellationToken); this.SafeAddClosedTwinSendingLinkHandler = this.linkClosedListener; twinSendingLink.SafeAddClosed((o, ea) => this.SafeAddClosedTwinSendingLinkHandler(o, new ConnectionEventArgs { ConnectionKey = ConnectionKeys.AmqpTwinSending, ConnectionStatus = ConnectionStatus.Disconnected_Retrying, ConnectionStatusChangeReason = ConnectionStatusChangeReason.No_Network })); }
public async Task<SendingAmqpLink> CreateSendingLinkAsync( string path, IotHubConnectionString connectionString, string corrId, SendingLinkType linkType, TimeSpan timeout, ProductInfo productInfo, CancellationToken cancellationToken) { this.OnCreateSendingLink(connectionString); var timeoutHelper = new TimeoutHelper(timeout); AmqpSession session = await this.GetSessionAsync(timeoutHelper, cancellationToken).ConfigureAwait(false); var linkAddress = this.BuildLinkAddress(connectionString, path); var linkSettings = new AmqpLinkSettings() { Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = linkAddress.AbsoluteUri }, LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debugging }; switch (linkType) { case SendingLinkType.TelemetryEvents: linkSettings.SndSettleMode = null; // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire) linkSettings.RcvSettleMode = null; // (byte)ReceiverSettleMode.First (null as it is the default and to avoid bytes on the wire) break; case SendingLinkType.Methods: case SendingLinkType.Twin: linkSettings.SndSettleMode = (byte)SenderSettleMode.Settled; linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.First; break; } SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime(), productInfo); if (linkType == SendingLinkType.Methods) { SetLinkSettingsCommonPropertiesForMethod(linkSettings, corrId); } else if (linkType == SendingLinkType.Twin) { SetLinkSettingsCommonPropertiesForTwin(linkSettings, corrId); } var link = new SendingAmqpLink(linkSettings); link.AttachTo(session); var audience = this.BuildAudience(connectionString, path); await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime(), cancellationToken).ConfigureAwait(false); return link; }
async Task <SendingAmqpLink> CreateMethodSendingLinkAsync(TimeSpan timeout, CancellationToken cancellationToken) { string path = this.BuildPath(CommonConstants.DeviceMethodPathTemplate, CommonConstants.ModuleMethodPathTemplate); SendingAmqpLink methodSendingLink = await this.IotHubConnection.CreateSendingLinkAsync(path, this.iotHubConnectionString, this.methodConnectionCorrelationId, IotHubConnection.SendingLinkType.Methods, timeout, this.productInfo, cancellationToken).ConfigureAwait(false); MyStringCopy(methodSendingLink.Name, out methodSendingLinkName); methodSendingLink.SafeAddClosed(OnAmqpConnectionClose); return(methodSendingLink); }
public void AmqpWebSocketTransportTest() { string address = "ws://localhost:28088"; var broker = new TestAmqpBroker(new string[] { address }, null, null, null); try { broker.Start(); string queue = "AmqpWebSocketTransportTest"; broker.AddQueue(queue); AmqpConnection connection = AmqpConnection.Factory.OpenConnectionAsync(address).GetAwaiter().GetResult(); AmqpSession session = connection.CreateSession(new AmqpSessionSettings()); session.Open(); SendingAmqpLink sLink = new SendingAmqpLink(session, AmqpUtils.GetLinkSettings(true, queue, SettleMode.SettleOnSend)); sLink.Open(); int messageCount = 100; for (int i = 0; i < messageCount; i++) { AmqpMessage message = AmqpMessage.Create(new AmqpValue() { Value = "message" + i }); sLink.SendMessageAsync(message, AmqpConstants.EmptyBinary, AmqpConstants.NullBinary, TimeSpan.FromSeconds(10)).Wait(); } sLink.Close(); ReceivingAmqpLink rLink = new ReceivingAmqpLink(session, AmqpUtils.GetLinkSettings(false, queue, SettleMode.SettleOnReceive, 100)); rLink.Open(); for (int i = 0; i < messageCount; i++) { AmqpMessage message2 = rLink.ReceiveMessageAsync(TimeSpan.FromSeconds(60)).GetAwaiter().GetResult(); Assert.NotNull(message2); rLink.AcceptMessage(message2, false); message2.Dispose(); } rLink.Close(); connection.Close(); } finally { broker.Stop(); } }
internal static async Task <Outcome> SendAmqpMessageAsync( SendingAmqpLink sendingAmqpLink, AmqpMessage message, TimeSpan timeout) { return(await sendingAmqpLink.SendMessageAsync( message, new ArraySegment <byte>(Guid.NewGuid().ToByteArray()), AmqpConstants.NullBinary, timeout ).ConfigureAwait(false)); }
private async Task <AmqpMessage> RoundTripTwinMessage(AmqpMessage amqpMessage, CancellationToken cancellationToken) { if (Logging.IsEnabled) { Logging.Enter(this, amqpMessage, cancellationToken, $"{nameof(AmqpTransportHandler)}.{nameof(RoundTripTwinMessage)}"); } string correlationId = Guid.NewGuid().ToString(); AmqpMessage response = null; try { Outcome outcome; SendingAmqpLink eventSendingLink = await this.GetTwinSendingLinkAsync(cancellationToken).ConfigureAwait(false); amqpMessage.Properties.CorrelationId = correlationId; var taskCompletionSource = new TaskCompletionSource <AmqpMessage>(); this.twinResponseCompletions[correlationId] = taskCompletionSource; outcome = await eventSendingLink.SendMessageAsync(amqpMessage, new ArraySegment <byte>(Guid.NewGuid().ToByteArray()), AmqpConstants.NullBinary, this.operationTimeout).ConfigureAwait(false); if (outcome.DescriptorCode != Accepted.Code) { throw AmqpErrorMapper.GetExceptionFromOutcome(outcome); } var receivingTask = taskCompletionSource.Task; if (await Task.WhenAny(receivingTask, Task.Delay(TimeSpan.FromSeconds(ResponseTimeoutInSeconds))).ConfigureAwait(false) == receivingTask) { // Task completed within timeout. // Consider that the task may have faulted or been canceled. // We re-await the task so that any exceptions/cancellation is rethrown. response = await receivingTask.ConfigureAwait(false); } else { // Timeout happen throw new TimeoutException(); } } finally { TaskCompletionSource <AmqpMessage> throwAway; this.twinResponseCompletions.TryRemove(correlationId, out throwAway); if (Logging.IsEnabled) { Logging.Exit(this, amqpMessage, cancellationToken, $"{nameof(AmqpTransportHandler)}.{nameof(RoundTripTwinMessage)}"); } } return(response); }
internal static async Task <SendingAmqpLink> OpenSendingAmqpLinkAsync( DeviceIdentity deviceIdentity, AmqpSession amqpSession, byte?senderSettleMode, byte?receiverSettleMode, string deviceTemplate, string moduleTemplate, string linkSuffix, string CorrelationId, TimeSpan timeout ) { if (Logging.IsEnabled) { Logging.Enter(typeof(AmqpLinkHelper), deviceIdentity, $"{nameof(OpenSendingAmqpLinkAsync)}"); } AmqpLinkSettings amqpLinkSettings = new AmqpLinkSettings { LinkName = CommonResources.GetNewStringGuid(linkSuffix), Role = false, InitialDeliveryCount = 0, Target = new Target() { Address = BuildLinkAddress(deviceIdentity, deviceTemplate, moduleTemplate) }, Source = new Source() { Address = deviceIdentity.IotHubConnectionString.DeviceId } }; amqpLinkSettings.SndSettleMode = senderSettleMode; amqpLinkSettings.RcvSettleMode = receiverSettleMode; amqpLinkSettings.AddProperty(IotHubAmqpProperty.TimeoutName, timeout.TotalMilliseconds); amqpLinkSettings.AddProperty(IotHubAmqpProperty.ClientVersion, deviceIdentity.ProductInfo.ToString()); amqpLinkSettings.AddProperty(IotHubAmqpProperty.ApiVersion, ClientApiVersionHelper.ApiVersionString); if (CorrelationId != null) { amqpLinkSettings.AddProperty(IotHubAmqpProperty.ChannelCorrelationId, CorrelationId); } SendingAmqpLink sendingLink = new SendingAmqpLink(amqpLinkSettings); sendingLink.AttachTo(amqpSession); await sendingLink.OpenAsync(timeout).ConfigureAwait(false); if (Logging.IsEnabled) { Logging.Exit(typeof(AmqpLinkHelper), deviceIdentity, $"{nameof(OpenSendingAmqpLinkAsync)}"); } return(sendingLink); }
async Task <SendingAmqpLink> CreateTwinSendingLinkAsync(TimeSpan timeout, CancellationToken cancellationToken) { string path = string.Format(CultureInfo.InvariantCulture, CommonConstants.DeviceTwinPathTemplate, System.Net.WebUtility.UrlEncode(this.deviceId)); SendingAmqpLink twinSendingLink = await this.IotHubConnection.CreateSendingLinkAsync(path, this.iotHubConnectionString, this.deviceId, IotHubConnection.SendingLinkType.Twin, timeout, cancellationToken); this.SafeAddClosedTwinSendingLinkHandler = this.linkClosedListener; twinSendingLink.SafeAddClosed((o, ea) => this.SafeAddClosedTwinSendingLinkHandler(o, new ConnectionEventArgs { ConnectionType = ConnectionType.AmqpTwinSending, ConnectionStatus = ConnectionStatus.Disconnected_Retrying, ConnectionStatusChangeReason = ConnectionStatusChangeReason.No_Network })); return(twinSendingLink); }
public async Task EnableMethodsAsync(TimeSpan timeout) { if (Logging.IsEnabled) Logging.Enter(this, timeout, $"{nameof(EnableMethodsAsync)}"); try { Debug.Assert(_methodSendingLink == null); Debug.Assert(_methodReceivingLink == null); string correlationIdSuffix = Guid.NewGuid().ToString(); Task<ReceivingAmqpLink> receiveLinkCreator = AmqpLinkHelper.OpenMethodsReceiverLinkAsync( _deviceIdentity, _amqpSession, correlationIdSuffix, timeout); Task<SendingAmqpLink> sendingLinkCreator = AmqpLinkHelper.OpenMethodsSenderLinkAsync( _deviceIdentity, _amqpSession, correlationIdSuffix, timeout); await Task.WhenAll(receiveLinkCreator, sendingLinkCreator).ConfigureAwait(false); _methodReceivingLink = receiveLinkCreator.Result; _methodSendingLink = sendingLinkCreator.Result; _methodReceivingLink.RegisterMessageListener(OnMethodReceived); _methodSendingLink.Closed += OnLinkDisconnected; _methodReceivingLink.Closed += OnLinkDisconnected; if (Logging.IsEnabled) Logging.Associate(this, _methodReceivingLink, $"{nameof(_methodReceivingLink)}"); if (Logging.IsEnabled) Logging.Associate(this, _methodSendingLink, $"{nameof(_methodSendingLink)}"); } catch (Exception) { _methodReceivingLink?.Abort(); _methodReceivingLink = null; _methodSendingLink?.Abort(); _methodSendingLink = null; throw; } finally { if (Logging.IsEnabled) Logging.Exit(this, timeout, $"{nameof(EnableMethodsAsync)}"); } }
/// <summary> /// Sends a set of messages to the associated Queue/Topic using a batched approach. /// </summary> /// /// <param name="messageFactory"></param> /// <param name="timeout"></param> /// <param name="cancellationToken">An optional <see cref="CancellationToken"/> instance to signal the request to cancel the operation.</param> /// internal virtual async Task SendBatchInternalAsync( Func <AmqpMessage> messageFactory, TimeSpan timeout, CancellationToken cancellationToken) { var stopWatch = Stopwatch.StartNew(); using (AmqpMessage batchMessage = messageFactory()) { string messageHash = batchMessage.GetHashCode().ToString(); ArraySegment <byte> transactionId = AmqpConstants.NullBinary; Transaction ambientTransaction = Transaction.Current; if (ambientTransaction != null) { transactionId = await AmqpTransactionManager.Instance.EnlistAsync( ambientTransaction, _connectionScope, timeout).ConfigureAwait(false); } SendingAmqpLink link = await _sendLink.GetOrCreateAsync(UseMinimum(_connectionScope.SessionTimeout, timeout)).ConfigureAwait(false); // Validate that the message is not too large to send. This is done after the link is created to ensure // that the maximum message size is known, as it is dictated by the service using the link. if (batchMessage.SerializedMessageSize > MaxMessageSize) { throw new ServiceBusException(string.Format(Resources.MessageSizeExceeded, messageHash, batchMessage.SerializedMessageSize, MaxMessageSize, _entityPath), ServiceBusException.FailureReason.MessageSizeExceeded); } // Attempt to send the message batch. var deliveryTag = new ArraySegment <byte>(BitConverter.GetBytes(Interlocked.Increment(ref _deliveryCount))); Outcome outcome = await link.SendMessageAsync( batchMessage, deliveryTag, transactionId, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); if (outcome.DescriptorCode != Accepted.Code) { throw (outcome as Rejected)?.Error.ToMessagingContractException(); } cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>(); stopWatch.Stop(); } }
public IAsyncResult BeginOpen(AmqpSession session, TimeSpan timeout, AsyncCallback callback, object state) { string uniqueueName = Guid.NewGuid().ToString("N"); Source source = new Source(); source.Address = uniqueueName; source.DistributionMode = DistributionMode.Move; Coordinator coordinator = new Coordinator(); AmqpLinkSettings settings = new AmqpLinkSettings(); settings.Source = source; settings.Target = coordinator; settings.LinkName = uniqueueName; settings.Role = false; this.sendLink = new SendingAmqpLink(session, settings); return this.sendLink.BeginOpen(timeout, callback, state); }
public DuplexAmqpLink(SendingAmqpLink sender, ReceivingAmqpLink receiver) : base("duplex") { AmqpTrace.Provider.AmqpLogOperationInformational(this, TraceOperation.Create, "Create"); this.sender = sender; this.receiver = receiver; this.sender.SafeAddClosed(this.OnLinkClosed); this.receiver.SafeAddClosed(this.OnLinkClosed); // TODO: ////if (this.sender.State != AmqpObjectState.Opened) ////{ //// this.SafeClose(); //// throw Fx.Exception.AsWarning(new ArgumentException("Sender wasn't open", "sender")); ////} ////if (this.receiver.State != AmqpObjectState.Opened) ////{ //// this.SafeClose(); //// throw Fx.Exception.AsWarning(new ArgumentException("Reciever wasn't open", "receiver")); ////} }
public AmqpLink CreateLink(AmqpSession session, AmqpLinkSettings settings) { bool isReceiver = settings.Role.Value; AmqpLink link; if (isReceiver) { if (settings.Target is Target && ((Target)settings.Target).Dynamic()) { string name = string.Format("$dynamic.{0}", Interlocked.Increment(ref this.dynamicId)); this.queues.Add(name, new TestQueue(this)); ((Target)settings.Target).Address = name; } link = new ReceivingAmqpLink(session, settings); } else { if (((Source)settings.Source).Dynamic()) { string name = string.Format("$dynamic.{0}", Interlocked.Increment(ref this.dynamicId)); this.queues.Add(name, new TestQueue(this)); ((Source)settings.Source).Address = name; } link = new SendingAmqpLink(session, settings); } return link; }
public void EndClose(IAsyncResult result) { this.sendLink.EndClose(result); this.sendLink = null; }