use axum::{Router, response::Html, routing::get}; use std::{fs::OpenOptions, io::{BufRead, Read}, path::Path}; use tower_http::services::ServeDir; const PUBKEY_PATH: &str = "./pubkeys/public_keys.json"; lazy_static::lazy_static! { static ref PUBLIC_KEYS: Vec> = load_public_keys(PUBKEY_PATH).expect("static path"); } type Error = Box; type Result = std::result::Result; fn load_public_keys(path: impl AsRef) -> std::io::Result>> { // Open the file let f = OpenOptions::new() .read(true) .write(false) .open(path)?; // Wrap it in a BufReader for efficient line-by-line reading let reader = std::io::BufReader::new(f); let mut public_keys = Vec::new(); // Iterate over each line in the file for line_result in reader.lines() { let line = line_result?; // Handle potential IO errors during reading // Skip empty lines or lines with only whitespace let trimmed_line = line.trim(); if trimmed_line.is_empty() { continue; } // Deserialize the line (which is a single JSON array) into a Vec let key: Vec = serde_json::from_str(trimmed_line).map_err(|e| { std::io::Error::new( std::io::ErrorKind::InvalidData, format!("Failed to parse JSON line: {}", e), ) })?; public_keys.push(key); } Ok(public_keys) } #[tokio::main] async fn main() -> Result<()> { // build our application with a single route let app = Router::new() .route("/", get(serve_path("./routes/root/index.html")?)) .route("/who", get(serve_path("./routes/who/index.html")?)) .route("/api/pubkey", get(async || select_key(&PUBLIC_KEYS))) .route("/contact", get(serve_path("./routes/contact/index.html")?)) .nest_service("/routes", ServeDir::new("./routes")); // run our app with hyper, listening globally on port 3000 let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); Ok(()) } fn select_key(pks: &Vec>) -> String { let idx = getrandom::u64().expect("random integer") as usize % pks.len(); serde_json::to_string(&pks[idx]).expect("serialize vec of bytes") } fn serve_path(path: impl AsRef) -> Result> { let mut s = String::new(); OpenOptions::new() .read(true) .write(false) .open(path)? .read_to_string(&mut s)?; Ok(Html(s)) }