/// <inheritdoc/>
        public Task Subscribe <T>(BusEvent <T> eventMessage) where T : class
        {
            if (eventMessage == null)
            {
                throw new ArgumentNullException(nameof(eventMessage));
            }

            var @event = (eventMessage is PlatformEvent <T>) ?
                         eventMessage as PlatformEvent <T> :
                         throw new ArgumentException($"{nameof(eventMessage)} must be type of {nameof(PlatformEvent<T>)}");

            if (!typeof(IMessageListener).IsAssignableFrom(typeof(T)))
            {
                throw new InvalidOperationException("Type parameter must be an IMessageListener");
            }

            var eventName = eventMessage.Name;

            if (string.IsNullOrWhiteSpace(eventName))
            {
                throw new ArgumentException($"EventName of {nameof(eventMessage)} cannot be empty");
            }

            var key = new SubscriptionInfo(eventName, @event.ReplayId, typeof(T));

            if (_subscriptions.ContainsKey(key))
            {
                // only allow a single subscription per (event + type)
                throw new ArgumentException(
                          $"EventName of {nameof(eventMessage)} is already subscribed to {typeof(T).Name}.");
            }

            // check connection
            if (!_streamingClient.IsConnected)
            {
                _streamingClient.Handshake();
            }

            // build channel segment
            var topicName = GetEventOrTopicName(eventName);
            var handler   = GetListerner <T>();

            _subscriptions.AddOrUpdate(key, handler, (existingKey, existingHandler) => existingHandler);

            _streamingClient.SubscribeTopic(topicName, handler as IMessageListener, @event.ReplayId);

            _logger.LogDebug($"{topicName} is subscribed with ReplayId: {@event.ReplayId}");

            return(Task.CompletedTask);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="EventBus"/> class.
        /// </summary>
        /// <param name="streamingClient">The instance of <see cref="IStreamingClient"/> with connection to salesforce.</param>
        /// <param name="logger">The instance of <see cref="ILogger{SalesforceEventBus}"/>.</param>
        /// <param name="forceClient">The instance of <see cref="ForceClientProxy"/> to provide a publish functionality to the bus.</param>
        /// <param name="messageListeners"></param>
        /// <param name="options"></param>
        public EventBus(
            IStreamingClient streamingClient,
            ILogger <EventBus> logger,
            IResilientForceClient forceClient,
            IEnumerable <IMessageListener> messageListeners,
            IOptions <SalesforceConfiguration> options)
        {
            _streamingClient = streamingClient ?? throw new ArgumentNullException(nameof(streamingClient));

            _logger = logger ?? throw new ArgumentNullException(nameof(logger));

            _forceClient = forceClient ?? throw new ArgumentNullException(nameof(forceClient));

            _options = options.Value ?? throw new ArgumentNullException(nameof(options));

            _messageListerners = messageListeners;

            _streamingClient.Reconnect += StreamingClient_Reconnect;

            _streamingClient.Handshake();
        }