Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_net/src/bin/localserve.rs

1.9 KiB, 1 run

created by r1870400018:58835, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//! `localserve` -- a std-only static file server for a directory, from the command line.
2//!
3//! The tokio-free [`LocalServer`](oxedyne_fe2o3_net::http::local::LocalServer) as a standalone tool: the
4//! drop-in replacement for `python3 -m http.server` a dev-preview loop reaches for. It has no
5//! required-features, so it builds under `--no-default-features` -- the whole point being a static server
6//! that pulls in neither an async runtime nor a TLS stack.
7//!
8//! ```text
9//! localserve <DIR> [--port N] [--lan]
10//! ```
11//!
12//! Loopback (`127.0.0.1`) by default; `--lan` binds `0.0.0.0` so a phone on the same network can reach
13//! the preview. Port `0` (the default) asks the OS for an ephemeral one and prints what it chose.
14
15use oxedyne_fe2o3_net::http::local::{
16 Listen,
17 LocalServer,
18};
19
20use oxedyne_fe2o3_core::prelude::*;
21
22fn main() -> Outcome<()> {
23 let args: Vec<String> = std::env::args().skip(1).collect();
24 let dir = match args.first().filter(|a| !a.starts_with("--")) {
25 Some(d) => d.clone(),
26 None => {
27 println!("usage: localserve <DIR> [--port N] [--lan]");
28 return Ok(());
29 },
30 };
31 let port = match flag_value(&args, "--port") {
32 Some(s) => match s.parse::<u16>() {
33 Ok(v) => v,
34 Err(e) => return Err(err!("'{}' is not a valid --port value: {}.", s, e; Input, Invalid)),
35 },
36 None => 0,
37 };
38 let lan = has_flag(&args, "--lan");
39 let listen = if lan { Listen::Any(port) } else { Listen::Loopback(port) };
40
41 let listener = res!(LocalServer::bind(listen));
42 let bound = res!(listener.local_addr(), IO, Network);
43 let host = if lan { "0.0.0.0" } else { "127.0.0.1" };
44 println!("localserve: serving {} at http://{}:{}/", dir, host, bound.port());
45
46 LocalServer::dir(dir).serve(listener)
47}
48
49fn flag_value(args: &[String], name: &str) -> Option<String> {
50 args.iter().position(|a| a == name).and_then(|i| args.get(i + 1)).cloned()
51}
52
53fn has_flag(args: &[String], name: &str) -> bool {
54 args.iter().any(|a| a == name)
55}