internal async Task <TFirefoxResponse> SendAsync <TFirefoxResponse>(IFirefoxRequest <TFirefoxResponse> request)
            where TFirefoxResponse : IFirefoxResponse
        {
            int id = GetMessageId();
            MessageTask <IFirefoxResponse> callback = new MessageTask <IFirefoxResponse>
            {
                TaskWrapper = new TaskCompletionSource <IFirefoxResponse>(),
                Method      = request.Command,
            };

            _callbacks[id] = callback;

            try
            {
                await RawSendAsync(new ConnectionRequest
                {
                    Id     = id,
                    Method = request.Command,
                    Params = request,
                }).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                if (_callbacks.TryRemove(id, out _))
                {
                    callback.TaskWrapper.TrySetException(new MessageException(ex.Message, ex));
                }
            }

            var result = await callback.TaskWrapper.Task.ConfigureAwait(false);

            return((TFirefoxResponse)result);
        }
        internal async Task <TFirefoxResponse> SendAsync <TFirefoxResponse>(IFirefoxRequest <TFirefoxResponse> request, bool waitForCallback = true)
            where TFirefoxResponse : IFirefoxResponse
        {
            if (_disposed)
            {
                throw new MessageException(
                          $"Protocol error ({request.Command}): Session closed. " +
                          $"Most likely the {_targetType} has been closed." +
                          $"Close reason: {_closeReason}");
            }

            int id = Connection.GetMessageId();
            MessageTask <IFirefoxResponse> callback = null;

            if (waitForCallback)
            {
                callback = new MessageTask <IFirefoxResponse>
                {
                    TaskWrapper = new TaskCompletionSource <IFirefoxResponse>(),
                    Method      = request.Command,
                };
                _callbacks[id] = callback;
            }

            try
            {
                await _rawSend(id, (IFirefoxRequest <IFirefoxResponse>) request).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                if (waitForCallback && _callbacks.TryRemove(id, out _))
                {
                    callback.TaskWrapper.TrySetException(new MessageException(ex.Message, ex));
                }
            }

            var result = waitForCallback ? (await callback.TaskWrapper.Task.ConfigureAwait(false)) : null;

            return((TFirefoxResponse)result);
        }