use std::sync::{ atomic::{AtomicI64, Ordering}, Arc, }; use axum::{ extract::{Path, State}, http::StatusCode, response::{IntoResponse, Response}, routing::get, Router, }; use tokio::sync::watch::Sender; use crate::database::Database; #[derive(Clone)] struct SharedState { database: Database, rating: Arc, mpris_sender: Sender<(String, String)>, } pub async fn http_serve(database: &Database, mpris_producer: Sender<(String, String)>) { let database = database.clone(); let rating = Arc::new(AtomicI64::new(0)); let shared_state = SharedState { database, rating, mpris_sender: mpris_producer, }; let app = Router::new() .route("/", get(root)) .route("/rating/{rating}", get(cache_rating_only)) .route("/userid/{user_id}", get(add_userid)) .route("/{user_id}/{rating}", get(add_rating)) .with_state(shared_state); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); axum::serve(listener, app).await.unwrap(); } async fn root() -> impl IntoResponse { (StatusCode::OK, "Use /{user_id}/{rating}") } async fn add_rating( Path((user_id, rating)): Path<(i64, i64)>, State(shared): State, ) -> Response { let mut mpris_rx = shared.mpris_sender.subscribe(); // Get the current interpret and track from the watch channel let (interpret, track) = (*mpris_rx.borrow_and_update()).clone(); match shared .database .user_add_rating(user_id, &interpret, &track, rating) .await { Ok(_) => (StatusCode::OK, "Done.").into_response(), Err(e) => { println!("HTTP error: {e}"); (StatusCode::BAD_REQUEST, e.to_string()).into_response() } } } async fn cache_rating_only(Path(rating): Path, State(shared): State) -> Response { shared.rating.store(rating, Ordering::Relaxed); (StatusCode::OK, "Done.").into_response() } async fn add_userid(Path(user_id): Path, State(shared): State) -> Response { let mut mpris_rx = shared.mpris_sender.subscribe(); // Get the current interpret and track from the watch channel let (interpret, track) = (*mpris_rx.borrow_and_update()).clone(); let rating = shared.rating.load(Ordering::Relaxed); match shared .database .user_add_rating(user_id, &interpret, &track, rating) .await { Ok(_) => (StatusCode::OK, "Done.").into_response(), Err(e) => { println!("HTTP error: {e}"); (StatusCode::BAD_REQUEST, e.to_string()).into_response() } } }