trillium_tokio/lib.rs
1#![forbid(unsafe_code)]
2#![deny(
3 clippy::dbg_macro,
4 missing_copy_implementations,
5 rustdoc::missing_crate_level_docs,
6 missing_debug_implementations,
7 missing_docs,
8 nonstandard_style,
9 unused_qualifications
10)]
11//! # Trillium server adapter for tokio
12//!
13//! ```rust,no_run
14//! # #[allow(clippy::needless_doctest_main)]
15//! fn main() {
16//! trillium_tokio::run(|conn: trillium::Conn| async move { conn.ok("hello tokio") });
17//! }
18//! ```
19//!
20//! ```rust,no_run
21//! # #[allow(clippy::needless_doctest_main)]
22//! #[tokio::main]
23//! async fn main() {
24//! trillium_tokio::run_async(|conn: trillium::Conn| async move { conn.ok("hello tokio") })
25//! .await;
26//! }
27//! ```
28//!
29//! For advanced binding — several listeners on one server, fallible binds you
30//! can recover from, or adopting an already-bound socket — call
31//! [`.listeners()`](trillium_server_common::Config::listeners)
32//! on a [`config()`](trillium_server_common::Config) to get a [`ListenerConfig`].
33//!
34//! ## Thread-per-core with `SO_REUSEPORT` on Linux
35//!
36//! `SO_REUSEPORT` is a socket option that lets several sockets bind the same
37//! address and port at once, with the kernel distributing incoming connections
38//! across them. Enable the `reuseport` cargo feature on Linux to use it for
39//! thread-per-core fan-out:
40//!
41//! ```rust,ignore
42//! use trillium::Conn;
43//!
44//! fn main() -> std::io::Result<()> {
45//! trillium_tokio::config()
46//! .listeners()
47//! .bind_reuseport_tcp(8080)?
48//! .run(|conn: Conn| async move { conn.ok("hello") });
49//! Ok(())
50//! }
51//! ```
52//!
53//! Each worker thread runs its own single-threaded runtime, pinned to a core,
54//! driving that worker's accept loop — one `SO_REUSEPORT` listener per worker.
55//! The standard multi-threaded work-stealing runtime is still present alongside
56//! them, hosting HTTP/3, signal handling, and the application tasks you spawn,
57//! so QUIC is never fanned out this way. Set the worker count with
58//! `.with_reuseport_workers(n)`; it defaults to the `WORKERS` environment
59//! variable, or if that's not set, to available parallelism.
60//!
61//! This trades the work-stealing runtime's load balancing for per-core
62//! locality, which can improve throughput for short, CPU-cheap requests served
63//! over many connections. It is gated off on platforms where plain
64//! `SO_REUSEPORT` does not distribute connections (including macOS), where it
65//! would offer no benefit.
66
67#[cfg(test)]
68#[doc = include_str!("../README.md")]
69mod readme {}
70
71use trillium::Handler;
72pub use trillium_server_common::{Binding, IntoListenAddr, ListenerConfig, Swansong};
73
74mod client;
75pub use client::ClientConfig;
76#[cfg(unix)]
77pub use client::UnixClientConfig;
78
79mod server;
80pub use async_compat;
81use server::Config;
82pub use tokio;
83pub use tokio_stream;
84
85mod transport;
86pub use transport::TokioTransport;
87
88/// # Runs a trillium handler in a sync context with default config
89///
90/// Runs a trillium handler on the tokio runtime with
91/// default configuration. See [`crate::config`] for what the defaults are
92/// and how to override them
93///
94///
95/// This function will block the current thread until the server shuts
96/// down
97pub fn run(handler: impl Handler) {
98 config().run(handler)
99}
100
101/// # Runs a trillium handler in an async context with default config
102///
103/// Run the provided trillium handler on an already-running tokio runtime
104/// with default settings. The defaults are the same as [`crate::run`]. To
105/// customize these settings, see [`crate::config`].
106///
107/// This function will poll pending until the server shuts down.
108pub async fn run_async(handler: impl Handler) {
109 config().run_async(handler).await
110}
111
112/// # Configures a server before running it
113///
114/// ## Defaults
115///
116/// The default configuration is as follows:
117///
118/// port: the contents of the `PORT` env var or else 8080
119/// host: the contents of the `HOST` env var or else "localhost"
120/// signals handling and graceful shutdown: enabled on cfg(unix) systems
121/// tcp nodelay: disabled
122/// tls acceptor: none
123///
124/// ## Usage
125///
126/// ```rust
127/// let swansong = trillium_tokio::Swansong::new();
128/// # swansong.shut_down(); // stoppping the server immediately for the test
129/// trillium_tokio::config()
130/// .with_port(0)
131/// .with_host("127.0.0.1")
132/// .without_signals()
133/// .with_nodelay()
134/// .with_acceptor(()) // see [`trillium_rustls`], [`trillium_native_tls`], and [`trillium_openssl`]
135/// .with_swansong(swansong)
136/// .run(|conn: trillium::Conn| async move { conn.ok("hello tokio") });
137/// ```
138///
139/// See [`trillium_server_common::Config`] for more details
140pub fn config() -> Config<()> {
141 Config::new()
142}
143
144mod runtime;
145pub use runtime::TokioRuntime;
146
147#[cfg(all(
148 feature = "reuseport",
149 unix,
150 not(target_os = "solaris"),
151 not(target_os = "illumos"),
152 not(target_os = "cygwin"),
153 not(target_vendor = "apple")
154))]
155mod reuseport;
156
157mod udp;
158pub use udp::TokioUdpSocket;