Added persistent counts, faster RNG, stats in page
This commit is contained in:
parent
d602984fbd
commit
f40478a58d
4 changed files with 63 additions and 37 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
count.txt
|
||||||
|
|
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -1,6 +1,6 @@
|
||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 4
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
|
@ -127,9 +127,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-lc-sys"
|
name = "aws-lc-sys"
|
||||||
version = "0.28.1"
|
version = "0.28.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ddeb19ee86cb16ecfc871e5b0660aff6285760957aaedda6284cf0e790d3769"
|
checksum = "bfa9b6986f250236c27e5a204062434a773a13243d2ffc2955f37bdba4c5c6a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bindgen",
|
"bindgen",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -287,9 +287,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.19"
|
version = "1.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
|
checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -503,9 +503,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.15"
|
version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -992,7 +992,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.16",
|
||||||
"libc",
|
"libc",
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -1175,9 +1175,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1229,9 +1229,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.14"
|
version = "0.7.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034"
|
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -1543,18 +1543,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.24"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879"
|
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.24"
|
version = "0.8.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be"
|
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "babble"
|
name = "babble"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
# edition = "2024"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "0.8.3"
|
axum = "0.8.3"
|
||||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -1,18 +1,18 @@
|
||||||
mod generator;
|
mod generator;
|
||||||
|
|
||||||
use axum::{Router, extract::Path, response::Html, routing::get};
|
use axum::{extract::Path, response::Html, routing::get, Router};
|
||||||
use axum_server::{bind_rustls, tls_rustls::RustlsConfig};
|
use axum_server::{bind_rustls, tls_rustls::RustlsConfig};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rand::{Rng as _, prelude::*, random_range};
|
use rand::{prelude::*, Rng as _};
|
||||||
use rand_chacha::{ChaCha8Rng, rand_core::SeedableRng};
|
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{
|
sync::{
|
||||||
Arc,
|
|
||||||
atomic::{AtomicU64, Ordering},
|
atomic::{AtomicU64, Ordering},
|
||||||
|
Arc,
|
||||||
},
|
},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
@ -32,6 +32,17 @@ pub struct Args {
|
||||||
key: Option<PathBuf>,
|
key: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn create_rng(seed_bytes: impl IntoIterator<Item = u8>) -> Rng {
|
||||||
|
let mut seed = [0; 32];
|
||||||
|
for (i, b) in seed_bytes.into_iter().take(seed.len()).enumerate() {
|
||||||
|
seed[i] = b;
|
||||||
|
}
|
||||||
|
Rng::from_seed(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
const COUNT_FILE: &str = "count.txt";
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
@ -41,43 +52,54 @@ async fn main() {
|
||||||
Arc::new(generator::Ast::new()),
|
Arc::new(generator::Ast::new()),
|
||||||
];
|
];
|
||||||
|
|
||||||
let counter = Arc::new(AtomicU64::new(0));
|
let counter = Arc::new(AtomicU64::new(
|
||||||
|
if let Some(prev_count) = std::fs::read_to_string(COUNT_FILE)
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse().ok())
|
||||||
|
{
|
||||||
|
prev_count
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
));
|
||||||
|
|
||||||
let app = {
|
let app = {
|
||||||
let counter = counter.clone();
|
let counter = counter.clone();
|
||||||
Router::new().route(
|
Router::new().route(
|
||||||
"/{id}",
|
"/{id}",
|
||||||
get(|Path(id): Path<String>| async move {
|
get(|Path(id): Path<String>| async move {
|
||||||
tokio::time::sleep(Duration::from_millis(random_range(200..1000))).await;
|
// Create a RNG for this path (deterministic, to simulate static pages)
|
||||||
counter.fetch_add(1, Ordering::Relaxed);
|
let mut rng = create_rng(id.bytes());
|
||||||
|
|
||||||
let mut seed = [0; 32];
|
// Count the request. Also doubles as the non-deterministic seed
|
||||||
for (i, b) in id
|
let count = counter.fetch_add(1, Ordering::Relaxed);
|
||||||
.bytes()
|
|
||||||
.chain(core::iter::repeat(0))
|
|
||||||
.take(seed.len())
|
|
||||||
.enumerate()
|
|
||||||
{
|
|
||||||
seed[i] = b;
|
|
||||||
}
|
|
||||||
let mut rng = Rng::from_seed(seed);
|
|
||||||
|
|
||||||
|
// Create a RNG for this session (non-deterministic)
|
||||||
|
let mut session_rng = create_rng(count.to_le_bytes());
|
||||||
|
|
||||||
|
// Artificially slow down connections as rudimentary DDoS protection, and to use up client resources
|
||||||
|
tokio::time::sleep(Duration::from_millis(session_rng.random_range(200..1000)))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
// Choose a bullshit generator from our collection for this page
|
||||||
let generator = generators.choose(&mut rng).unwrap();
|
let generator = generators.choose(&mut rng).unwrap();
|
||||||
|
|
||||||
let title = generator
|
let title = generator
|
||||||
.word_stream(rng.random_range(2..10), &mut rng.clone())
|
.word_stream(rng.random_range(2..10), &mut rng.clone())
|
||||||
.join(" ");
|
.join(" ");
|
||||||
|
|
||||||
|
let stats = format!("Served rubbish to {count} clients so far");
|
||||||
|
|
||||||
let content = generator
|
let content = generator
|
||||||
.word_stream(rng.random_range(50..5_000), &mut rng.clone())
|
.word_stream(rng.random_range(50..5_000), &mut rng.clone())
|
||||||
.fold(String::new(), |mut content, word| {
|
.fold(String::new(), |mut content, word| {
|
||||||
|
// Small chance of every word becoming a link back into the void
|
||||||
if rng.random_bool(0.05) {
|
if rng.random_bool(0.05) {
|
||||||
let url = generator.word_stream(3, &mut rng.clone()).join("-");
|
let url = generator.word_stream(3, &mut rng.clone()).join("-");
|
||||||
content += &format!(" <a href=\"{}\">{}</a>", url, word);
|
content += &format!(" <a href=\"{}\">{}</a>", url, word);
|
||||||
} else if rng.random_bool(0.01) {
|
|
||||||
content += ".<br>";
|
|
||||||
} else {
|
} else {
|
||||||
content += " ";
|
// Also, a chance for every word to end with a newline. This should probably be controlled by the generator.
|
||||||
|
content += if rng.random_bool(0.01) { ".<br>" } else { " " };
|
||||||
content += &word
|
content += &word
|
||||||
}
|
}
|
||||||
content
|
content
|
||||||
|
@ -92,6 +114,7 @@ async fn main() {
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
|
<p>{stats}</p>
|
||||||
<p>{content}</p>
|
<p>{content}</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -116,6 +139,7 @@ async fn main() {
|
||||||
chrono::offset::Local::now(),
|
chrono::offset::Local::now(),
|
||||||
count,
|
count,
|
||||||
);
|
);
|
||||||
|
let _ = std::fs::write(COUNT_FILE, &format!("{count}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue