From 0f189b8e98bd0cd4b54c4e95b5a35caa0db4ed8b Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Wed, 16 Apr 2025 23:02:28 +0200 Subject: [PATCH] CSV generation in the webserver --- src/id_store.rs | 16 ++++++++-------- src/main.rs | 6 +++--- src/webserver.rs | 23 +++++++++++++++++++---- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/id_store.rs b/src/id_store.rs index 92d901b..66ec8dd 100644 --- a/src/id_store.rs +++ b/src/id_store.rs @@ -58,6 +58,7 @@ impl IDStore { } pub fn export_csv(&self) -> Result> { + let mut csv = String::new(); let seperator = ";"; let mut user_ids: HashSet = HashSet::new(); @@ -74,23 +75,22 @@ impl IDStore { days.sort(); let header = days.join(seperator); - println!("ID,{}", header); + csv.push_str(&format!("ID{}{}\n", seperator, header)); for user_id in user_ids.iter() { - print!("{},", user_id.0); + csv.push_str(&user_id.0.to_string()); for day in days.iter() { - let was_there: bool = self.days.get(day).unwrap().ids.contains(user_id); + let was_there: bool = self.days.get(day).ok_or("Failed to access day")?.ids.contains(user_id); if was_there { - print!("{}x", seperator); + csv.push_str(&format!("{}x", seperator)); } else { - print!("{}", seperator); + csv.push_str(seperator); } } - println!(); + csv.push('\n'); } - - Ok("".to_owned()) + Ok(csv) } } diff --git a/src/main.rs b/src/main.rs index 0c012e5..5322503 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,15 +26,15 @@ async fn main() { }); let store:Arc> = Arc::new(Mutex::new(id_store::IDStore::new())); + let channel_store = store.clone(); tokio::spawn(async move { while let Some(tally_id_string) = rx.recv().await { - println!("Got from channel: {}", tally_id_string); - store.lock().await.add_id(id_store::TallyID(tally_id_string)); + channel_store.lock().await.add_id(id_store::TallyID(tally_id_string)); } }); - match start_webserver().await { + match start_webserver(store.clone()).await { Ok(()) => {} Err(e) => { eprintln!("Failed to start webserver: {}", e); diff --git a/src/webserver.rs b/src/webserver.rs index e36ec9f..f2fdf1c 100644 --- a/src/webserver.rs +++ b/src/webserver.rs @@ -1,15 +1,19 @@ -use rocket::Config; +use rocket::http::Status; +use rocket::{Config, State}; use rocket::{get, http::ContentType, response::content::RawHtml, routes}; use rust_embed::Embed; use std::borrow::Cow; use std::ffi::OsStr; +use std::sync::Arc; +use tokio::sync::Mutex; +use crate::id_store::IDStore; #[derive(Embed)] #[folder = "web/dist"] struct Asset; -pub async fn start_webserver() -> Result<(), rocket::Error> { +pub async fn start_webserver(store: Arc>) -> Result<(), rocket::Error> { let config = Config { address: "0.0.0.0".parse().unwrap(), // Listen on all interfaces port: 8000, @@ -17,13 +21,13 @@ pub async fn start_webserver() -> Result<(), rocket::Error> { }; rocket::custom(config) - .mount("/", routes![static_files,index]) + .mount("/", routes![static_files, index, export_csv]) + .manage(store) .launch() .await?; Ok(()) } - #[get("/")] fn index() -> Option>> { let asset = Asset::get("index.html")?; @@ -42,3 +46,14 @@ fn static_files(file: std::path::PathBuf) -> Option<(ContentType, Vec)> { Some((content_type, asset.data.into_owned())) } + +#[get("/api/csv")] +async fn export_csv(manager: &State>>) -> Result { + match manager.lock().await.export_csv() { + Ok(csv) => Ok(csv), + Err(e) => { + eprintln!("Failed to generate csv: {}", e); + Err(Status::InternalServerError) + } + } +}