Skip to main content

server/
server.rs

1use std::{fs, process};
2use nwep::{
3    Keypair,
4    server::{Router, ResponseWriter, Request, ServerBuilder},
5};
6
7const DEFAULT_KEY_FILE: &str = "server.key";
8const DEFAULT_ADDR: &str = "[::]:6937";
9
10fn load_or_generate_keypair(path: &str) -> Result<Keypair, Box<dyn std::error::Error>> {
11    match fs::read_to_string(path) {
12        Ok(contents) => {
13            let hex = contents.trim();
14            if hex.len() != 64 {
15                return Err(format!("invalid key file {path}: expected 64 hex chars").into());
16            }
17            let bytes: Vec<u8> = (0..32)
18                .map(|i| u8::from_str_radix(&hex[i * 2..i * 2 + 2], 16))
19                .collect::<Result<_, _>>()?;
20            let mut seed = [0u8; 32];
21            seed.copy_from_slice(&bytes);
22            Ok(Keypair::from_seed(&seed)?)
23        }
24        Err(e) if e.kind() == std::io::ErrorKind::NotFound => {
25            let kp = Keypair::generate()?;
26            let hex: String = kp.seed().iter().map(|b| format!("{b:02x}")).collect();
27            fs::write(path, format!("{hex}\n"))
28                .map_err(|e| format!("saving key file: {e}"))?;
29            Ok(kp)
30        }
31        Err(e) => Err(e.into()),
32    }
33}
34
35fn main() {
36    nwep::init().unwrap_or_else(|e| {
37        eprintln!("init: {e}");
38        process::exit(1);
39    });
40
41    let key_file = std::env::var("NWEP_KEY_FILE").unwrap_or_else(|_| DEFAULT_KEY_FILE.into());
42    let keypair = load_or_generate_keypair(&key_file).unwrap_or_else(|e| {
43        eprintln!("keypair: {e}");
44        process::exit(1);
45    });
46
47    let node_id = keypair.node_id().unwrap_or_else(|e| {
48        eprintln!("node_id: {e}");
49        process::exit(1);
50    });
51    eprintln!("node id: {node_id}");
52
53    let mut router = Router::new();
54    router.handle_func("/hello", |w: &mut ResponseWriter, _r: &Request| {
55        let _ = w.respond("ok", b"hello from nwep-rust");
56    });
57
58    let addr = std::env::args().nth(1).unwrap_or_else(|| DEFAULT_ADDR.into());
59
60    let (server, event_loop) = ServerBuilder::new(&addr, keypair)
61        .on_connect(|info| eprintln!("connected: {}", info.node_id))
62        .on_disconnect(|info, code| eprintln!("disconnected: {} (code {code})", info.node_id))
63        .build(router)
64        .unwrap_or_else(|e| {
65            eprintln!("server: {e}");
66            process::exit(1);
67        });
68
69    let url = server.url("/hello");
70    eprintln!("listening on {}", server.addr());
71    println!("{url}"); // URL printed to stdout for the client to read
72
73    if let Err(e) = event_loop.run() {
74        eprintln!("server run: {e}");
75        process::exit(1);
76    }
77}