From 92a59773499c66548a68b978ae111f35bba09e93 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 19:44:18 -0400 Subject: [PATCH 1/9] Added migrations Added new table to store metadata --- migrations/20250420185217_init_migration.sql | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/migrations/20250420185217_init_migration.sql b/migrations/20250420185217_init_migration.sql index cb96059..3c53c1a 100644 --- a/migrations/20250420185217_init_migration.sql +++ b/migrations/20250420185217_init_migration.sql @@ -6,4 +6,13 @@ CREATE TABLE IF NOT EXISTS "songQueue" ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), filename TEXT NOT NULL, data BYTEA NOT NULL -); \ No newline at end of file +); + +CREATE TABLE IF NOT EXISTS "metadataQueue" ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + metadata jsonb NOT NULL, + created_at timestamp DEFAULT now() +); + +-- Create an index for better query performance +CREATE INDEX metadata_queue_data_metadata ON "metadataQueue" USING gin (metadata); \ No newline at end of file -- 2.47.3 From a42f9a5f5f9b0bdbbb4e9a68106260894baca2eb Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:07:54 -0400 Subject: [PATCH 2/9] Updated table --- migrations/20250420185217_init_migration.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/migrations/20250420185217_init_migration.sql b/migrations/20250420185217_init_migration.sql index 3c53c1a..57615c4 100644 --- a/migrations/20250420185217_init_migration.sql +++ b/migrations/20250420185217_init_migration.sql @@ -11,7 +11,8 @@ CREATE TABLE IF NOT EXISTS "songQueue" ( CREATE TABLE IF NOT EXISTS "metadataQueue" ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), metadata jsonb NOT NULL, - created_at timestamp DEFAULT now() + created_at timestamp DEFAULT now(), + song_queue_id UUID NOT NULL ); -- Create an index for better query performance -- 2.47.3 From 0638e7e16d4b0dcdcca78ec1cc3a24f6ff546c61 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:08:15 -0400 Subject: [PATCH 3/9] Added code for new endpoint --- src/callers/metadata.rs | 103 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 src/callers/metadata.rs diff --git a/src/callers/metadata.rs b/src/callers/metadata.rs new file mode 100644 index 0000000..d317bd0 --- /dev/null +++ b/src/callers/metadata.rs @@ -0,0 +1,103 @@ +pub mod request { + use serde::{Deserialize, Serialize}; + + #[derive(Default, Deserialize, Serialize)] + pub struct Request { + pub id: uuid::Uuid, + pub album: String, + pub album_artist: String, + pub artist: String, + pub disc: i32, + pub disc_count: i32, + pub duration: i64, + pub genre: String, + pub title: String, + pub track: i32, + pub track_count: i32, + pub year: i32, + } +} + +pub mod response { + use serde::{Deserialize, Serialize}; + + #[derive(Default, Deserialize, Serialize)] + pub struct Response { + pub message: String, + pub data: Vec, + } +} + +mod metadata_queue { + use sqlx::Row; + + #[derive(Debug, serde::Serialize, sqlx::FromRow)] + pub struct InsertedData { + pub id: uuid::Uuid, + } + + pub async fn insert( + pool: &sqlx::PgPool, + metadata: &String, + song_queue_id: &uuid::Uuid, + ) -> Result { + let result = sqlx::query( + r#" + INSERT INTO "metadataQueue" (metadata, song_queue_id) VALUES($1, $2) RETURNING id; + "#, + ) + .bind(metadata) + .bind(song_queue_id) + .fetch_one(pool) + .await + .map_err(|e| { + eprintln!("Error inserting: {}", e); + }); + + match result { + Ok(row) => { + let id: uuid::Uuid = row + .try_get("id") + .map_err(|_e| sqlx::Error::RowNotFound) + .unwrap(); + Ok(id) + } + Err(_err) => Err(sqlx::Error::RowNotFound), + } + } +} + +pub mod endpoint { + use axum::{Json, http::StatusCode}; + + pub async fn queue_metadata( + axum::Extension(pool): axum::Extension, + Json(payload): Json, + ) -> (StatusCode, Json) { + let mut results: Vec = Vec::new(); + let mut response = super::response::Response::default(); + match serde_json::to_string_pretty(&payload) { + Ok(meta) => match super::metadata_queue::insert(&pool, &meta, &payload.id).await { + Ok(id) => { + results.push(id); + response.data = results; + response.message = if response.data.is_empty() { + String::from("Error") + } else { + String::from("Success") + }; + + (StatusCode::OK, Json(response)) + } + Err(err) => { + response.message = err.to_string(); + (StatusCode::BAD_REQUEST, Json(response)) + } + }, + Err(err) => { + response.message = err.to_string(); + (StatusCode::BAD_REQUEST, Json(response)) + } + } + } +} -- 2.47.3 From 9cb54255384926d6c47c39280e200ec016dbbd08 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:08:24 -0400 Subject: [PATCH 4/9] Updated module --- src/callers/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index 9ee3d1a..edccd1c 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -1,3 +1,4 @@ +pub mod metadata; pub mod song; pub mod endpoints { -- 2.47.3 From b077f36c8bab056e904e943d9afc1363ab0fe42b Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:08:36 -0400 Subject: [PATCH 5/9] Code formatting: --- src/callers/metadata.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/callers/metadata.rs b/src/callers/metadata.rs index d317bd0..b8c5962 100644 --- a/src/callers/metadata.rs +++ b/src/callers/metadata.rs @@ -95,8 +95,8 @@ pub mod endpoint { } }, Err(err) => { - response.message = err.to_string(); - (StatusCode::BAD_REQUEST, Json(response)) + response.message = err.to_string(); + (StatusCode::BAD_REQUEST, Json(response)) } } } -- 2.47.3 From 61b006bbcff61984b319413b7fb3522cfc3c5ad9 Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:27:03 -0400 Subject: [PATCH 6/9] Added test code --- src/callers/mod.rs | 1 + src/main.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/src/callers/mod.rs b/src/callers/mod.rs index edccd1c..5abbb9f 100644 --- a/src/callers/mod.rs +++ b/src/callers/mod.rs @@ -3,4 +3,5 @@ pub mod song; pub mod endpoints { pub const QUEUESONG: &str = "/api/v2/song/queue"; + pub const QUEUEMETADATA: &str = "/api/v2/song/metadata/queue"; } diff --git a/src/main.rs b/src/main.rs index 27dd3a4..aafcc52 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,6 +69,10 @@ pub mod init { crate::callers::endpoints::QUEUESONG, post(crate::callers::song::endpoint::queue_song), ) + .route( + crate::callers::endpoints::QUEUEMETADATA, + post(crate::callers::metadata::endpoint::queue_metadata), + ) } pub async fn app() -> axum::Router { @@ -245,4 +249,101 @@ mod tests { let _ = db_mgr::drop_database(&tm_pool, &db_name).await; } + + #[tokio::test] + async fn test_song_metadata_queue() { + let tm_pool = db_mgr::get_pool().await.unwrap(); + let db_name = db_mgr::generate_db_name().await; + + match db_mgr::create_database(&tm_pool, &db_name).await { + Ok(_) => { + println!("Success"); + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + } + + let pool = db_mgr::connect_to_db(&db_name).await.unwrap(); + db::migrations(&pool).await; + + let app = crate::init::routes() + .await + .layer(axum::Extension(pool)) + .layer(axum::extract::DefaultBodyLimit::max(1024 * 1024 * 1024)) + .layer(TimeoutLayer::new(Duration::from_secs(300))); + + // Create multipart form + let mut form = MultipartForm::default(); + let _ = form.add_file("flac", "tests/Machine_gun/track01.flac"); + + // Create request + let content_type = form.content_type(); + let body = MultipartBody::from(form); + let req = axum::http::Request::builder() + .method(axum::http::Method::POST) + .uri(crate::callers::endpoints::QUEUESONG) + .header(axum::http::header::CONTENT_TYPE, content_type) + .body(axum::body::Body::from_stream(body)) + .unwrap(); + + // Send request + match app.clone().oneshot(req).await { + Ok(response) => { + let body = axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap(); + println!("Body: {:?}", body); + let resp: crate::callers::song::response::Response = + serde_json::from_slice(&body).unwrap(); + assert_eq!(false, resp.data.is_empty(), "Should not be empty"); + assert_eq!(false, resp.data[0].is_nil(), "Should not be empty"); + let new_payload: serde_json::Value = serde_json::json!( + { + "id": resp.data[0], + "album" : "Machine Gun: The FillMore East First Show", + "album_artist" : "Jimi Hendrix", + "artist" : "Jimi Hendrix", + "disc" : 1, + "disc_count" : 1, + "duration" : 330, + "genre" : "Psychadelic Rock", + "title" : "Power of Soul", + "track" : 1, + "track_count" : 11, + "year" : 2016 + }); + + match app + .clone() + .oneshot( + axum::http::Request::builder() + .method(axum::http::Method::POST) + .uri(crate::callers::endpoints::QUEUEMETADATA) + .header(axum::http::header::CONTENT_TYPE, "application/json") + .body(axum::body::Body::from(new_payload.to_string())) + .unwrap(), + ) + .await + { + Ok(response) => { + let body = axum::body::to_bytes(response.into_body(), usize::MAX) + .await + .unwrap(); + let resp: crate::callers::song::response::Response = + serde_json::from_slice(&body).unwrap(); + assert_eq!(false, resp.data.is_empty(), "Should not be empty"); + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + } + } + Err(err) => { + assert!(false, "Error: {:?}", err); + } + }; + + let _ = db_mgr::drop_database(&tm_pool, &db_name).await; + } } -- 2.47.3 From cf62edd37b7562512bfa53ae189e5e46480e701a Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:35:36 -0400 Subject: [PATCH 7/9] Fixed test --- src/callers/metadata.rs | 45 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/callers/metadata.rs b/src/callers/metadata.rs index b8c5962..088ebd3 100644 --- a/src/callers/metadata.rs +++ b/src/callers/metadata.rs @@ -38,7 +38,7 @@ mod metadata_queue { pub async fn insert( pool: &sqlx::PgPool, - metadata: &String, + metadata: &serde_json::Value, song_queue_id: &uuid::Uuid, ) -> Result { let result = sqlx::query( @@ -76,24 +76,33 @@ pub mod endpoint { ) -> (StatusCode, Json) { let mut results: Vec = Vec::new(); let mut response = super::response::Response::default(); - match serde_json::to_string_pretty(&payload) { - Ok(meta) => match super::metadata_queue::insert(&pool, &meta, &payload.id).await { - Ok(id) => { - results.push(id); - response.data = results; - response.message = if response.data.is_empty() { - String::from("Error") - } else { - String::from("Success") - }; + let meta = serde_json::json!( + { + "id": &payload.id, + "album": &payload.album, + "album_artist": &payload.album_artist, + "genre": &payload.genre, + "year": &payload.year, + "track_count": &payload.track_count, + "disc_count": &payload.disc_count, + "title": &payload.title, + "artist": &payload.artist, + "disc": &payload.disc, + "track": &payload.track, + "duration": &payload.duration, + }); + match super::metadata_queue::insert(&pool, &meta, &payload.id).await { + Ok(id) => { + results.push(id); + response.data = results; + response.message = if response.data.is_empty() { + String::from("Error") + } else { + String::from("Success") + }; - (StatusCode::OK, Json(response)) - } - Err(err) => { - response.message = err.to_string(); - (StatusCode::BAD_REQUEST, Json(response)) - } - }, + (StatusCode::OK, Json(response)) + } Err(err) => { response.message = err.to_string(); (StatusCode::BAD_REQUEST, Json(response)) -- 2.47.3 From daf57d0f3cdc87a4e4fac54fe37808118378b5fd Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:42:14 -0400 Subject: [PATCH 8/9] Cleanup --- src/callers/metadata.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/callers/metadata.rs b/src/callers/metadata.rs index 088ebd3..8a9883b 100644 --- a/src/callers/metadata.rs +++ b/src/callers/metadata.rs @@ -16,6 +16,26 @@ pub mod request { pub track_count: i32, pub year: i32, } + + impl Request { + pub async fn to_json_value(&self) -> serde_json::Value { + serde_json::json!( + { + "id": &self.id, + "album": &self.album, + "album_artist": &self.album_artist, + "genre": &self.genre, + "year": &self.year, + "track_count": &self.track_count, + "disc_count": &self.disc_count, + "title": &self.title, + "artist": &self.artist, + "disc": &self.disc, + "track": &self.track, + "duration": &self.duration, + }) + } + } } pub mod response { @@ -76,21 +96,7 @@ pub mod endpoint { ) -> (StatusCode, Json) { let mut results: Vec = Vec::new(); let mut response = super::response::Response::default(); - let meta = serde_json::json!( - { - "id": &payload.id, - "album": &payload.album, - "album_artist": &payload.album_artist, - "genre": &payload.genre, - "year": &payload.year, - "track_count": &payload.track_count, - "disc_count": &payload.disc_count, - "title": &payload.title, - "artist": &payload.artist, - "disc": &payload.disc, - "track": &payload.track, - "duration": &payload.duration, - }); + let meta = payload.to_json_value().await; match super::metadata_queue::insert(&pool, &meta, &payload.id).await { Ok(id) => { results.push(id); -- 2.47.3 From b42c629ea2833586a87e72c40724e5d49eaca5ee Mon Sep 17 00:00:00 2001 From: phoenix Date: Wed, 23 Apr 2025 20:44:37 -0400 Subject: [PATCH 9/9] Code refactor --- src/callers/metadata.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/callers/metadata.rs b/src/callers/metadata.rs index 8a9883b..c16546d 100644 --- a/src/callers/metadata.rs +++ b/src/callers/metadata.rs @@ -21,7 +21,7 @@ pub mod request { pub async fn to_json_value(&self) -> serde_json::Value { serde_json::json!( { - "id": &self.id, + "id": &self.id, "album": &self.album, "album_artist": &self.album_artist, "genre": &self.genre, -- 2.47.3