Architecture
The main path has four layers: transport, pipeline runtime, stage traits, and channel/context.
Crate Layout
src/lib.rs: public modules and common re-exports.src/traits.rs:Inbound,Business,Handler,DatagramHandler,Outbound, andFlow.src/pipeline/stream: TCP typed builder and runtime pipeline.src/pipeline/datagram: UDP typed builder and runtime pipeline.src/pipeline/core: sharedIdentity,Then, stage pipe traits, and builder state markers.src/codec: stream/datagram codec traits and built-in codecs.src/context: stage contexts, handler contexts, stats, and identity types.src/channel: external write handles and internal command enums.src/tls.rs: optional TLS context builders and server/client contexts behind thetlsfeature.src/transport/tcp: TCP server, client, connection runtime, and config.src/transport/udp: UDP server, client, socket runtime, and config.src/life.rs: lifecycle hook trait and close reasons.rs-netty-macros: the#[handler]attribute macro.
TCP Runtime Flow
A TCP server calls the pipeline factory once for each accepted connection. A client can use either a reusable factory or pipeline_instance, which consumes one single-use pipeline.
The runtime flow is roughly:
TcpListener / TcpStream
-> optional TLS accept/connect
-> read_buf
-> Decoder::decode
-> InboundPipe
-> BusinessPipe
-> Handler::read(Context<W>, msg)
-> Context outbox or Channel command queue
-> OutboundPipe
-> Encoder::encode
-> write_buf
-> flush/write_all
StreamConnectionRuntime selects over socket reads, external channel commands, and shutdown signals. Without an idle timeout it uses a no-timeout loop. With idle_timeout, it adds a read-idle timer. The timer is reset only by socket reads; outbound writes do not reset it.
UDP Runtime Flow
UDP servers and clients run around one socket task. The pipeline is socket-level:
UdpSocket::recv_from
-> DatagramDecoder::decode_datagram
-> InboundPipe
-> BusinessPipe
-> DatagramHandler::read(DatagramContext<W>, msg)
-> DatagramContext outbox or DatagramChannel command queue
-> OutboundPipe
-> DatagramEncoder::encode_datagram
-> pending_datagrams
-> flush/send_to
A UDP server does not currently create per-peer child pipelines. If you need per-peer state, store it in the handler explicitly, for example with HashMap<SocketAddr, State>.
Static Stage Composition
The builder composes stages at the type level as Then<A, B>. Identity means that a direction has no user stages. Runtime InboundPipe, BusinessPipe, and OutboundPipe process Then recursively:
Flow::Next(value)forwards the value to the next stage.Flow::Stopstops processing the current message direction without treating it as an error.Erris mapped by the connection/socket runtime into decode, encode, handler, or runtime errors.
The main path does not use dynamic Box<dyn Handler> pipeline dispatch. Pipeline types are built from generic static stage composition.
Channel And Context
Context<W> and DatagramContext<W> are the write entry points inside final handlers. They hold a handler-local outbox, which is useful for multiple writes and explicit flush boundaries during one read.
Channel<W> and DatagramChannel<W> are cloneable external handles. They send commands to the connection/socket task through a bounded Tokio mpsc queue. TCP channels expose stats(), capacity(), max_capacity(), and is_closed(); UDP channels expose socket identity and queue state.