aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main.rs136
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 {