Skip to main content

rs_netty/
lib.rs

1#![deny(unsafe_code)]
2//! Tokio-native typed TCP/UDP pipeline framework inspired by Netty.
3//!
4//! `rs-netty` keeps the familiar channel, pipeline, and handler shape while
5//! using Rust's type system to validate pipeline order and message transitions
6//! at compile time.
7//!
8//! # Quick start
9//!
10//! ```no_run
11//! use rs_netty::{codec::LineCodec, handler, pipeline, Result, TcpServer};
12//!
13//! #[tokio::main]
14//! async fn main() -> Result<()> {
15//!     TcpServer::bind("127.0.0.1:9000")
16//!         .pipeline(|| {
17//!             pipeline()
18//!                 .codec(LineCodec::new())
19//!                 .handler(Echo)
20//!         })
21//!         .run()
22//!         .await
23//! }
24//!
25//! struct Echo;
26//!
27//! #[handler(Echo)]
28//! async fn echo(msg: String) -> Result<String> {
29//!     Ok(msg)
30//! }
31//! ```
32//!
33//! # Pipeline shape
34//!
35//! TCP pipelines are built with [`pipeline()`] and UDP pipelines are built with
36//! [`datagram_pipeline()`]. The builder only exposes methods that are valid in
37//! the current state, so invalid orderings such as adding a handler before a
38//! codec fail to compile.
39//!
40//! A TCP pipeline has this shape:
41//!
42//! ```text
43//! codec -> inbound* -> business* -> handler -> outbound*
44//! ```
45//!
46//! A UDP pipeline has the same typed stage model, but processes whole datagrams
47//! rather than a byte stream.
48//!
49//! # Write and flush semantics
50//!
51//! Writes issued through [`Context`] are staged in the current handler's
52//! outbox and then encoded into the connection write buffer. `flush` and
53//! `write_and_flush` request a local socket flush immediately; dropping their
54//! returned handles is fire-and-forget, while awaiting them waits until the
55//! local socket write completes. [`DatagramContext`] keeps the same manual
56//! flush model for datagram sockets.
57//!
58//! Writes issued through [`Channel`], [`TcpClientHandle`], [`DatagramChannel`],
59//! or [`UdpClientHandle`] are sent through the connection/socket command queue
60//! and follow the same manual flush semantics. The queue is bounded by the
61//! configured outbound queue size.
62//!
63//! # Handler ergonomics
64//!
65//! Simple handlers can use the [`handler`] attribute macro:
66//!
67//! ```no_run
68//! # use rs_netty::{handler, Result};
69//! struct Echo;
70//!
71//! #[handler(Echo)]
72//! async fn echo(msg: String) -> Result<String> {
73//!     Ok(msg)
74//! }
75//! ```
76//!
77//! A handler function that returns `Result<Out>` automatically writes and
78//! flushes `Out` back through the pipeline. A function that returns `Result<()>`
79//! consumes the inbound message without automatically writing; in that case use
80//! `#[handler(TypeName, write = WriteType)]` so the macro can set
81//! `Handler::Write`.
82//!
83//! Write a manual [`Handler`] or [`DatagramHandler`] implementation when the
84//! logic needs direct access to [`Context`] or [`DatagramContext`], such as
85//! explicit flush timing or multiple writes for one inbound message.
86//!
87//! # Client pipeline choices
88//!
89//! [`TcpClient::pipeline`] accepts a reusable factory closure, matching the
90//! server API and working well for stateless or cloneable client handlers.
91//! [`TcpClient::pipeline_instance`] accepts one already-built pipeline and
92//! consumes it when the client connects. Prefer `pipeline_instance` when a
93//! client handler owns one-shot state, such as `tokio::sync::oneshot::Sender`.
94
95pub mod channel;
96pub mod client;
97pub mod codec;
98pub mod context;
99pub mod error;
100pub mod life;
101pub mod pipeline;
102pub mod server;
103#[cfg(feature = "tls")]
104pub mod tls;
105pub mod traits;
106pub mod transport;
107
108pub use channel::{Channel, DatagramChannel};
109pub use context::{
110    BusinessContext, ConnInfo, ConnectionStats, Context, DatagramContext, DatagramInfo,
111    InboundContext, OutboundContext,
112};
113pub use error::{Error, Result};
114pub use life::{CloseReason, Life, NoLife};
115pub use pipeline::builder::pipeline;
116pub use pipeline::datagram::builder::datagram_pipeline;
117#[cfg(feature = "macros")]
118pub use rs_netty_macros::handler;
119#[cfg(feature = "tls")]
120pub use tls::{
121    ClientTlsContext, ClientTlsContextBuilder, HasTrust, NoTrust, ServerTlsContext,
122    ServerTlsContextBuilder, TlsContextBuilder, TlsInfo,
123};
124pub use traits::{Business, DatagramHandler, Flow, Handler, Inbound, Outbound};
125pub use transport::tcp::client::{TcpClient, TcpClientHandle};
126pub use transport::tcp::server::TcpServer;
127pub use transport::udp::client::{UdpClient, UdpClientHandle};
128pub use transport::udp::server::UdpServer;