public Task UpdatePersistentSubscriptionAsync(string stream, string groupName, PersistentSubscriptionSettings settings,
            UserCredentials userCredentials)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            Ensure.NotNullOrEmpty(groupName, "groupName");

            var source = new TaskCompletionSource<PersistentSubscriptionUpdateResult>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.UpdatePersistentSubscription(source, stream, groupName));

            var corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.UpdatePersistentSubscription(
                corrId,
                corrId,
                envelope,
                stream,
                groupName,
                settings.ResolveLinkTos,
                settings.StartFrom,
                (int) settings.MessageTimeout.TotalMilliseconds,
                settings.ExtraStatistics,
                settings.MaxRetryCount,
                settings.HistoryBufferSize,
                settings.LiveBufferSize,
                settings.ReadBatchSize,
                (int) settings.CheckPointAfter.TotalMilliseconds,
                settings.MinCheckPointCount,
                settings.MaxCheckPointCount,
                settings.MaxSubscriberCount,
                settings.NamedConsumerStrategy,
                user,
                userCredentials == null ? null : userCredentials.Username,
                userCredentials == null ? null : userCredentials.Password));

            return source.Task;
        }
        public Task<StreamEventsSlice> ReadStreamEventsForwardAsync(string stream, int start, int count, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            Ensure.Nonnegative(start, "start");
            Ensure.Positive(count, "count");
            if (count > Consts.MaxReadSize) throw new ArgumentException(string.Format("Count should be less than {0}. For larger reads you should page.", Consts.MaxReadSize));
            var source = new TaskCompletionSource<StreamEventsSlice>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadStreamForwardEvents(source, stream, start));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.ReadStreamEventsForward(corrId, corrId, envelope,
                stream, start, count, resolveLinkTos, false, null, user));

            return source.Task;
        }
        public Task<AllEventsSlice> ReadAllEventsBackwardAsync(Position position, int maxCount, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.Positive(maxCount, "maxCount");
            if (maxCount > Consts.MaxReadSize) throw new ArgumentException(string.Format("Count should be less than {0}. For larger reads you should page.", Consts.MaxReadSize));
            var source = new TaskCompletionSource<AllEventsSlice>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadAllEventsBackward(source));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.ReadAllEventsBackward(corrId, corrId, envelope,
                position.CommitPosition,
                position.PreparePosition, maxCount, resolveLinkTos, false, null, user));

            return source.Task;
        }
        Task IEventStoreTransactionConnection.TransactionalWriteAsync(EventStoreTransaction transaction, IEnumerable<EventData> events, UserCredentials userCredentials)
        {
            // ReSharper disable PossibleMultipleEnumeration
            Ensure.NotNull(transaction, "transaction");
            Ensure.NotNull(events, "events");

            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionWrite(source, this));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.TransactionWrite(corrId, corrId, envelope,
                false, transaction.TransactionId, events.ConvertToEvents(), user));

            return source.Task;

            // ReSharper restore PossibleMultipleEnumeration
        }
        public Task<EventReadResult> ReadEventAsync(string stream, int eventNumber, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            if (eventNumber < -1) throw new ArgumentOutOfRangeException("eventNumber");

            var source = new TaskCompletionSource<EventReadResult>();
            
            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadEvent(source, stream, eventNumber));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.ReadEvent(corrId, corrId, envelope,
                stream, eventNumber, resolveLinkTos, false, user));

            return source.Task;
        }
        public Task TransactionalWriteAsync(EventStoreTransaction transaction, IEnumerable<EventData> events,
            UserCredentials userCredentials = null)
        {
            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(
                new EmbeddedResponders.TransactionWrite(source, this));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.TransactionWrite(corrId, corrId, envelope, false, 
                transaction.TransactionId, events.ConvertToEvents(), user));
            
            return source.Task;
        }
        public Task<EventStoreTransaction> StartTransactionAsync(string stream, int expectedVersion, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");

            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionStart(source, this, stream, expectedVersion));

            Guid corrId = Guid.NewGuid();

            _publisher.Publish(new ClientMessage.TransactionStart(corrId, corrId, envelope,
                false, stream, expectedVersion, SystemAccount.Principal));

            return source.Task;
        }
        public Task<WriteResult> CommitTransactionAsync(EventStoreTransaction transaction, UserCredentials userCredentials = null)
        {
            var source = new TaskCompletionSource<WriteResult>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionCommit(source));

            Guid corrId = Guid.NewGuid();

            var message = new ClientMessage.TransactionCommit(corrId, corrId, envelope, false,
                transaction.TransactionId, SystemAccount.Principal);

            _publisher.Publish(message);

            return source.Task;
            
        }
        public Task<DeleteResult> DeleteStreamAsync(string stream, int expectedVersion, bool hardDelete, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");

            var source = new TaskCompletionSource<DeleteResult>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.DeleteStream(source, stream, expectedVersion));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.DeleteStream(corrId, corrId, envelope, false,
                stream, expectedVersion, hardDelete, user));

            return source.Task;
        }
        public Task<AllEventsSlice> ReadAllEventsBackwardAsync(Position position, int maxCount, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.Positive(maxCount, "maxCount");

            var source = new TaskCompletionSource<AllEventsSlice>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadAllEventsBackward(source));

            Guid corrId = Guid.NewGuid();

            var message = new ClientMessage.ReadAllEventsBackward(corrId, corrId, envelope,
                position.CommitPosition,
                position.PreparePosition, maxCount, resolveLinkTos, false, null, SystemAccount.Principal);

            _publisher.Publish(message);

            return source.Task;
        }
        public Task TransactionalWriteAsync(EventStoreTransaction transaction, IEnumerable<EventData> events,
            UserCredentials userCredentials = null)
        {
            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionWrite(source, this));

            Guid corrId = Guid.NewGuid();

            var message = new ClientMessage.TransactionWrite(corrId, corrId, envelope,false, 
                transaction.TransactionId, events.ConvertToEvents(), SystemAccount.Principal);

            _publisher.Publish(message);

            return source.Task;
            
        }
        public Task<StreamEventsSlice> ReadStreamEventsBackwardAsync(string stream, int start, int count, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            Ensure.Positive(count, "count");

            var source = new TaskCompletionSource<StreamEventsSlice>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadStreamEventsBackward(source, stream, start));

            Guid corrId = Guid.NewGuid();

            var message = new ClientMessage.ReadStreamEventsBackward(corrId, corrId, envelope,
                stream, start, count, resolveLinkTos, false, null, SystemAccount.Principal);

            _publisher.Publish(message);

            return source.Task;
        }
        public Task<EventReadResult> ReadEventAsync(string stream, int eventNumber, bool resolveLinkTos, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            if (eventNumber < -1) throw new ArgumentOutOfRangeException("eventNumber");

            var source = new TaskCompletionSource<EventReadResult>();
            
            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.ReadEvent(source, stream, eventNumber));

            Guid corrId = Guid.NewGuid();

            var message = new ClientMessage.ReadEvent(corrId, corrId, envelope,
                stream, eventNumber, resolveLinkTos, false, SystemAccount.Principal);

            _publisher.Publish(message);

            return source.Task;
        }
        Task IEventStoreTransactionConnection.TransactionalWriteAsync(EventStoreTransaction transaction, IEnumerable<EventData> events, UserCredentials userCredentials)
        {
            // ReSharper disable PossibleMultipleEnumeration
            Ensure.NotNull(transaction, "transaction");
            Ensure.NotNull(events, "events");

            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionWrite(source, this));

            Guid corrId = Guid.NewGuid();

            _publisher.Publish(new ClientMessage.TransactionWrite(corrId, corrId, envelope,
                false, transaction.TransactionId, events.ConvertToEvents(), SystemAccount.Principal));

            return source.Task;

            // ReSharper restore PossibleMultipleEnumeration
        }
        public Task DeletePersistentSubscriptionAsync(
            string stream, string groupName, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            Ensure.NotNullOrEmpty(groupName, "groupName");

            var source = new TaskCompletionSource<PersistentSubscriptionDeleteResult>();

            var envelope = new EmbeddedResponseEnvelope(
                new EmbeddedResponders.DeletePersistentSubscription(source, stream, groupName));

            var corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.DeletePersistentSubscription(
                corrId,
                corrId,
                envelope,
                stream,
                groupName,
                user));

            return source.Task;
        }
        public Task<WriteResult> AppendToStreamAsync(string stream, int expectedVersion, IEnumerable<EventData> events, UserCredentials userCredentials = null)
        {
            // ReSharper disable PossibleMultipleEnumeration
            Ensure.NotNullOrEmpty(stream, "stream");
            Ensure.NotNull(events, "events");

            var source = new TaskCompletionSource<WriteResult>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.AppendToStream(source, stream, expectedVersion));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.WriteEvents(corrId, corrId, envelope, false,
                stream, expectedVersion, events.ConvertToEvents(), user));

            return source.Task;
            // ReSharper restore PossibleMultipleEnumeration
        }
        public Task<WriteResult> SetStreamMetadataAsync(string stream, int expectedMetastreamVersion, byte[] metadata, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");
            if (SystemStreams.IsMetastream(stream))
                throw new ArgumentException(string.Format("Setting metadata for metastream '{0}' is not supported.", stream), "stream");

            var metaevent = new EventData(Guid.NewGuid(), SystemEventTypes.StreamMetadata, true, metadata ?? Empty.ByteArray, null);
            var metastream = SystemStreams.MetastreamOf(stream);

            var source = new TaskCompletionSource<WriteResult>();

            var envelope = new EmbeddedResponseEnvelope(
                new EmbeddedResponders.AppendToStream(source, metastream, expectedMetastreamVersion));

            var corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.WriteEvents(corrId, corrId, envelope, false, metastream,
                expectedMetastreamVersion, metaevent.ConvertToEvent(), user));

            return source.Task;
        }
        public Task<EventStoreTransaction> StartTransactionAsync(string stream, int expectedVersion, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");

            var source = new TaskCompletionSource<EventStoreTransaction>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.TransactionStart(source, this, stream, expectedVersion));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(_authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException, user => new ClientMessage.TransactionStart(corrId, corrId, envelope,
                false, stream, expectedVersion, user));

            return source.Task;
        }
        public Task<WriteResult> CommitTransactionAsync(EventStoreTransaction transaction, UserCredentials userCredentials = null)
        {
            var source = new TaskCompletionSource<WriteResult>();

            var envelope = new EmbeddedResponseEnvelope(
                new EmbeddedResponders.TransactionCommit(source));

            Guid corrId = Guid.NewGuid();

            _publisher.PublishWithAuthentication(
                _authenticationProvider, GetUserCredentials(_settings, userCredentials), source.SetException,
                user => new ClientMessage.TransactionCommit(corrId, corrId, envelope, false,
                    transaction.TransactionId, user));

            return source.Task;
        }
        public Task<DeleteResult> DeleteStreamAsync(string stream, int expectedVersion, bool hardDelete, UserCredentials userCredentials = null)
        {
            Ensure.NotNullOrEmpty(stream, "stream");

            var source = new TaskCompletionSource<DeleteResult>();

            var envelope = new EmbeddedResponseEnvelope(new EmbeddedResponders.DeleteStream(source, stream, expectedVersion));

            Guid corrId = Guid.NewGuid();

            _publisher.Publish(new ClientMessage.DeleteStream(corrId, corrId, envelope, false,
                stream, expectedVersion, hardDelete, SystemAccount.Principal));

            return source.Task;
        }