static void WritePromiseCombiner(IChannelHandlerContext ctx, List <object> output, IPromise promise) { PromiseCombiner combiner = new PromiseCombiner(); for (int i = 0; i < output.Count; i++) { combiner.Add(ctx.WriteAsync(output[i])); } combiner.Finish(promise); }
/// <summary> /// Removes all pending write operation and performs them via <see cref="IChannelHandlerContext.WriteAsync(object, IPromise)"/> /// </summary> /// <returns><see cref="Task"/> if something was written and <c>null</c> /// if the <see cref="PendingWriteQueue"/> is empty.</returns> public Task RemoveAndWriteAllAsync() { Debug.Assert(_ctx.Executor.InEventLoop); if (IsEmpty) { return(null); } var p = _ctx.NewPromise(); PromiseCombiner combiner = new PromiseCombiner(_ctx.Executor); try { // It is possible for some of the written promises to trigger more writes. The new writes // will "revive" the queue, so we need to write them up until the queue is empty. for (PendingWrite write = _head; write is object; write = _head) { _head = _tail = null; _size = 0; _bytes = 0; while (write is object) { PendingWrite next = write.Next; object msg = write.Msg; IPromise promise = write.Promise; Recycle(write, false); if (!promise.IsVoid) { combiner.Add(promise.Task); } _ = _ctx.WriteAsync(msg, promise); write = next; } } combiner.Finish(p); } catch (Exception exc) { p.SetException(exc); } AssertEmpty(); return(p.Task); }
public override Task WriteDataAsync(IChannelHandlerContext ctx, int streamId, IByteBuffer data, int padding, bool endOfStream, IPromise promise) { IHttp2Stream stream = Connection.Stream(streamId); EmbeddedChannel channel = stream?.GetProperty <EmbeddedChannel>(_propertyKey); if (channel is null) { // The compressor may be null if no compatible encoding type was found in this stream's headers return(base.WriteDataAsync(ctx, streamId, data, padding, endOfStream, promise)); } try { // The channel will release the buffer after being written _ = channel.WriteOutbound(data); var buf = NextReadableBuf(channel); if (buf is null) { if (endOfStream) { if (channel.Finish()) { buf = NextReadableBuf(channel); } return(base.WriteDataAsync(ctx, streamId, buf ?? Unpooled.Empty, padding, true, promise)); } // END_STREAM is not set and the assumption is data is still forthcoming. promise.Complete(); return(promise.Task); } PromiseCombiner combiner = new PromiseCombiner(ctx.Executor); while (true) { var nextBuf = NextReadableBuf(channel); var compressedEndOfStream = nextBuf is null && endOfStream; if (compressedEndOfStream && channel.Finish()) { nextBuf = NextReadableBuf(channel); compressedEndOfStream = nextBuf is null; } var bufPromise = ctx.NewPromise(); combiner.Add(bufPromise.Task); _ = base.WriteDataAsync(ctx, streamId, buf, padding, compressedEndOfStream, bufPromise); if (nextBuf is null) { break; } padding = 0; // Padding is only communicated once on the first iteration buf = nextBuf; } combiner.Finish(promise); } catch (Exception cause) { _ = promise.TrySetException(cause); } finally { if (endOfStream) { Cleanup(stream, channel); } } return(promise.Task); }