public override async Task Read(IAsyncStreamReader <ReadReq> requestStream, IServerStreamWriter <ReadResp> responseStream, ServerCallContext context) { if (!await requestStream.MoveNext().ConfigureAwait(false)) { return; } if (requestStream.Current.ContentCase != ReadReq.ContentOneofCase.Options) { throw new InvalidOperationException(); } var options = requestStream.Current.Options; var user = context.GetHttpContext().User; if (!await _authorizationProvider.CheckAccessAsync(user, ProcessMessagesOperation.WithParameter(Plugins.Authorization.Operations.Subscriptions.Parameters.StreamId(options.StreamName)), context.CancellationToken).ConfigureAwait(false)) { throw AccessDenied(); } var connectionName = context.RequestHeaders.FirstOrDefault(x => x.Key == Constants.Headers.ConnectionName)?.Value ?? "<unknown>"; var correlationId = Guid.NewGuid(); var uuidOptionsCase = options.UuidOption.ContentCase; await using var enumerator = new PersistentStreamSubscriptionEnumerator(correlationId, connectionName, _publisher, options.StreamName, options.GroupName, options.BufferSize, user, context.CancellationToken); var subscriptionId = await enumerator.Started.ConfigureAwait(false); var read = requestStream.ForEachAsync(HandleAckNack); await responseStream.WriteAsync(new ReadResp { SubscriptionConfirmation = new ReadResp.Types.SubscriptionConfirmation { SubscriptionId = subscriptionId } }).ConfigureAwait(false); while (await enumerator.MoveNextAsync().ConfigureAwait(false)) { await responseStream.WriteAsync(new ReadResp { Event = ConvertToReadEvent(enumerator.Current) }).ConfigureAwait(false); } await read.ConfigureAwait(false); ValueTask HandleAckNack(ReadReq request) { _publisher.Publish(request.ContentCase switch { ReadReq.ContentOneofCase.Ack => new ClientMessage.PersistentSubscriptionAckEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Ack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), ReadReq.ContentOneofCase.Nack => new ClientMessage.PersistentSubscriptionNackEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Nack.Reason, request.Nack.Action switch { ReadReq.Types.Nack.Types.Action.Unknown => NakAction.Unknown, ReadReq.Types.Nack.Types.Action.Park => NakAction.Park, ReadReq.Types.Nack.Types.Action.Retry => NakAction.Retry, ReadReq.Types.Nack.Types.Action.Skip => NakAction.Skip, ReadReq.Types.Nack.Types.Action.Stop => NakAction.Stop, _ => throw new InvalidOperationException() }, request.Nack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), _ => throw new InvalidOperationException() });
public override async Task Read(IAsyncStreamReader <ReadReq> requestStream, IServerStreamWriter <ReadResp> responseStream, ServerCallContext context) { if (!await requestStream.MoveNext().ConfigureAwait(false)) { return; } if (requestStream.Current.ContentCase != ReadReq.ContentOneofCase.Options) { throw new InvalidOperationException(); } var options = requestStream.Current.Options; var user = context.GetHttpContext().User; var connectionName = context.RequestHeaders.FirstOrDefault(x => x.Key == Constants.Headers.ConnectionName)?.Value ?? "<unknown>"; var correlationId = Guid.NewGuid(); var uuidOptionsCase = options.UuidOption.ContentCase; var source = new TaskCompletionSource <bool>(); string subscriptionId = default; await using var _ = context.CancellationToken.Register(source.SetCanceled).ConfigureAwait(false); #pragma warning disable 4014 requestStream.ForEachAsync(HandleAckNack); #pragma warning restore 4014 await using var enumerator = new PersistentStreamSubscriptionEnumerator(correlationId, connectionName, _queue, options.StreamName, options.GroupName, options.BufferSize, user, context.CancellationToken); subscriptionId = await enumerator.Started.ConfigureAwait(false); await responseStream.WriteAsync(new ReadResp { SubscriptionConfirmation = new ReadResp.Types.SubscriptionConfirmation { SubscriptionId = subscriptionId } }).ConfigureAwait(false); while (await enumerator.MoveNextAsync().ConfigureAwait(false)) { await responseStream.WriteAsync(new ReadResp { Event = ConvertToReadEvent(enumerator.Current) }).ConfigureAwait(false); } Task HandleAckNack(ReadReq request) { _queue.Publish(request.ContentCase switch { ReadReq.ContentOneofCase.Ack => (Message) new ClientMessage.PersistentSubscriptionAckEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Ack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), ReadReq.ContentOneofCase.Nack => new ClientMessage.PersistentSubscriptionNackEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Nack.Reason, request.Nack.Action switch { ReadReq.Types.Nack.Types.Action.Unknown => NakAction.Unknown, ReadReq.Types.Nack.Types.Action.Park => NakAction.Park, ReadReq.Types.Nack.Types.Action.Retry => NakAction.Retry, ReadReq.Types.Nack.Types.Action.Skip => NakAction.Skip, ReadReq.Types.Nack.Types.Action.Stop => NakAction.Stop, _ => throw new InvalidOperationException() }, request.Nack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), _ => throw new InvalidOperationException() });
public override async Task Read(IAsyncStreamReader <ReadReq> requestStream, IServerStreamWriter <ReadResp> responseStream, ServerCallContext context) { if (!await requestStream.MoveNext().ConfigureAwait(false)) { return; } if (requestStream.Current.ContentCase != ReadReq.ContentOneofCase.Options) { throw new InvalidOperationException(); } var options = requestStream.Current.Options; var user = context.GetHttpContext().User; string streamId = null; switch (options.StreamOptionCase) { case ReadReq.Types.Options.StreamOptionOneofCase.StreamIdentifier: streamId = options.StreamIdentifier; break; case ReadReq.Types.Options.StreamOptionOneofCase.All: streamId = SystemStreams.AllStream; break; default: throw new InvalidOperationException(); } if (!await _authorizationProvider.CheckAccessAsync(user, ProcessMessagesOperation.WithParameter(Plugins.Authorization.Operations.Subscriptions.Parameters.StreamId(streamId)), context.CancellationToken).ConfigureAwait(false)) { throw RpcExceptions.AccessDenied(); } var connectionName = context.RequestHeaders.FirstOrDefault(x => x.Key == Constants.Headers.ConnectionName)?.Value ?? "<unknown>"; var correlationId = Guid.NewGuid(); var uuidOptionsCase = options.UuidOption.ContentCase; await using var enumerator = new PersistentStreamSubscriptionEnumerator(correlationId, connectionName, _publisher, streamId, options.GroupName, options.BufferSize, user, context.CancellationToken); var subscriptionId = await enumerator.Started.ConfigureAwait(false); var read = ValueTask.CompletedTask; var cts = new CancellationTokenSource(); try { read = PumpRequestStream(cts.Token); await responseStream.WriteAsync(new ReadResp { SubscriptionConfirmation = new ReadResp.Types.SubscriptionConfirmation { SubscriptionId = subscriptionId } }).ConfigureAwait(false); while (await enumerator.MoveNextAsync().ConfigureAwait(false)) { await responseStream.WriteAsync(new ReadResp { Event = ConvertToReadEvent(enumerator.Current) }).ConfigureAwait(false); } } catch (IOException) { Log.Information("Subscription {correlationId} to {subscriptionId} disposed. The request stream was closed.", correlationId, subscriptionId); } finally { // make sure we stop reading the request stream before leaving this method cts.Cancel(); await read.ConfigureAwait(false); } async ValueTask PumpRequestStream(CancellationToken token) { try { await requestStream.ForEachAsync(HandleAckNack, token).ConfigureAwait(false); } catch { } } ValueTask HandleAckNack(ReadReq request) { _publisher.Publish(request.ContentCase switch { ReadReq.ContentOneofCase.Ack => new ClientMessage.PersistentSubscriptionAckEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Ack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), ReadReq.ContentOneofCase.Nack => new ClientMessage.PersistentSubscriptionNackEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Nack.Reason, request.Nack.Action switch { ReadReq.Types.Nack.Types.Action.Unknown => NakAction.Unknown, ReadReq.Types.Nack.Types.Action.Park => NakAction.Park, ReadReq.Types.Nack.Types.Action.Retry => NakAction.Retry, ReadReq.Types.Nack.Types.Action.Skip => NakAction.Skip, ReadReq.Types.Nack.Types.Action.Stop => NakAction.Stop, _ => throw RpcExceptions.InvalidArgument(request.Nack.Action) }, request.Nack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), _ => throw RpcExceptions.InvalidArgument(request.ContentCase) });
public override async Task Read(IAsyncStreamReader <ReadReq> requestStream, IServerStreamWriter <ReadResp> responseStream, ServerCallContext context) { if (!await requestStream.MoveNext()) { return; } if (requestStream.Current.ContentCase != ReadReq.ContentOneofCase.Options) { throw new InvalidOperationException(); } var options = requestStream.Current.Options; var user = await GetUser(_authenticationProvider, context.RequestHeaders); var correlationId = Guid.NewGuid(); var source = new TaskCompletionSource <bool>(); string subscriptionId = default; context.CancellationToken.Register(source.SetCanceled); #pragma warning disable 4014 Task.Run(() => requestStream.ForEachAsync(HandleAckNack)); #pragma warning restore 4014 await using var enumerator = new PersistentStreamSubscriptionEnumerator(correlationId, _queue, options.StreamName, options.GroupName, options.BufferSize, user, context.CancellationToken); subscriptionId = await enumerator.Started; await responseStream.WriteAsync(new ReadResp { Empty = new ReadResp.Types.Empty() }); while (await enumerator.MoveNextAsync()) { await responseStream.WriteAsync(new ReadResp { Event = ConvertToReadEvent(enumerator.Current) }); } Task HandleAckNack(ReadReq request) { _queue.Publish(request.ContentCase switch { ReadReq.ContentOneofCase.Ack => (Message) new ClientMessage.PersistentSubscriptionAckEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Ack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), ReadReq.ContentOneofCase.Nack => new ClientMessage.PersistentSubscriptionNackEvents( correlationId, correlationId, new NoopEnvelope(), subscriptionId, request.Nack.Reason, request.Nack.Action switch { ReadReq.Types.Nack.Types.Action.Unknown => NakAction.Unknown, ReadReq.Types.Nack.Types.Action.Park => NakAction.Park, ReadReq.Types.Nack.Types.Action.Retry => NakAction.Retry, ReadReq.Types.Nack.Types.Action.Skip => NakAction.Skip, ReadReq.Types.Nack.Types.Action.Stop => NakAction.Stop, _ => throw new InvalidOperationException() }, request.Nack.Ids.Select(id => Uuid.FromDto(id).ToGuid()).ToArray(), user), _ => throw new InvalidOperationException() });