private void ChannelInputClosed(IChannelHandlerContext context, bool callChannelInactive)
        {
            var output = RecyclableArrayList.Take();

            try
            {
                if (_cumulation != null)
                {
                    CallDecode(context, _cumulation, output);
                    DecodeLast(context, _cumulation, output);
                }
                else
                {
                    DecodeLast(context, Unpooled.Empty, output);
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new DecoderException(ex);
            }
            finally
            {
                try
                {
                    if (_cumulation != null)
                    {
                        _cumulation.Release();
                        _cumulation = null;
                    }
                    var size = output.Count;
                    FireChannelRead(context, output, size);

                    if (size > 0)
                    {
                        // Something was read, call FireChannelReadComplete()
                        context.FireChannelReadComplete();
                    }

                    if (callChannelInactive)
                    {
                        context.FireChannelInactive();
                    }
                }
                finally
                {
                    // recycle in all cases
                    output.Return();
                }
            }
        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            if (message is IByteBuf)
            {
                var output = RecyclableArrayList.Take();
                try
                {
                    var data = (IByteBuf)message;
                    _first = _cumulation == null;
                    if (_first)
                    {
                        _cumulation = data;
                    }
                    else
                    {
                        _cumulation = _cumulator(context.Allocator, _cumulation, data);
                    }
                    CallDecode(context, _cumulation, output);
                }
                catch (DecoderException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    throw new DecoderException(ex);
                }
                finally
                {
                    if (_cumulation != null && !_cumulation.IsReadable())
                    {
                        _numReads = 0;
                        _cumulation.Release();
                        _cumulation = null;
                    }
                    else if (++_numReads >= _discardAfterReads)
                    {
                        _numReads = 0;
                        DiscardSomeReadBytes();
                    }

                    var size = output.Count;
                    _decodeWasNull = size == 0;
                    FireChannelRead(context, output, size);
                    output.Return();
                }
            }
            else
            {
                // not a byte buffer? then we can't handle it. Forward it along
                context.FireChannelRead(message);
            }
        }
Beispiel #3
0
        /// <summary>
        ///     Write messages to the outbound of this <see cref="IChannel" />.
        /// </summary>
        /// <param name="msgs">The messages to be written.</param>
        /// <returns><c>true</c> if the write operation did add something to the inbound buffer</returns>
        public bool WriteOutbound(params object[] msgs)
        {
            EnsureOpen();
            if (msgs.Length == 0)
            {
                return(IsNotEmpty(outboundMessages));
            }

            var futures = RecyclableArrayList.Take();

            try
            {
                foreach (var m in msgs)
                {
                    if (m == null)
                    {
                        break;
                    }
                    futures.Add(WriteAsync(m));
                }

                Flush();

                var size = futures.Count;
                for (var i = 0; i < size; i++)
                {
                    var future = (Task)futures[i];
                    Debug.Assert(future.IsCompleted);
                    if (future.Exception != null)
                    {
                        RecordException(future.Exception);
                    }
                }

                RunPendingTasks();
                CheckException();
                return(IsNotEmpty(outboundMessages));
            }
            finally
            {
                futures.Return();
            }
        }
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            var output = RecyclableArrayList.Take();

            try
            {
                if (AcceptInboundMessage(message))
                {
                    var cast = (TMessage)message;
                    try
                    {
                        Decode(context, cast, output);
                    }
                    finally
                    {
                        ReferenceCountUtil.Release(cast);
                    }
                }
                else
                {
                    output.Add(message);
                }
            }
            catch (DecoderException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new DecoderException(ex);
            }
            finally
            {
                var size = output.Count;
                for (var i = 0; i < size; i++)
                {
                    context.FireChannelRead(output[i]);
                }
                output.Return();
            }
        }
        public override Task WriteAsync(IChannelHandlerContext context, object message)
        {
            Task result = null;
            RecyclableArrayList output = null;

            try
            {
                if (CanAcceptOutboundMessage(message))
                {
                    var cast = (T)message;
                    output = RecyclableArrayList.Take();
                    try
                    {
                        Encode(context, cast, output);
                    }
                    finally
                    {
                        // TODO: reference counting
                    }

                    if (!output.Any())
                    {
                        output.Return();
                        output = null;

                        throw new EncoderException($"{GetType()} must produce at least one message");
                    }
                }
                else
                {
                    return(context.WriteAsync(message));
                }
            }
            catch (EncoderException ex)
            {
                return(TaskEx.FromException(ex));
            }
            catch (Exception ex)
            {
                return(TaskEx.FromException(new EncoderException(ex)));
            }
            finally
            {
                if (output != null)
                {
                    var sizeMinusOne = output.Count - 1;
                    if (sizeMinusOne == 0)
                    {
                        result = context.WriteAsync(output[0]);
                    }
                    else if (sizeMinusOne > 0)
                    {
                        // TODO: netty does some promise optimizations here, which our API doesn't support at the moment
                        for (var i = 0; i < sizeMinusOne; i++)
                        {
                            context.WriteAsync(output[i]);
                        }
                        result = context.WriteAsync(output[sizeMinusOne]);
                    }

                    output.Return();
                }
            }
            return(result);
        }