#[macro_use] extern crate rocket; use std::sync::atomic::Ordering; use std::sync::Mutex; use rocket::serde::{Deserialize, Serialize, json::Json}; use rocket::State; use rocket::Request; use rocket::Response; use rocket::http::Header; #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] struct Page { slug: String, votes: i32 } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(crate = "rocket::serde")] struct VoteRecord { pages: Vec } struct AppState { record: Mutex } #[get("/votes/view/")] fn view_votes(slug: String, state: &State) -> Json { println!("Requesting votes for {slug}"); //Json(state.leaderboard.lock().unwrap().clone()) for page in &state.record.lock().unwrap().pages { if page.slug == slug { return Json(page.clone()) } } return Json(Page { slug, votes: 0 }) } #[post("/votes/submit/")] fn leaderboard_submit_score(slug: String, state: &State) { println!("Submitting vote for {slug}"); let mut found = false; for mut page in &mut state.record.lock().unwrap().pages { if page.slug == slug { page.votes += 1; found = true; } } if !found { state.record.lock().unwrap().pages.push(Page { slug, votes: 1 }); } println!("{:#?}", state.record.lock()); } use rocket::fairing::{Fairing, Info, Kind}; pub struct CORS; #[rocket::async_trait] impl Fairing for CORS { fn info(&self) -> Info { Info { name: "Add CORS headers to responses", kind: Kind::Response } } async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) { response.set_header(Header::new("Access-Control-Allow-Origin", "*")); response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS")); response.set_header(Header::new("Access-Control-Allow-Headers", "*")); response.set_header(Header::new("Access-Control-Allow-Credentials", "true")); } } #[rocket::main] async fn main() -> Result<(), rocket::error::Error> { let initial_state = if let Ok(data) = std::fs::read_to_string("votes.json") { AppState { record: Mutex::new(serde_json::from_str(&data).expect("Failed to parse")) } } else { AppState { record: Mutex::new(VoteRecord { pages: vec![] }) } }; let rocket = rocket::build() .mount("/", routes![view_votes, leaderboard_submit_score]) .manage(initial_state) .attach(CORS) .ignite().await? .launch().await?; let state = rocket.state::().unwrap(); serde_json::to_writer(&std::fs::File::create("votes.json").unwrap(), &state.record).expect("TODO: panic message"); Ok(()) }