private RabbitMQQueue BindSubscriptionQueue(TopicName topicName, Uri publisherUri, string subscriptionQueueName, CancellationToken cancellationToken)
        {
            var       publisherTopicExchange = topicName.GetTopicExchangeName();
            var       attempts    = 0;
            const int maxAttempts = 10;
            var       retryDelay  = TimeSpan.FromSeconds(5);

            while (!cancellationToken.IsCancellationRequested)
            {
                try
                {
                    using (var connection = _connectionManager.GetConnection(publisherUri))
                        using (var channel = connection.CreateModel())
                        {
                            attempts++;
                            channel.ExchangeDeclarePassive(publisherTopicExchange);

                            var subscriptionQueue = new RabbitMQQueue(connection,
                                                                      subscriptionQueueName, this, _encoding, _defaultQueueOptions, _diagnosticService, _securityTokenService, null);

                            subscriptionQueue.Init();

                            channel.QueueBind(subscriptionQueueName, publisherTopicExchange, "", null);

                            _diagnosticService.Emit(
                                new RabbitMQEventBuilder(this, RabbitMQEventType.RabbitMQQueueBound)
                            {
                                Detail        = "Subscription queue bound to topic exchange",
                                Queue         = subscriptionQueueName,
                                Exchange      = publisherTopicExchange,
                                Topic         = topicName,
                                ChannelNumber = channel.ChannelNumber
                            }.Build());

                            return(subscriptionQueue);
                        }
                }
                catch (Exception ex)
                {
                    if (attempts >= maxAttempts)
                    {
                        throw;
                    }

                    _diagnosticService.Emit(
                        new RabbitMQEventBuilder(this, RabbitMQEventType.RabbitMQQueueBindError)
                    {
                        Detail    = "Error binding subscription queue to topic exchange (attempt " + attempts + " of " + maxAttempts + ").  Retrying in " + retryDelay,
                        Queue     = subscriptionQueueName,
                        Exchange  = publisherTopicExchange,
                        Topic     = topicName,
                        Exception = ex
                    }.Build());

                    Task.Delay(retryDelay, cancellationToken).Wait(cancellationToken);
                }
            }

            throw new OperationCanceledException();
        }
        /// <inheritdoc />
        /// <summary>
        /// Establishes a named queue
        /// </summary>
        /// <param name="queueName">The name of the queue</param>
        /// <param name="listener">An object that will receive messages off of the queue for processing</param>
        /// <param name="options">(Optional) Options that govern how the queue behaves</param>
        /// <param name="cancellationToken">(Optional) A cancellation token that can be used
        /// by the caller to cancel queue creation if necessary</param>
        /// <returns>Returns a task that will complete when the queue has been created</returns>
        /// <exception cref="T:System.ArgumentNullException">Thrown if <paramref name="queueName" /> or
        /// <paramref name="listener" /> is <c>null</c></exception>
        /// <exception cref="T:Platibus.QueueAlreadyExistsException">Thrown if a queue with the specified
        /// name already exists</exception>
        public Task CreateQueue(QueueName queueName, IQueueListener listener, QueueOptions options = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckDisposed();
            var connection = _connectionManager.GetConnection(_uri);
            var queue      = new RabbitMQQueue(connection, queueName,
                                               listener, _encoding, options ?? _defaultQueueOptions, _diagnosticService, _securityTokenService, _messageEncryptionService);

            if (!_queues.TryAdd(queueName, queue))
            {
                throw new QueueAlreadyExistsException(queueName);
            }

            queue.Init();
            return(Task.FromResult(true));
        }
        public Task CreateQueue(QueueName queueName, IQueueListener listener, QueueOptions options = default(QueueOptions), CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckDisposed();
            var connection = _connectionManager.GetConnection(_uri);
            var queue = new RabbitMQQueue(queueName, listener, connection, _encoding, options);
            if (!_queues.TryAdd(queueName, queue))
            {
                throw new QueueAlreadyExistsException(queueName);
            }

            Log.DebugFormat("Initializing RabbitMQ queue \"{0}\"", queueName);
            queue.Init();
            Log.DebugFormat("RabbitMQ queue \"{0}\" created successfully", queueName);

            return Task.FromResult(true);
        }
        /// <summary>
        /// Initializes a new <see cref="RabbitMQTransportService"/>
        /// </summary>
        /// <param name="options">The options that govern the configuration and behavior of the
        /// RabbitMQ transport</param>
        public RabbitMQTransportService(RabbitMQTransportServiceOptions options)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            _baseUri              = options.BaseUri;
            _connectionManager    = options.ConnectionManager;
            _diagnosticService    = options.DiagnosticService ?? DiagnosticService.DefaultInstance;
            _messageJournal       = options.MessageJournal;
            _securityTokenService = options.SecurityTokenService ?? new JwtSecurityTokenService();
            _encoding             = options.Encoding ?? Encoding.GetEncoding(RabbitMQDefaults.Encoding);
            _defaultQueueOptions  = options.DefaultQueueOptions ?? new QueueOptions();

            var connection = _connectionManager.GetConnection(_baseUri);
            var topics     = (options.Topics ?? Enumerable.Empty <TopicName>()).Where(t => t != null);

            using (var channel = connection.CreateModel())
            {
                foreach (var topicName in topics)
                {
                    var exchangeName = topicName.GetTopicExchangeName();
                    channel.ExchangeDeclare(exchangeName, "fanout", _defaultQueueOptions.IsDurable, false, new Dictionary <string, object>());
                    _diagnosticService.Emit(
                        new RabbitMQEventBuilder(this, RabbitMQEventType.RabbitMQExchangeDeclared)
                    {
                        Detail        = "Fanout exchange declared for topic",
                        Exchange      = exchangeName,
                        Topic         = topicName,
                        ChannelNumber = channel.ChannelNumber
                    }.Build());
                }
            }

            _inboundQueue = new RabbitMQQueue(connection, InboxQueueName, this,
                                              _encoding, _defaultQueueOptions, _diagnosticService, _securityTokenService, null);

            _inboundQueue.Init();
        }