diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 136 |
1 files changed, 76 insertions, 60 deletions
diff --git a/src/main.rs b/src/main.rs index 760247a..8e61fc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,15 +27,18 @@ struct Args { /// port for serving http traffic #[arg(short, long, default_value_t = 3200)] port: u16, + /// delay all responses (in milliseconds) + #[arg(short, long, default_value_t = 0)] + delay: u32, } #[tokio::main] async fn main() -> Result<ExitCode, Box<dyn std::error::Error + Send + Sync>> { let args = Args::parse(); - tracing_subscriber::fmt::init(); + tracing_subscriber::fmt::fmt().init(); - let svc = RandomPageService::new(args.seed.as_str()); + let svc = RandomPageService::new(&args); let addr = SocketAddr::from(([127, 0, 0, 1], args.port)); @@ -58,20 +61,21 @@ async fn main() -> Result<ExitCode, Box<dyn std::error::Error + Send + Sync>> { #[derive(Debug, Clone)] struct RandomPageService { - pub seed: String, - pub dict: Arc<Vec<&'static str>>, - pub dict_set: Arc<HashSet<&'static str>>, + pub ctx: Arc<PageGenerator>, } impl RandomPageService { - pub fn new(seed: &str) -> Self { + pub fn new(args: &Args) -> Self { let dictionary_data = include_bytes!(env!("DICTIONARY_FILE_PATH")); let dictionary_string: &'static str = std::str::from_utf8(dictionary_data).unwrap(); Self { - seed: seed.to_string(), - dict: Arc::new(dictionary_string.split_whitespace().collect()), - dict_set: Arc::new(dictionary_string.split_whitespace().collect()), + ctx: Arc::new(PageGenerator { + seed: args.seed.clone(), + delay: args.delay, + dict: dictionary_string.split_whitespace().collect(), + dict_set: dictionary_string.split_whitespace().collect(), + }), } } } @@ -96,25 +100,15 @@ impl Service<Request<hyper::body::Incoming>> for RandomPageService { ) } - let path = req.uri().path(); + let ctx = self.ctx.clone(); - tracing::info!(path, "path"); - - let path_segments = path.split('/').filter(|v| v.len() > 0); - - for segment in path_segments { - if !self.dict_set.contains(segment) { - return Box::pin(async { - mk_response("not found".to_string(), StatusCode::NOT_FOUND) - }); + Box::pin(async move { + let path = req.uri().path(); + match ctx.build_page(path).await { + Ok(body) => mk_response(body, StatusCode::OK), + Err((err_message, code)) => mk_response(err_message.to_string(), code), } - } - - let res_body = build_page(&self.seed, path, &self.dict); - - let res = mk_response(res_body, StatusCode::OK); - - Box::pin(async { res }) + }) } } @@ -122,40 +116,62 @@ const MAX_ROUTE_SEGMENTS: usize = 6; const PARAGRAPH_WORDS: RangeInclusive<usize> = 10..=200; const N_LINKS: RangeInclusive<usize> = 3..=10; -pub fn build_page( - base_seed: &str, - route: &str, - dictionary: &[&'static str], -) -> String { - let mut rng: Pcg64 = - Seeder::from(format!("{}---{}", base_seed, route)).make_rng(); - let n_words = rng.gen_range(PARAGRAPH_WORDS); - let n_links = rng.gen_range(N_LINKS); - - let random_paragraph = (0..n_words) - .map(|_| random_word(&mut rng, dictionary)) - .collect::<Vec<&str>>() - .join(" "); - - let random_links = (0..n_links) - .map(|_| random_route_link(&mut rng, dictionary)) - .map(|link| format!("<p>{}</p>", link)) - .collect::<Vec<String>>() - .join("\n"); - - format!( - r#" - <html> - <head> - </head> - <body> - <p>{}</p> - {} - </body> - </html> - "#, - random_paragraph, random_links, - ) +#[derive(Debug)] +struct PageGenerator { + seed: String, + delay: u32, + dict: Vec<&'static str>, + dict_set: HashSet<&'static str>, +} + +impl PageGenerator { + async fn build_page( + &self, + route: &str, + ) -> Result<String, (&'static str, StatusCode)> { + if self.delay > 0 { + tokio::time::sleep(tokio::time::Duration::from_millis(self.delay as u64)) + .await; + } + + for segment in route.split('/').filter(|v| v.len() > 0) { + if !self.dict_set.contains(segment) { + return Err(("not found", StatusCode::NOT_FOUND)); + } + } + + let mut rng: Pcg64 = + Seeder::from(format!("{}---{}", self.seed, route)).make_rng(); + let n_words = rng.gen_range(PARAGRAPH_WORDS); + let n_links = rng.gen_range(N_LINKS); + + let random_paragraph = (0..n_words) + .map(|_| random_word(&mut rng, &self.dict)) + .collect::<Vec<&str>>() + .join(" "); + + let random_links = (0..n_links) + .map(|_| random_route_link(&mut rng, &self.dict)) + .map(|link| format!("<p>{}</p>", link)) + .collect::<Vec<String>>() + .join("\n"); + + tracing::info!(route); + + Ok(format!( + r#" + <html> + <head> + </head> + <body> + <p>{}</p> + {} + </body> + </html> + "#, + random_paragraph, random_links, + )) + } } fn random_route_link(rng: &mut Pcg64, dictionary: &[&'static str]) -> String { |