- crud is now the demonstrator: app owns smarm runtime + root supervisor,
store actor and urus::endpoint as ordered siblings (store first, so
reverse-order shutdown drains HTTP before stopping the store),
Shutdown::Infinity on the endpoint, shutdown via
rt.handle().request_shutdown(root_sup) from the stdin thread.
Deletes two kludges the old shape forced:
* static OnceLock<Sender> spawn-on-first-use -> a supervised child
that self-registers a typed Name; handlers use smarm::send per
request and turn 'between incarnations' into a 503 instead of
panicking on a dropped store.
* static SHUTTING_DOWN AtomicBool + 250ms recv_timeout poll in the
store loop and in the SSE ticker -> a plain park; the tree stops
both. Smoke-tested live: CRUD round-trips, SSE stream, clean drain
with the stream open, port closed after.
- Other examples stay short and on serve*, updated for the split config
(serve_with(cfg, smarm::Config, pipe) / serve_with_shutdown(..., signal)).
plain_serve's URUS_SCHED_THREADS now builds a smarm::Config.
ws_chat's doc block explains the OnceLock is a serve*-only workaround
and points at crud for the clean shape.
- README: new 'Your Own Supervision Tree' section (endpoint as the real
API), graceful shutdown reframed as the serve*-only path, Config table
loses scheduler_threads and gains name, PubSub rule 1 notes the
supervised-sibling alternative.
111 lib + 50 integration + 2 doc tests green; clippy clean.
49 lines
1.8 KiB
Rust
49 lines
1.8 KiB
Rust
//! Serve with an optional TOML config overlay.
|
|
//!
|
|
//! urus is a library and never presumes a config path or reads the
|
|
//! environment for one — the binary decides where the file lives and hands
|
|
//! the text to `Config::with_toml_str`. Here that's a `--config PATH` flag;
|
|
//! with no flag, the compiled defaults are used unchanged.
|
|
//!
|
|
//! Requires the `config-file` feature:
|
|
//! cargo run --example serve_toml --features config-file -- --config urus.toml
|
|
//!
|
|
//! Example urus.toml (all keys optional, sparse override; seconds):
|
|
//! head_timeout_secs = 15
|
|
//! body_timeout_secs = 300
|
|
//! body_burst_bytes = 4096
|
|
//! body_stall_timeout_secs = 20
|
|
|
|
use std::net::SocketAddr;
|
|
|
|
use urus::{serve_with, Config, Conn, Next, Pipeline, Router};
|
|
|
|
fn json_id(conn: Conn, _next: Next) -> Conn {
|
|
let id: u64 = conn.params.get("id").and_then(|s| s.parse().ok()).unwrap_or(0);
|
|
conn.put_status(200)
|
|
.put_header("content-type", "application/json")
|
|
.put_body(format!("{{\"id\":{id}}}"))
|
|
}
|
|
|
|
fn main() {
|
|
let addr: SocketAddr = "0.0.0.0:8080".parse().expect("addr");
|
|
let mut cfg = Config::new(addr);
|
|
|
|
// Minimal flag scan: `--config PATH`. No presumed default location.
|
|
let mut args = std::env::args().skip(1);
|
|
while let Some(arg) = args.next() {
|
|
if arg == "--config" {
|
|
let path = args.next().expect("--config needs a PATH");
|
|
let toml = std::fs::read_to_string(&path)
|
|
.unwrap_or_else(|e| panic!("reading config {path}: {e}"));
|
|
cfg = cfg
|
|
.with_toml_str(&toml)
|
|
.unwrap_or_else(|e| panic!("invalid config {path}: {e}"));
|
|
eprintln!("serve_toml: loaded config from {path}");
|
|
}
|
|
}
|
|
|
|
let pipe = Pipeline::new().plug(Router::new().get("/json/:id", json_id));
|
|
serve_with(cfg, smarm::Config::default(), pipe).expect("serve");
|
|
}
|