diff options
Diffstat (limited to 'corgi_stats')
-rw-r--r-- | corgi_stats/Cargo.toml | 8 | ||||
-rw-r--r-- | corgi_stats/src/main.rs | 132 | ||||
-rw-r--r-- | corgi_stats/src/style.css | 37 |
3 files changed, 0 insertions, 177 deletions
diff --git a/corgi_stats/Cargo.toml b/corgi_stats/Cargo.toml deleted file mode 100644 index a012b94..0000000 --- a/corgi_stats/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "corgi-stats" -version = "0.1.0" -edition = "2024" - -[dependencies] -rusqlite = { version = "0.34.0", features = ["bundled", "time"] } -time = "0.3.40" diff --git a/corgi_stats/src/main.rs b/corgi_stats/src/main.rs deleted file mode 100644 index 2e0c372..0000000 --- a/corgi_stats/src/main.rs +++ /dev/null @@ -1,132 +0,0 @@ -use rusqlite::{Connection, params}; -use std::time::Instant; -use time::{Duration, OffsetDateTime}; - -// Thank you, cat, for optimizing my query -const TOP_TEN_ALL_TIME: &str = "\ - SELECT reqs.cnt, agents.agent - FROM agents - JOIN ( - SELECT count(id) as cnt, agent_id - FROM requests - GROUP BY agent_id - ) reqs - ON reqs.agent_id=agents.id - ORDER BY reqs.cnt DESC LIMIT 10; -"; - -const STYLE: &'static str = include_str!("style.css"); - -fn main() { - let db_path = std::env::var("CORGI_STATS_DB").ok(); - let db = if let Some(path) = db_path { - if let Ok(db) = Connection::open(path) { - db - } else { - error_and_die(500, "failed to open database"); - } - } else { - error_and_die(500, "database key not set"); - }; - - let now = OffsetDateTime::now_utc(); - let fifteen_ago = now - Duration::minutes(15); - - let query = "SELECT count(requests.id) AS request_count, agents.agent FROM requests \ - INNER JOIN agents ON requests.agent_id = agents.id \ - WHERE requests.timestamp > ?1 \ - GROUP BY requests.agent_id;"; - - let mut prepared = db.prepare(query).unwrap(); - let mut agents: Vec<(usize, String)> = prepared - .query_map(params![fifteen_ago], |row| Ok((row.get(0)?, row.get(1)?))) - .unwrap() - .map(|r| r.unwrap()) - .collect(); - - agents.sort_by(|a, b| a.0.cmp(&b.0).reverse()); - - let mut prepared = db.prepare(TOP_TEN_ALL_TIME).unwrap(); - let highest_five: Vec<(usize, String)> = prepared - .query_map(params![], |row| Ok((row.get(0)?, row.get(1)?))) - .unwrap() - .map(|r| r.unwrap()) - .collect(); - let sum_highest_five = highest_five.iter().fold(0, |acc, (count, _)| acc + count); - - println!("Content-Type: text/html\n"); - println!("<html>"); - #[rustfmt::skip] - println!("<head>\n\ - <title>corgi stats</title>\n\ - <style>\n{STYLE}\n</style>\n\ - </head>"); - - println!("<body>"); - println!("<h1>Corgi Stats :)</h1>"); - - #[rustfmt::skip] - println!("<table>\n\ - <thead>\n\ - \t<tr>\n\ - \t\t<th scope='row' colspan='3' class='ttitle'>Requests for the last 15 minutes</th>\n\ - \t</tr>\n\ - \t<tr>\n\ - \t\t<th># Req.</th>\n\ - \t\t<th>Req/min</th>\n\ - \t\t<th>Agent</th>\n\ - \t</tr>\n\ - </thead>\n<tbody>"); - - for (count, agent) in &agents { - #[rustfmt::skip] - println!("<tr>\n\ - \t<td>{count}</td>\n\ - \t<td>{:.1}</td>\n\ - \t<td>{agent}</td>\n\ - </tr>", - *count as f32 / 15.0); - } - - println!("</tbody>\n</table>"); - - #[rustfmt::skip] - println!("<table>\n\ - <thead>\n\ - \t<tr>\n\ - \t\t<th scope='row' colspan='3' class='ttitle'>Top 10 User Agents All Time</th>\n\ - \t</tr>\n\ - \t<tr>\n\ - \t\t<th># Req.</th>\n\ - \t\t<th>Req/min</th>\n\ - \t\t<th>Agent</th>\n\ - \t</tr>\n\ - </thead>\n<tbody>"); - - // Finish what we started - println!("</body>\n</html>"); - - for (count, agent) in highest_five { - #[rustfmt::skip] - println!("<tr>\n\ - \t<td>{count}</td>\n\ - \t<td>{:.1}</td>\n\ - \t<td>{agent}</td>\n\ - </tr>", - (count as f32 / sum_highest_five as f32) * 100.0); - } -} - -fn error_and_die<S: Into<String>>(status: u16, msg: S) -> ! { - println!("Status: {status}"); - println!("Content-Type: text/html\n"); - println!("<html>"); - println!("\t<head><title>{status}</title></head>"); - println!("\t<body style='width: 20rem; padding: 0px; margin: 2rem;'>"); - println!("\t\t<h1>{status}</h1>"); - println!("\t\t<hr/>"); - println!("\t\t<p>{}</p>", msg.into()); - println!("\t</body>\n</html>"); - - std::process::exit(0); -} diff --git a/corgi_stats/src/style.css b/corgi_stats/src/style.css deleted file mode 100644 index 5b3995d..0000000 --- a/corgi_stats/src/style.css +++ /dev/null @@ -1,37 +0,0 @@ -h1 { - font-family: sans-serif; -} - -table { - border-collapse: collapse; - border: 2px solid gray; - margin: 1rem 0px; -} - -tr { - background-color: white; -} - -tbody>tr:nth-of-type(odd) { - background-color: cornsilk; -} - -th, -td { - border: 1px solid darkslateblue; - padding: 2px 3px; -} - -thead th { - background-color: darksalmon; -} - -th { - text-align: left; - padding: 4px 6px; - white-space: nowrap; -} - -th.ttitle { - text-align: center; -} \ No newline at end of file |