/// <summary>
        /// Builds a <see cref="IMessagingHubConnection">connection</see> with the configured parameters
        /// </summary>
        /// <returns>An inactive connection with the Messaging Hub. Call <see cref="IMessagingHubConnection.ConnectAsync"/> to activate it</returns>
        public IMessagingHubConnection Build()
        {
            var channelBuilder = ClientChannelBuilder.Create(() => _transportFactory.Create(EndPoint), EndPoint)
                                 .WithSendTimeout(SendTimeout)
                                 .WithEnvelopeBufferSize(ChannelBuffer)
                                 .AddCommandModule(c => new ReplyPingChannelModule(c));

            channelBuilder =
                channelBuilder
                .AddBuiltHandler(
                    (c, t) =>
            {
                if (Throughput > 0)
                {
                    ThroughputControlChannelModule.CreateAndRegister(c, Throughput);
                }

                return(Task.CompletedTask);
            })
                .AddBuiltHandler(
                    (c, t) =>
            {
                if (ChannelCount > 1)
                {
                    FillEnvelopeRecipientsChannelModule.CreateAndRegister(c);
                }

                return(Task.CompletedTask);
            });


            var establishedClientChannelBuilder = new EstablishedClientChannelBuilder(channelBuilder)
                                                  .WithIdentity(Identity)
                                                  .WithAuthentication(GetAuthenticationScheme())
                                                  .WithCompression(Compression)
                                                  .AddEstablishedHandler(SetPresenceAsync)
                                                  .AddEstablishedHandler(SetReceiptAsync)
                                                  .WithEncryption(Encryption);

            if (Instance != null)
            {
                establishedClientChannelBuilder = establishedClientChannelBuilder.WithInstance(Instance);
            }

            var onDemandClientChannelFactory = new OnDemandClientChannelFactory(establishedClientChannelBuilder);

            return(new MessagingHubConnection(SendTimeout, MaxConnectionRetries, onDemandClientChannelFactory, ChannelCount));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates a new instance of ChannelBase
        /// </summary>
        /// <param name="transport">The transport.</param>
        /// <param name="sendTimeout">The channel send timeout.</param>
        /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param>
        /// <param name="closeTimeout">The channel close timeout.</param>
        /// <param name="envelopeBufferSize">Size of the envelope buffer.</param>
        /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param>
        /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param>
        /// <param name="remotePingInterval">The interval to ping the remote party.</param>
        /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param>
        /// <param name="channelCommandProcessor">The channel command processor.</param>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="System.ArgumentException">
        /// Invalid send timeout
        /// or
        /// Invalid consume timeout
        /// or
        /// Invalid close timeout
        /// </exception>
        /// <exception cref="System.ArgumentOutOfRangeException"></exception>
        protected ChannelBase(
            ITransport transport,
            TimeSpan sendTimeout,
            TimeSpan?consumeTimeout,
            TimeSpan closeTimeout,
            int envelopeBufferSize,
            bool fillEnvelopeRecipients,
            bool autoReplyPings,
            TimeSpan?remotePingInterval,
            TimeSpan?remoteIdleTimeout,
            IChannelCommandProcessor channelCommandProcessor)
        {
            if (sendTimeout == default(TimeSpan))
            {
                throw new ArgumentException("Invalid send timeout", nameof(sendTimeout));
            }
            if (consumeTimeout != null && consumeTimeout.Value == default(TimeSpan))
            {
                throw new ArgumentException("Invalid consume timeout", nameof(consumeTimeout));
            }
            if (closeTimeout == default(TimeSpan))
            {
                throw new ArgumentException("Invalid close timeout", nameof(closeTimeout));
            }
            if (envelopeBufferSize <= 0)
            {
                envelopeBufferSize = DataflowBlockOptions.Unbounded;
            }
            Transport          = transport ?? throw new ArgumentNullException(nameof(transport));
            Transport.Closing += Transport_Closing;
            _sendTimeout       = sendTimeout;
            _consumeTimeout    = consumeTimeout;
            _closeTimeout      = closeTimeout;
            _consumerCts       = new CancellationTokenSource();
            _syncRoot          = new object();
            var dataflowBlockOptions = new ExecutionDataflowBlockOptions()
            {
                BoundedCapacity        = envelopeBufferSize,
                MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded,
                EnsureOrdered          = false
            };

            _transportBuffer           = new BufferBlock <Envelope>(dataflowBlockOptions);
            _messageConsumerBlock      = new TransformBlock <Envelope, Message>(e => ConsumeMessageAsync(e), dataflowBlockOptions);
            _commandConsumerBlock      = new TransformBlock <Envelope, Command>(e => ConsumeCommandAsync(e), dataflowBlockOptions);
            _notificationConsumerBlock = new TransformBlock <Envelope, Notification>(e => ConsumeNotificationAsync(e), dataflowBlockOptions);
            _sessionConsumerBlock      = new TransformBlock <Envelope, Session>(e => ConsumeSession(e), dataflowBlockOptions);
            _messageBuffer             = new BufferBlock <Message>(dataflowBlockOptions);
            _commandBuffer             = new BufferBlock <Command>(dataflowBlockOptions);
            _notificationBuffer        = new BufferBlock <Notification>(dataflowBlockOptions);
            _sessionBuffer             = new BufferBlock <Session>(dataflowBlockOptions);
            _drainEnvelopeBlock        = DataflowBlock.NullTarget <Envelope>();
            _transportBuffer.LinkTo(_messageConsumerBlock, PropagateCompletionLinkOptions, e => e is Message);
            _transportBuffer.LinkTo(_commandConsumerBlock, PropagateCompletionLinkOptions, e => e is Command);
            _transportBuffer.LinkTo(_notificationConsumerBlock, PropagateCompletionLinkOptions, e => e is Notification);
            _transportBuffer.LinkTo(_sessionConsumerBlock, PropagateCompletionLinkOptions, e => e is Session);
            _messageConsumerBlock.LinkTo(_messageBuffer, PropagateCompletionLinkOptions, e => e != null);
            _messageConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null);
            _commandConsumerBlock.LinkTo(_commandBuffer, PropagateCompletionLinkOptions, e => e != null);
            _commandConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null);
            _notificationConsumerBlock.LinkTo(_notificationBuffer, PropagateCompletionLinkOptions, e => e != null);
            _notificationConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null);
            _sessionConsumerBlock.LinkTo(_sessionBuffer, PropagateCompletionLinkOptions, e => e != null);
            _sessionConsumerBlock.LinkTo(_drainEnvelopeBlock, e => e == null);
            _channelCommandProcessor = channelCommandProcessor ?? new ChannelCommandProcessor();
            MessageModules           = new List <IChannelModule <Message> >();
            NotificationModules      = new List <IChannelModule <Notification> >();
            CommandModules           = new List <IChannelModule <Command> >();

            if (autoReplyPings)
            {
                CommandModules.Add(new ReplyPingChannelModule(this));
            }
            if (fillEnvelopeRecipients)
            {
                FillEnvelopeRecipientsChannelModule.CreateAndRegister(this);
            }
            if (remotePingInterval != null)
            {
                RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Creates a new instance of ChannelBase
        /// </summary>
        /// <param name="transport">The transport.</param>
        /// <param name="sendTimeout">The channel send timeout.</param>
        /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param>
        /// <param name="closeTimeout">The channel close timeout.</param>
        /// <param name="envelopeBufferSize">Size of the envelope buffer.</param>
        /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param>
        /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param>
        /// <param name="remotePingInterval">The interval to ping the remote party.</param>
        /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param>
        /// <exception cref="System.ArgumentNullException"></exception>
        protected ChannelBase(
            ITransport transport,
            TimeSpan sendTimeout,
            TimeSpan?consumeTimeout,
            TimeSpan closeTimeout,
            int envelopeBufferSize,
            bool fillEnvelopeRecipients,
            bool autoReplyPings,
            TimeSpan?remotePingInterval,
            TimeSpan?remoteIdleTimeout)
        {
            if (transport == null)
            {
                throw new ArgumentNullException(nameof(transport));
            }
            if (sendTimeout == default(TimeSpan))
            {
                throw new ArgumentException("Invalid send timeout", nameof(sendTimeout));
            }
            if (consumeTimeout != null && consumeTimeout.Value == default(TimeSpan))
            {
                throw new ArgumentException("Invalid consume timeout", nameof(consumeTimeout));
            }
            if (closeTimeout == default(TimeSpan))
            {
                throw new ArgumentException("Invalid close timeout", nameof(closeTimeout));
            }
            if (envelopeBufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(envelopeBufferSize));
            }

            Transport          = transport;
            Transport.Closing += Transport_Closing;

            _sendTimeout    = sendTimeout;
            _consumeTimeout = consumeTimeout;
            _closeTimeout   = closeTimeout;
            _consumerCts    = new CancellationTokenSource();
            _syncRoot       = new object();

            var options = new DataflowBlockOptions()
            {
                BoundedCapacity = envelopeBufferSize
            };

            _messageBuffer      = new BufferBlock <Message>(options);
            _commandBuffer      = new BufferBlock <Command>(options);
            _notificationBuffer = new BufferBlock <Notification>(options);
            _sessionBuffer      = new BufferBlock <Session>(new DataflowBlockOptions()
            {
                BoundedCapacity = 1
            });
            _pendingCommandsDictionary = new ConcurrentDictionary <string, TaskCompletionSource <Command> >();
            MessageModules             = new List <IChannelModule <Message> >();
            NotificationModules        = new List <IChannelModule <Notification> >();
            CommandModules             = new List <IChannelModule <Command> >();

            if (autoReplyPings)
            {
                CommandModules.Add(new ReplyPingChannelModule(this));
            }

            if (fillEnvelopeRecipients)
            {
                FillEnvelopeRecipientsChannelModule.CreateAndRegister(this);
            }

            if (remotePingInterval != null)
            {
                RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates a new instance of ChannelBase
        /// </summary>
        /// <param name="transport">The transport.</param>
        /// <param name="sendTimeout">The channel send timeout.</param>
        /// <param name="consumeTimeout">The channel consume timeout. Each envelope received from the transport must be consumed in the specified timeout or it will cause the channel to be closed.</param>
        /// <param name="closeTimeout">The channel close timeout.</param>
        /// <param name="envelopeBufferSize">Size of the envelope buffer.</param>
        /// <param name="fillEnvelopeRecipients">Indicates if the from and to properties of sent and received envelopes should be filled with the session information if not defined.</param>
        /// <param name="autoReplyPings">Indicates if the channel should reply automatically to ping request commands. In this case, the ping command are not returned by the ReceiveCommandAsync method.</param>
        /// <param name="remotePingInterval">The interval to ping the remote party.</param>
        /// <param name="remoteIdleTimeout">The timeout to close the channel due to inactivity.</param>
        /// <param name="channelCommandProcessor">The channel command processor.</param>
        /// <exception cref="System.ArgumentNullException"></exception>
        /// <exception cref="System.ArgumentException">
        /// Invalid send timeout
        /// or
        /// Invalid consume timeout
        /// or
        /// Invalid close timeout
        /// </exception>
        /// <exception cref="System.ArgumentOutOfRangeException"></exception>
        protected ChannelBase(
            ITransport transport,
            TimeSpan sendTimeout,
            TimeSpan?consumeTimeout,
            TimeSpan closeTimeout,
            int envelopeBufferSize,
            bool fillEnvelopeRecipients,
            bool autoReplyPings,
            TimeSpan?remotePingInterval,
            TimeSpan?remoteIdleTimeout,
            IChannelCommandProcessor channelCommandProcessor)
        {
            if (closeTimeout == default)
            {
                throw new ArgumentException("Invalid close timeout", nameof(closeTimeout));
            }
            if (envelopeBufferSize <= 0)
            {
                envelopeBufferSize = -1;
            }
            Transport                = transport ?? throw new ArgumentNullException(nameof(transport));
            Transport.Closing       += Transport_Closing;
            _closeTimeout            = closeTimeout;
            _channelCommandProcessor = channelCommandProcessor ?? new ChannelCommandProcessor();

            // Modules
            MessageModules      = new List <IChannelModule <Message> >();
            NotificationModules = new List <IChannelModule <Notification> >();
            CommandModules      = new List <IChannelModule <Command> >();
            if (autoReplyPings)
            {
                CommandModules.Add(new ReplyPingChannelModule(this));
            }
            if (fillEnvelopeRecipients)
            {
                FillEnvelopeRecipientsChannelModule.CreateAndRegister(this);
            }
            if (remotePingInterval != null)
            {
                _remotePingChannelModule = RemotePingChannelModule.CreateAndRegister(this, remotePingInterval.Value, remoteIdleTimeout);
            }

            _receiverChannel = new ReceiverChannel(
                this,
                Transport,
                _channelCommandProcessor,
                MessageModules,
                NotificationModules,
                CommandModules,
                HandleConsumerExceptionAsync,
                envelopeBufferSize,
                consumeTimeout,
                _closeTimeout);

            _senderChannel = new SenderChannel(
                this,
                Transport,
                MessageModules,
                NotificationModules,
                CommandModules,
                HandleSenderExceptionAsync,
                envelopeBufferSize,
                sendTimeout,
                _closeTimeout);
        }