Пример #1
0
        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);
        }
Пример #2
0
        /// <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);
        }