diff options
Diffstat (limited to 'src/main.rs')
-rwxr-xr-x | src/main.rs | 113 |
1 files changed, 54 insertions, 59 deletions
diff --git a/src/main.rs b/src/main.rs index 26e1cf0..cddd2f1 100755 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,26 @@ mod atom; +mod db; mod error; mod fs; +mod gatherer; +mod griph; mod ifc; mod markup; mod settings; mod templated; mod timeparse; mod util; -mod db; -use std::{fs::File, io::{BufRead, BufReader, Write}, os::unix::fs::MetadataExt, str::FromStr, sync::Arc, time::Duration}; +use std::{ + fs::File, + io::{BufRead, BufReader, Write}, + os::unix::fs::MetadataExt, + str::FromStr, + sync::Arc, + time::Duration, +}; +use ::time::OffsetDateTime; use axum::{ body::Body, extract::{Path, State}, @@ -25,6 +35,7 @@ use confindent::{Confindent, Node}; use db::Database; pub use error::RuntimeError; use fs::Filesystem; +use gatherer::Gatherer; use settings::Settings; use templated::Frontmatter; use tokio_util::io::ReaderStream; @@ -38,7 +49,8 @@ use crate::{ #[derive(Clone)] pub struct AwakeState { - pub database: Arc<Database> + pub database: Arc<Database>, + pub cache_path: Utf8PathBuf, } #[tokio::main] @@ -64,6 +76,7 @@ async fn main() { let templates = conf.child_value("Templates").unwrap(); let hostname = conf.child_owned("Hostname").unwrap(); let dbpath = conf.child_owned("Database").unwrap(); + let cache = conf.child_owned("Cache").unwrap(); let database = Database::new(dbpath.into()); database.create_tables(); @@ -71,18 +84,24 @@ async fn main() { let fs = Filesystem::new(&webroot); let state = AwakeState { - database: Arc::new(database) + database: Arc::new(database), + cache_path: cache.into(), }; - let mi_state = state.clone(); - let meminfo_thread = std::thread::spawn(move || { - loop { - let meminfo = Meminfo::current(); - mi_state.database.insert_host_meminfo(meminfo); - - std::thread::sleep(Duration::from_secs(60)); + match std::env::args().nth(1).as_deref() { + Some("graph") => { + gatherer::make_mem_graph(&state); } - }); + _ => (), + } + + let mut gatherer = Gatherer::new(state.clone()); + + #[cfg(target_os = "linux")] + gatherer.start(); + + #[cfg(not(target_os = "linux"))] + tracing::warn!("compilation target was not linux; not collecing stat data"); let settings = Settings { template_dir: Utf8PathBuf::from(webroot.join(templates)) @@ -93,9 +112,11 @@ async fn main() { let app = Router::new() .route("/", get(index_handler)) + .route("/api/stats/:name", get(stats)) .route("/*path", get(handler)) .layer(Extension(fs)) - .layer(Extension(settings)).with_state(state); + .layer(Extension(settings)) + .with_state(state); let listener = tokio::net::TcpListener::bind("0.0.0.0:2560").await.unwrap(); axum::serve(listener, app).await.unwrap() @@ -190,6 +211,7 @@ fn redirect<S: Into<String>>(redirection: S) -> Response { const STREAM_AFTER: u64 = 20 * 1024 * 1024; async fn send_file(filepath: Utf8PathBuf) -> Result<Response, RuntimeError> { + tracing::debug!(target: "send_file", filepath = ?filepath); let ext = filepath.extension().unwrap_or_default(); let stem = filepath.file_stem().unwrap_or_default(); @@ -209,6 +231,7 @@ async fn send_file(filepath: Utf8PathBuf) -> Result<Response, RuntimeError> { "png" => "image/png", _ => "", }; + tracing::debug!(target: "send_file", mime = ?mime); let mut response = Response::builder(); if !mime.is_empty() { @@ -223,6 +246,8 @@ async fn send_file(filepath: Utf8PathBuf) -> Result<Response, RuntimeError> { let stream = ReaderStream::new(file); Ok(response.body(Body::from_stream(stream)).unwrap()) } else { + tracing::debug!("small file, sending entirely at once"); + let content = Filesystem::read(filepath).await?; Ok(response.body(Body::from(content)).unwrap()) } @@ -380,63 +405,33 @@ async fn send_template( fn template_content(state: AwakeState, frontmatter: &Frontmatter, marked: String) -> String { let Ok(mut doc) = Document::from_str(&marked, Options::default()) else { - return marked + return marked; }; if frontmatter.get("system-stats").is_some() { let mem = state.database.get_last_host_meminfo(); - doc.set("stats.mem.total", mem.total_kb / 1024); - doc.set("stats.mem.usage", mem.usage() / 1024); + doc.set("stats.mem.total", mem.total_kb / 1000); + doc.set("stats.mem.usage", mem.usage() / 1000); } doc.compile() } -struct Meminfo { - pub total: usize, - pub free: usize, - pub avaialable: usize -} - -impl Meminfo { - pub fn current() -> Self { - let procinfo = File::open("/proc/meminfo").unwrap(); - let bread = BufReader::new(procinfo); +async fn stats(State(state): State<AwakeState>, Path(name): Path<String>) -> Response { + const NAMES: &[&'static str] = &["current_hostmeminfo.gif", "current_hostnetinfo.gif"]; - let mut meminfo = Meminfo { - total: 0, - free: 0, - avaialable: 0 - }; - - for line in bread.lines() { - let line = line.unwrap(); - - if let Some((raw_key, raw_value_kb)) = line.split_once(':') { - let value = if let Some(raw_value) = raw_value_kb.trim().strip_suffix(" kB") { - if let Ok(parsed) = raw_value.parse() { - parsed - } else { - continue; - } - } else { - continue; - }; - - match raw_key.trim() { - "MemTotal" => meminfo.total = value, - "MemFree" => meminfo.free = value, - "MemAvailable" => meminfo.avaialable = value, - _ => () - } - } + if NAMES.contains(&name.as_str()) { + let path = state.cache_path.join(name); + match send_file(path).await { + Ok(resp) => resp, + Err(e) => Response::builder().body(Body::from(e.to_string())).unwrap(), } + } else { + tracing::debug!("invalid stat requested: {name}"); - meminfo - } - - pub fn usage(&self) -> usize { - self.total - self.avaialable + Response::builder() + .body(Body::from("that stat is not real")) + .unwrap() } -} \ No newline at end of file +} |