Пример #1
0
        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);
        }
Пример #2
0
        public static AmqpLinkSettings GetLinkSettings(bool forSender, string address, SettleMode settleType, int credit = 0, bool dynamic = false)
        {
            AmqpLinkSettings settings = null;

            // create a setting for sender
            settings = new AmqpLinkSettings();
            settings.LinkName = string.Format("link-{0}", Guid.NewGuid().ToString("N"));
            settings.Role = !forSender;

            Target target = new Target();
            target.Address = address;

            Source source = new Source();
            source.Address = address;
            source.DistributionMode = "move";

            settings.Source = source;
            settings.Target = target;
            settings.SettleType = settleType;

            if (!forSender)
            {
                settings.TotalLinkCredit = (uint)credit;
                settings.AutoSendFlow = credit > 0;
                if (dynamic)
                {
                    source.Address = null;
                    source.Dynamic = true;
                }
            }
            else
            {
                settings.InitialDeliveryCount = 0;
                if (dynamic)
                {
                    target.Address = null;
                    target.Dynamic = true;
                }
            }

            settings.AddProperty("x-opt-just-testing", "ignore me");

            return settings;
        }
Пример #3
0
        /// <summary>
        ///   Creates an AMQP link for use with publishing operations.
        /// </summary>
        /// <param name="entityPath">The entity path to send to.</param>
        /// <param name="connection">The active and opened AMQP connection to use for this link.</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 for operations related to receiving events.</returns>
        protected virtual async Task <SendingAmqpLink> CreateSendingLinkAsync(
            string entityPath,
            AmqpConnection connection,
            TimeSpan timeout,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var session   = default(AmqpSession);
            var stopWatch = ValueStopwatch.StartNew();

            try
            {
                string[] audience;
                Uri      destinationEndpoint = null;

                destinationEndpoint = new Uri(ServiceEndpoint, entityPath);
                audience            = new string[] { destinationEndpoint.AbsoluteUri };

                // Perform the initial authorization for the link.

                var authClaims = new[] { ServiceBusClaim.Send };

                DateTime authExpirationUtc = await RequestAuthorizationUsingCbsAsync(
                    connection,
                    TokenProvider,
                    destinationEndpoint,
                    audience,
                    authClaims,
                    timeout.CalculateRemaining(stopWatch.GetElapsedTime()))
                                             .ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the AMQP session associated with the link.

                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);

                await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the link.

                var linkSettings = new AmqpLinkSettings
                {
                    Role = false,
                    InitialDeliveryCount = 0,
                    Source = new Source {
                        Address = Guid.NewGuid().ToString()
                    },
                    Target = new Target {
                        Address = destinationEndpoint.AbsolutePath
                    }
                };

                linkSettings.AddProperty(AmqpClientConstants.TimeoutName, (uint)timeout.CalculateRemaining(stopWatch.GetElapsedTime()).TotalMilliseconds);

                var link = new SendingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{ Id };{ connection.Identifier }:{ session.Identifier }:{ link.Identifier }";
                link.AttachTo(session);

                // Configure refresh for authorization of the link.

                var refreshTimer = default(Timer);

                TimerCallback refreshHandler = CreateAuthorizationRefreshHandler
                                               (
                    entityPath,
                    connection,
                    link,
                    TokenProvider,
                    destinationEndpoint,
                    audience,
                    authClaims,
                    AuthorizationRefreshTimeout,
                    () => refreshTimer
                                               );

                refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan);

                // Track the link before returning it, so that it can be managed with the scope.

                BeginTrackingLinkAsActive(entityPath, link, refreshTimer);
                return(link);
            }
            catch (Exception exception)
            {
                // Aborting the session will perform any necessary cleanup of
                // the associated link as well.

                session?.Abort();
                ExceptionDispatchInfo.Capture(AmqpExceptionHelper.TranslateException(
                                                  exception,
                                                  null,
                                                  session.GetInnerException(),
                                                  connection.IsClosing()))
                .Throw();

                throw; // will never be reached
            }
        }
Пример #4
0
 public AmqpSendReceiveLinkCreator(string entityPath, ServiceBusConnection serviceBusConnection, Uri endpointAddress, string[] requiredClaims, ICbsTokenProvider cbsTokenProvider, AmqpLinkSettings linkSettings, string clientId)
     : base(entityPath, serviceBusConnection, endpointAddress, requiredClaims, cbsTokenProvider, linkSettings, clientId)
 {
 }
Пример #5
0
        /// <summary>
        ///   Creates an AMQP link for use with management operations.
        /// </summary>
        /// <param name="entityPath"></param>
        ///
        /// <param name="connection">The active and opened AMQP connection to use for this link.</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 management operations.</returns>
        protected virtual async Task <RequestResponseAmqpLink> CreateManagementLinkAsync(
            string entityPath,
            AmqpConnection connection,
            TimeSpan timeout,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var session   = default(AmqpSession);
            var stopWatch = ValueStopwatch.StartNew();

            try
            {
                // Create and open the AMQP session associated with the link.

                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);

                await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the link.

                var linkSettings = new AmqpLinkSettings();
                linkSettings.AddProperty(AmqpClientConstants.TimeoutName, (uint)timeout.CalculateRemaining(stopWatch.GetElapsedTime()).TotalMilliseconds);
                linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, AmqpClientConstants.EntityTypeManagement);
                entityPath += '/' + AmqpClientConstants.ManagementAddress;

                // Perform the initial authorization for the link.

                string[] claims            = { ServiceBusClaim.Manage, ServiceBusClaim.Listen, ServiceBusClaim.Send };
                var      endpoint          = new Uri(ServiceEndpoint, entityPath);
                var      audience          = new[] { endpoint.AbsoluteUri };
                DateTime authExpirationUtc = await RequestAuthorizationUsingCbsAsync(
                    connection,
                    TokenProvider,
                    ServiceEndpoint,
                    audience,
                    claims,
                    timeout.CalculateRemaining(stopWatch.GetElapsedTime()))
                                             .ConfigureAwait(false);

                var link = new RequestResponseAmqpLink(
                    AmqpClientConstants.EntityTypeManagement,
                    session,
                    entityPath,
                    linkSettings.Properties);
                linkSettings.LinkName = $"{connection.Settings.ContainerId};{connection.Identifier}:{session.Identifier}:{link.Identifier}";

                // Track the link before returning it, so that it can be managed with the scope.
                var refreshTimer = default(Timer);

                TimerCallback refreshHandler = CreateAuthorizationRefreshHandler
                                               (
                    entityPath,
                    connection,
                    link,
                    TokenProvider,
                    ServiceEndpoint,
                    audience,
                    claims,
                    AuthorizationRefreshTimeout,
                    () => (ActiveLinks.ContainsKey(link) ? refreshTimer : null)
                                               );

                refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan);

                // Track the link before returning it, so that it can be managed with the scope.

                BeginTrackingLinkAsActive(entityPath, link, refreshTimer);
                return(link);
            }
            catch (Exception exception)
            {
                // Aborting the session will perform any necessary cleanup of
                // the associated link as well.

                session?.Abort();
                ExceptionDispatchInfo.Capture(AmqpExceptionHelper.TranslateException(
                                                  exception,
                                                  null,
                                                  session.GetInnerException(),
                                                  connection.IsClosing()))
                .Throw();

                throw; // will never be reached
            }
        }
Пример #6
0
        /// <summary>
        ///   Creates an AMQP link for use with receiving operations.
        /// </summary>
        /// <param name="entityPath">The entity path to receive from.</param>
        /// <param name="connection">The active and opened AMQP connection to use for this link.</param>
        /// <param name="endpoint">The fully qualified endpoint to open the link for.</param>
        /// <param name="prefetchCount">Controls the number of events received and queued locally without regard to whether an operation was requested.</param>
        /// <param name="receiveMode">The <see cref="ReceiveMode"/> used to specify how messages are received. Defaults to PeekLock mode.</param>
        /// <param name="sessionId">The session to receive from.</param>
        /// <param name="isSessionReceiver">Whether or not this is a sessionful receiver.</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 for operations related to receiving events.</returns>
        protected virtual async Task <ReceivingAmqpLink> CreateReceivingLinkAsync(
            string entityPath,
            AmqpConnection connection,
            Uri endpoint,
            TimeSpan timeout,
            uint prefetchCount,
            ReceiveMode receiveMode,
            string sessionId,
            bool isSessionReceiver,
            CancellationToken cancellationToken)
        {
            Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var session   = default(AmqpSession);
            var stopWatch = ValueStopwatch.StartNew();

            try
            {
                // Perform the initial authorization for the link.

                string[] authClaims        = new string[] { ServiceBusClaim.Send };
                var      audience          = new[] { endpoint.AbsoluteUri };
                DateTime authExpirationUtc = await RequestAuthorizationUsingCbsAsync(
                    connection,
                    TokenProvider,
                    endpoint,
                    audience,
                    authClaims,
                    timeout.CalculateRemaining(stopWatch.GetElapsedTime())).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the AMQP session associated with the link.

                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };

                // This is the maximum number of unsettled transfers across all receive links on this session.
                // This will allow the session to accept unlimited number of transfers, even if the recevier(s)
                // are not settling any of the deliveries.
                sessionSettings.IncomingWindow = uint.MaxValue;

                session = connection.CreateSession(sessionSettings);

                await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                var filters = new FilterSet();

                // even if supplied sessionId is null, we need to add the Session filter if it is a session receiver
                if (isSessionReceiver)
                {
                    filters.Add(AmqpClientConstants.SessionFilterName, sessionId);
                }

                var linkSettings = new AmqpLinkSettings
                {
                    Role            = true,
                    TotalLinkCredit = prefetchCount,
                    AutoSendFlow    = prefetchCount > 0,
                    SettleType      = (receiveMode == ReceiveMode.PeekLock) ? SettleMode.SettleOnDispose : SettleMode.SettleOnSend,
                    Source          = new Source {
                        Address = endpoint.AbsolutePath, FilterSet = filters
                    },
                    Target = new Target {
                        Address = Guid.NewGuid().ToString()
                    }
                };

                var link = new ReceivingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{connection.Settings.ContainerId};{connection.Identifier}:{session.Identifier}:{link.Identifier}:{linkSettings.Source.ToString()}";

                link.AttachTo(session);

                // Configure refresh for authorization of the link.

                var refreshTimer = default(Timer);

                TimerCallback refreshHandler = CreateAuthorizationRefreshHandler
                                               (
                    entityPath,
                    connection,
                    link,
                    TokenProvider,
                    endpoint,
                    audience,
                    authClaims,
                    AuthorizationRefreshTimeout,
                    () => (ActiveLinks.ContainsKey(link) ? refreshTimer : null)
                                               );

                refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan);

                // Track the link before returning it, so that it can be managed with the scope.

                BeginTrackingLinkAsActive(entityPath, link, refreshTimer);
                return(link);
            }
            catch (Exception exception)
            {
                // Aborting the session will perform any necessary cleanup of
                // the associated link as well.

                session?.Abort();
                ExceptionDispatchInfo.Capture(AmqpExceptionHelper.TranslateException(
                                                  exception,
                                                  null,
                                                  session.GetInnerException(),
                                                  connection.IsClosing()))
                .Throw();

                throw; // will never be reached
            }
        }
Пример #7
0
        async Task <ReceivingAmqpLink> CreateLinkAsync(TimeSpan timeout)
        {
            var amqpEventHubClient = ((AmqpEventHubClient)this.EventHubClient);

            var            timeoutHelper = new TimeoutHelper(timeout);
            AmqpConnection connection    = await amqpEventHubClient.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

            // Authenticate over CBS
            var cbsLink = connection.Extensions.Find <AmqpCbsLink>();

            ICbsTokenProvider cbsTokenProvider = amqpEventHubClient.CbsTokenProvider;
            Uri    address   = new Uri(amqpEventHubClient.ConnectionStringBuilder.Endpoint, this.Path);
            string audience  = address.AbsoluteUri;
            string resource  = address.AbsoluteUri;
            var    expiresAt = await cbsLink.SendTokenAsync(cbsTokenProvider, address, audience, resource, new[] { ClaimConstants.Listen }, timeoutHelper.RemainingTime()).ConfigureAwait(false);

            AmqpSession session = null;

            try
            {
                // Create our Session
                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);
                await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                FilterSet filterMap = null;
                var       filters   = this.CreateFilters();
                if (filters != null && filters.Count > 0)
                {
                    filterMap = new FilterSet();
                    foreach (var filter in filters)
                    {
                        filterMap.Add(filter.DescriptorName, filter);
                    }
                }

                // Create our Link
                var linkSettings = new AmqpLinkSettings
                {
                    Role            = true,
                    TotalLinkCredit = (uint)this.PrefetchCount,
                    AutoSendFlow    = this.PrefetchCount > 0
                };
                linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, (int)MessagingEntityType.ConsumerGroup);
                linkSettings.Source = new Source {
                    Address = address.AbsolutePath, FilterSet = filterMap
                };
                linkSettings.Target = new Target {
                    Address = this.ClientId
                };
                linkSettings.SettleType = SettleMode.SettleOnSend;

                // Receiver metrics enabled?
                if (this.ReceiverRuntimeMetricEnabled)
                {
                    linkSettings.DesiredCapabilities = new Multiple <AmqpSymbol>(new List <AmqpSymbol>
                    {
                        AmqpClientConstants.EnableReceiverRuntimeMetricName
                    });
                }

                if (this.Epoch.HasValue)
                {
                    linkSettings.AddProperty(AmqpClientConstants.AttachEpoch, this.Epoch.Value);
                }

                if (!string.IsNullOrWhiteSpace(this.Identifier))
                {
                    linkSettings.AddProperty(AmqpClientConstants.ReceiverIdentifierName, this.Identifier);
                }

                var link = new ReceivingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{amqpEventHubClient.ContainerId};{connection.Identifier}:{session.Identifier}:{link.Identifier}";
                link.AttachTo(session);

                await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                var activeClientLink = new ActiveClientLink(
                    link,
                    audience,                                                         // audience
                    this.EventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri, // endpointUri
                    new[] { ClaimConstants.Listen },
                    true,
                    expiresAt);

                this.clientLinkManager.SetActiveLink(activeClientLink);

                return(link);
            }
            catch
            {
                // Cleanup any session (and thus link) in case of exception.
                session?.Abort();
                throw;
            }
        }
Пример #8
0
        async Task <SendingAmqpLink> CreateLinkAsync(TimeSpan timeout)
        {
            var amqpEventHubClient = ((AmqpEventHubClient)this.EventHubClient);

            var            timeoutHelper = new TimeoutHelper(timeout);
            AmqpConnection connection    = await amqpEventHubClient.ConnectionManager.GetOrCreateAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

            // Authenticate over CBS
            var cbsLink = connection.Extensions.Find <AmqpCbsLink>();

            ICbsTokenProvider cbsTokenProvider = amqpEventHubClient.CbsTokenProvider;
            Uri    address   = new Uri(amqpEventHubClient.ConnectionStringBuilder.Endpoint, this.Path);
            string audience  = address.AbsoluteUri;
            string resource  = address.AbsoluteUri;
            var    expiresAt = await cbsLink.SendTokenAsync(
                cbsTokenProvider,
                address,
                audience,
                resource,
                new[] { ClaimConstants.Send },
                timeoutHelper.RemainingTime()).ConfigureAwait(false);

            AmqpSession session = null;

            try
            {
                // Create our Session
                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);
                await session.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                // Create our Link
                var linkSettings = new AmqpLinkSettings();
                linkSettings.AddProperty(AmqpClientConstants.TimeoutName, (uint)timeoutHelper.RemainingTime().TotalMilliseconds);
                linkSettings.AddProperty(AmqpClientConstants.EntityTypeName, (int)MessagingEntityType.EventHub);
                linkSettings.Role = false;
                linkSettings.InitialDeliveryCount = 0;
                linkSettings.Target = new Target {
                    Address = address.AbsolutePath
                };
                linkSettings.Source = new Source {
                    Address = this.ClientId
                };

                var link = new SendingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{amqpEventHubClient.ContainerId};{connection.Identifier}:{session.Identifier}:{link.Identifier}";
                link.AttachTo(session);

                await link.OpenAsync(timeoutHelper.RemainingTime()).ConfigureAwait(false);

                var activeClientLink = new ActiveClientLink(
                    link,
                    audience,                                                         // audience
                    this.EventHubClient.ConnectionStringBuilder.Endpoint.AbsoluteUri, // endpointUri
                    new[] { ClaimConstants.Send },
                    true,
                    expiresAt);

                this.MaxMessageSize = (long)activeClientLink.Link.Settings.MaxMessageSize();
                this.clientLinkManager.SetActiveLink(activeClientLink);
                return(link);
            }
            catch
            {
                // Cleanup any session (and thus link) in case of exception.
                session?.Abort();
                throw;
            }
        }
Пример #9
0
        /// <summary>
        ///   Creates an AMQP link for use with publishing operations.
        /// </summary>
        ///
        /// <param name="connection">The active and opened AMQP connection to use for this link.</param>
        /// <param name="endpoint">The fully qualified endpoint to open the link for.</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 for operations related to receiving events.</returns>
        ///
        protected virtual async Task <SendingAmqpLink> CreateSendingLinkAsync(AmqpConnection connection,
                                                                              Uri endpoint,
                                                                              TimeSpan timeout,
                                                                              CancellationToken cancellationToken)
        {
            Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var session   = default(AmqpSession);
            var stopWatch = Stopwatch.StartNew();

            try
            {
                // Perform the initial authorization for the link.

                var authClaims        = new[] { EventHubsClaim.Send };
                var authExpirationUtc = await RequestAuthorizationUsingCbsAsync(connection, TokenProvider, endpoint, endpoint.AbsoluteUri, endpoint.AbsoluteUri, authClaims, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the AMQP session associated with the link.

                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);

                await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the link.

                var linkSettings = new AmqpLinkSettings
                {
                    Role = false,
                    InitialDeliveryCount = 0,
                    Source = new Source {
                        Address = Guid.NewGuid().ToString()
                    },
                    Target = new Target {
                        Address = endpoint.AbsolutePath
                    }
                };

                linkSettings.AddProperty(AmqpProperty.Timeout, (uint)timeout.CalculateRemaining(stopWatch.Elapsed).TotalMilliseconds);
                linkSettings.AddProperty(AmqpProperty.EntityType, (int)AmqpProperty.Entity.EventHub);

                var link = new SendingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{ Id };{ connection.Identifier }:{ session.Identifier }:{ link.Identifier }";
                link.AttachTo(session);

                stopWatch.Stop();

                // Configure refresh for authorization of the link.

                var refreshTimer = default(Timer);

                var refreshHandler = CreateAuthorizationRefreshHandler
                                     (
                    connection,
                    link,
                    TokenProvider,
                    endpoint,
                    endpoint.AbsoluteUri,
                    endpoint.AbsoluteUri,
                    authClaims,
                    AuthorizationRefreshTimeout,
                    () => refreshTimer
                                     );

                refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan);

                // Track the link before returning it, so that it can be managed with the scope.

                BeginTrackingLinkAsActive(link, refreshTimer);
                return(link);
            }
            catch
            {
                // Aborting the session will perform any necessary cleanup of
                // the associated link as well.

                session?.Abort();
                throw;
            }
        }
        private static async Task <AmqpIoTReceivingLink> OpenReceivingAmqpLinkAsync(
            DeviceIdentity deviceIdentity,
            AmqpSession amqpSession,
            byte?senderSettleMode,
            byte?receiverSettleMode,
            string deviceTemplate,
            string moduleTemplate,
            string linkSuffix,
            string correlationId,
            TimeSpan timeout
            )
        {
            if (Logging.IsEnabled)
            {
                Logging.Enter(typeof(AmqpIoTSession), deviceIdentity, $"{nameof(OpenReceivingAmqpLinkAsync)}");
            }

            uint prefetchCount = deviceIdentity.AmqpTransportSettings.PrefetchCount;

            AmqpLinkSettings amqpLinkSettings = new AmqpLinkSettings
            {
                LinkName        = linkSuffix,
                Role            = true,
                TotalLinkCredit = prefetchCount,
                AutoSendFlow    = prefetchCount > 0,
                Source          = new Source()
                {
                    Address = BuildLinkAddress(deviceIdentity, deviceTemplate, moduleTemplate)
                },
                Target = new Target()
                {
                    Address = deviceIdentity.IotHubConnectionString.DeviceId
                }
            };

            amqpLinkSettings.SndSettleMode = senderSettleMode;
            amqpLinkSettings.RcvSettleMode = receiverSettleMode;
            amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.TimeoutName, timeout.TotalMilliseconds);
            amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ClientVersion, deviceIdentity.ProductInfo.ToString());
            amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ApiVersion, ClientApiVersionHelper.ApiVersionString);
            if (correlationId != null)
            {
                amqpLinkSettings.AddProperty(AmqpIoTErrorAdapter.ChannelCorrelationId, correlationId);
            }

            try
            {
                ReceivingAmqpLink receivingLink = new ReceivingAmqpLink(amqpLinkSettings);
                receivingLink.AttachTo(amqpSession);
                await receivingLink.OpenAsync(timeout).ConfigureAwait(false);

                return(new AmqpIoTReceivingLink(receivingLink));
            }
            catch (Exception e) when(!e.IsFatal())
            {
                Exception ex = AmqpIoTExceptionAdapter.ConvertToIoTHubException(e, amqpSession);

                if (ReferenceEquals(e, ex))
                {
                    throw;
                }
                else
                {
                    if (ex is AmqpIoTResourceException)
                    {
                        amqpSession.SafeClose();
                        throw new IotHubCommunicationException(ex.Message, ex);
                    }
                    throw ex;
                }
            }
            finally
            {
                if (Logging.IsEnabled)
                {
                    Logging.Exit(typeof(AmqpIoTSession), deviceIdentity, $"{nameof(OpenReceivingAmqpLinkAsync)}");
                }
            }
        }
Пример #11
0
        /// <summary>
        ///   Creates an AMQP link for use with receiving operations.
        /// </summary>
        ///
        /// <param name="connection">The active and opened AMQP connection to use for this link.</param>
        /// <param name="endpoint">The fully qualified endpoint to open the link for.</param>
        /// <param name="eventPosition">The position of the event in the partition where the link should be filtered to.</param>
        /// <param name="consumerOptions">The set of active options for the consumer that will make use of the link.</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 for operations related to receiving events.</returns>
        ///
        protected virtual async Task <ReceivingAmqpLink> CreateReceivingLinkAsync(AmqpConnection connection,
                                                                                  Uri endpoint,
                                                                                  EventPosition eventPosition,
                                                                                  EventHubConsumerClientOptions consumerOptions,
                                                                                  TimeSpan timeout,
                                                                                  CancellationToken cancellationToken)
        {
            Argument.AssertNotDisposed(IsDisposed, nameof(AmqpConnectionScope));
            cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

            var session   = default(AmqpSession);
            var stopWatch = Stopwatch.StartNew();

            try
            {
                // Perform the initial authorization for the link.

                var authClaims        = new[] { EventHubsClaim.Listen };
                var authExpirationUtc = await RequestAuthorizationUsingCbsAsync(connection, TokenProvider, endpoint, endpoint.AbsoluteUri, endpoint.AbsoluteUri, authClaims, timeout.CalculateRemaining(stopWatch.Elapsed)).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the AMQP session associated with the link.

                var sessionSettings = new AmqpSessionSettings {
                    Properties = new Fields()
                };
                session = connection.CreateSession(sessionSettings);

                await OpenAmqpObjectAsync(session, timeout).ConfigureAwait(false);

                cancellationToken.ThrowIfCancellationRequested <TaskCanceledException>();

                // Create and open the link.

                var filters = new FilterSet();
                filters.Add(AmqpFilter.ConsumerFilterName, AmqpFilter.CreateConsumerFilter(AmqpFilter.BuildFilterExpression(eventPosition)));

                var linkSettings = new AmqpLinkSettings
                {
                    Role            = true,
                    TotalLinkCredit = (uint)consumerOptions.PrefetchCount,
                    AutoSendFlow    = consumerOptions.PrefetchCount > 0,
                    SettleType      = SettleMode.SettleOnSend,
                    Source          = new Source {
                        Address = endpoint.AbsolutePath, FilterSet = filters
                    },
                    Target = new Target {
                        Address = Guid.NewGuid().ToString()
                    }
                };

                linkSettings.AddProperty(AmqpProperty.EntityType, (int)AmqpProperty.Entity.ConsumerGroup);

                if (consumerOptions.OwnerLevel.HasValue)
                {
                    linkSettings.AddProperty(AmqpProperty.OwnerLevel, consumerOptions.OwnerLevel.Value);
                }

                if (consumerOptions.TrackLastEnqueuedEventInformation)
                {
                    linkSettings.DesiredCapabilities = new Multiple <AmqpSymbol>(new List <AmqpSymbol>
                    {
                        AmqpProperty.TrackLastEnqueuedEventInformation
                    });
                }

                var link = new ReceivingAmqpLink(linkSettings);
                linkSettings.LinkName = $"{ Id };{ connection.Identifier }:{ session.Identifier }:{ link.Identifier }";
                link.AttachTo(session);

                stopWatch.Stop();

                // Configure refresh for authorization of the link.

                var refreshTimer = default(Timer);

                var refreshHandler = CreateAuthorizationRefreshHandler
                                     (
                    connection,
                    link,
                    TokenProvider,
                    endpoint,
                    endpoint.AbsoluteUri,
                    endpoint.AbsoluteUri,
                    authClaims,
                    AuthorizationRefreshTimeout,
                    () => refreshTimer
                                     );

                refreshTimer = new Timer(refreshHandler, null, CalculateLinkAuthorizationRefreshInterval(authExpirationUtc), Timeout.InfiniteTimeSpan);

                // Track the link before returning it, so that it can be managed with the scope.

                BeginTrackingLinkAsActive(link, refreshTimer);
                return(link);
            }
            catch
            {
                // Aborting the session will perform any necessary cleanup of
                // the associated link as well.

                session?.Abort();
                throw;
            }
        }
Пример #12
0
        public async Task <SendingAmqpLink> CreateSendingLinkAsync(
            string path,
            IotHubConnectionString connectionString,
            string corrId,
            SendingLinkType linkType,
            TimeSpan timeout,
            ProductInfo productInfo,
            CancellationToken cancellationToken)
        {
            try
            {
                if (Logging.IsEnabled)
                {
                    Logging.Enter(this, corrId, linkType, $"{nameof(IotHubConnection)}.{nameof(CreateSendingLinkAsync)}");
                }

                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);
            }
            finally
            {
                if (Logging.IsEnabled)
                {
                    Logging.Exit(this, corrId, linkType, $"{nameof(IotHubConnection)}.{nameof(CreateSendingLinkAsync)}");
                }
            }
        }
Пример #13
0
 AmqpLinkSettings SetLinkSettingsCommonPropertiesForTwin(AmqpLinkSettings linkSettings, string corrId)
 {
     linkSettings.AddProperty(IotHubAmqpProperty.ApiVersion, ClientApiVersionHelper.ApiVersionString);
     linkSettings.AddProperty(IotHubAmqpProperty.ChannelCorrelationId, "twin:" + corrId);
     return(linkSettings);
 }
Пример #14
0
 protected static AmqpLinkSettings SetLinkSettingsCommonPropertiesForMethod(AmqpLinkSettings linkSettings, string corrId)
 {
     linkSettings.AddProperty(IotHubAmqpProperty.ApiVersion, ClientApiVersionHelper.ApiVersionString);
     linkSettings.AddProperty(IotHubAmqpProperty.ChannelCorrelationId, "methods:" + corrId);
     return(linkSettings);
 }
Пример #15
0
        public async Task <ReceivingAmqpLink> CreateReceivingLinkAsync(
            string path,
            IotHubConnectionString connectionString,
            string corrId,
            ReceivingLinkType linkType,
            uint prefetchCount,
            TimeSpan timeout,
            ProductInfo productInfo,
            CancellationToken cancellationToken)
        {
            try
            {
                if (Logging.IsEnabled)
                {
                    Logging.Enter(this, corrId, linkType, $"{nameof(IotHubConnection)}.{nameof(CreateReceivingLinkAsync)}");
                }

                this.OnCreateReceivingLink(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            = true,
                    TotalLinkCredit = prefetchCount,
                    AutoSendFlow    = prefetchCount > 0,
                    Source          = new Source()
                    {
                        Address = linkAddress.AbsoluteUri
                    },
                    LinkName = Guid.NewGuid().ToString("N") // Use a human readable link name to help with debuggin
                };

                switch (linkType)
                {
                // Exactly once
                case ReceivingLinkType.C2DMessages:
                    linkSettings.SndSettleMode = null;     // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire)
                    linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.Second;
                    break;

                // At least once
                case ReceivingLinkType.Events:
                    linkSettings.SndSettleMode = null;     // SenderSettleMode.Unsettled (null as it is the default and to avoid bytes on the wire)
                    linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.First;
                    break;

                // At most once
                case ReceivingLinkType.Methods:
                case ReceivingLinkType.Twin:
                    linkSettings.SndSettleMode = (byte)SenderSettleMode.Settled;
                    linkSettings.RcvSettleMode = (byte)ReceiverSettleMode.First;
                    break;
                }

                SetLinkSettingsCommonProperties(linkSettings, timeoutHelper.RemainingTime(), productInfo);
                if (linkType == ReceivingLinkType.Methods)
                {
                    SetLinkSettingsCommonPropertiesForMethod(linkSettings, corrId);
                }
                else if (linkType == ReceivingLinkType.Twin)
                {
                    SetLinkSettingsCommonPropertiesForTwin(linkSettings, corrId);
                }

                var link = new ReceivingAmqpLink(linkSettings);
                link.AttachTo(session);

                var audience = this.BuildAudience(connectionString, path);
                await this.OpenLinkAsync(link, connectionString, audience, timeoutHelper.RemainingTime(), cancellationToken).ConfigureAwait(false);

                return(link);
            }
            finally
            {
                if (Logging.IsEnabled)
                {
                    Logging.Exit(this, corrId, linkType, $"{nameof(IotHubConnection)}.{nameof(CreateReceivingLinkAsync)}");
                }
            }
        }