Handlers
rs-netty has five stage traits. They live in src/traits.rs, and trait-variant generates the public Send variants used on the main path.
Inbound
Inbound<I> is an inbound transformation stage after decoding and before the final handler:
#![allow(unused)]
fn main() {
struct Trim;
impl Inbound<String> for Trim {
type Out = String;
async fn read(
&mut self,
_ctx: &mut rs_netty::InboundContext,
msg: String,
) -> rs_netty::Result<rs_netty::Flow<Self::Out>> {
Ok(rs_netty::Flow::Next(msg.trim().to_string()))
}
}
}
InboundContext exposes id(), peer_addr(), and local_addr(). It does not allow writes.
Business
Business<I> is an application-level transformation stage between inbound stages and the final handler. It has the same type shape as Inbound, but the method is handle and the context is BusinessContext. Once the builder enters the business phase, it can add more business stages or the final handler, but cannot go back to inbound stages.
Handler
Handler<I> is the end of the TCP inbound side:
#![allow(unused)]
fn main() {
impl Handler<Request> for Router {
type Write = Response;
async fn read(&mut self, ctx: &mut Context<Self::Write>, req: Request) -> Result<()> {
ctx.write_and_flush(Response { body: req.body }).await
}
}
}
type Write is the application type this handler can write to the outbound side. Outbound stages start from this type and eventually produce a value the codec can encode.
Context<W> provides:
- identity:
id,peer_addr,local_addr channel(): a cloneable external channelstats():ConnectionStatswhen stats are enabledwrite,flush,write_and_flushclose
DatagramHandler
DatagramHandler<I> is the end of the UDP inbound side. It uses DatagramContext<W>, which supports write, write_to, flush, write_and_flush, write_to_and_flush, and close.
#![allow(unused)]
fn main() {
impl DatagramHandler<String> for UdpEcho {
type Write = String;
async fn read(&mut self, ctx: &mut DatagramContext<Self::Write>, msg: String) -> Result<()> {
ctx.write_and_flush(format!("echo: {msg}")).await
}
}
}
Outbound
Outbound<I> converts the application type written by a handler into the next outbound type. The final outbound type must be encodable by the codec.
#![allow(unused)]
fn main() {
struct RenderResponse;
impl Outbound<Response> for RenderResponse {
type Out = String;
async fn write(
&mut self,
_ctx: &mut rs_netty::OutboundContext,
msg: Response,
) -> rs_netty::Result<rs_netty::Flow<Self::Out>> {
Ok(rs_netty::Flow::Next(msg.body))
}
}
}
OutboundContext also exposes only identity information and does not allow direct writes.
Macro Or Manual Impl
#[handler] is good for simple one-in/one-out final handlers and consume-only handlers. Write a manual impl when you need direct Context / DatagramContext access, explicit flush timing, multiple writes, connection close, or channel().