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); } }
/// <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); }