Add user stats route
This commit is contained in:
63
Cargo.lock
generated
63
Cargo.lock
generated
@@ -963,6 +963,12 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "http-range-header"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httparse"
|
name = "httparse"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@@ -1396,6 +1402,16 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mime_guess"
|
||||||
|
version = "2.0.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||||
|
dependencies = [
|
||||||
|
"mime",
|
||||||
|
"unicase",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minimal-lexical"
|
name = "minimal-lexical"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -1936,8 +1952,10 @@ dependencies = [
|
|||||||
"crossterm 0.29.0",
|
"crossterm 0.29.0",
|
||||||
"mpris",
|
"mpris",
|
||||||
"ratatui 0.30.0",
|
"ratatui 0.30.0",
|
||||||
|
"serde",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
"tui-textarea",
|
"tui-textarea",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2779,6 +2797,19 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-util"
|
||||||
|
version = "0.7.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-sink",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower"
|
name = "tower"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
@@ -2795,6 +2826,32 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tower-http"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.10.0",
|
||||||
|
"bytes",
|
||||||
|
"futures-core",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"http-body",
|
||||||
|
"http-body-util",
|
||||||
|
"http-range-header",
|
||||||
|
"httpdate",
|
||||||
|
"mime",
|
||||||
|
"mime_guess",
|
||||||
|
"percent-encoding",
|
||||||
|
"pin-project-lite",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util",
|
||||||
|
"tower-layer",
|
||||||
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-layer"
|
name = "tower-layer"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@@ -2862,6 +2919,12 @@ version = "0.1.7"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicase"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.18"
|
version = "0.3.18"
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ sqlx = { version = "0.8.3", features = ["sqlite", "runtime-tokio"] }
|
|||||||
tokio = { version = "1.36.0", features = ["rt", "macros", "rt-multi-thread"] }
|
tokio = { version = "1.36.0", features = ["rt", "macros", "rt-multi-thread"] }
|
||||||
tui-textarea = "0.7.0"
|
tui-textarea = "0.7.0"
|
||||||
axum = "0.8.3"
|
axum = "0.8.3"
|
||||||
|
tower-http = { version = "0.6.8", features = ["fs"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
[profile.optimize]
|
[profile.optimize]
|
||||||
inherits = "release"
|
inherits = "release"
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
use std::i64;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use serde::Serialize;
|
||||||
use sqlx::{Row, SqlitePool};
|
use sqlx::{Row, SqlitePool};
|
||||||
|
use std::i64;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Database {
|
pub struct Database {
|
||||||
pool: SqlitePool,
|
pool: SqlitePool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
pub struct UserStats {
|
||||||
|
pub name: String,
|
||||||
|
pub rating_count: i64,
|
||||||
|
pub average_rating: f64,
|
||||||
|
}
|
||||||
|
|
||||||
impl Database {
|
impl Database {
|
||||||
pub async fn new() -> Result<Self> {
|
pub async fn new() -> Result<Self> {
|
||||||
let pool = SqlitePool::connect("sqlite://ratings.db?mode=rwc").await?;
|
let pool = SqlitePool::connect("sqlite://ratings.db?mode=rwc").await?;
|
||||||
@@ -218,7 +225,7 @@ impl Database {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_user_most_ratings(&self) -> Result<()> {
|
pub async fn get_user_most_ratings(&self) -> Result<Vec<UserStats>> {
|
||||||
let mut conn = self.pool.acquire().await?;
|
let mut conn = self.pool.acquire().await?;
|
||||||
|
|
||||||
let records = sqlx::query(
|
let records = sqlx::query(
|
||||||
@@ -233,16 +240,16 @@ impl Database {
|
|||||||
.fetch_all(&mut *conn)
|
.fetch_all(&mut *conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
//let id = record.try_get("id")?;
|
// Map the database records into our new struct
|
||||||
|
let mut stats = Vec::new();
|
||||||
for r in records {
|
for r in records {
|
||||||
let name: &str = r.try_get("name")?;
|
stats.push(UserStats {
|
||||||
let count: i64 = r.try_get("c")?;
|
name: r.try_get("name")?,
|
||||||
let avg: f64 = r.try_get("avg(rating)")?;
|
rating_count: r.try_get("c")?,
|
||||||
|
average_rating: r.try_get("avg(rating)")?,
|
||||||
println!("Name: {name}, Ratings: {count}, Average: {avg}");
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(stats)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,10 @@ use axum::{
|
|||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{IntoResponse, Response},
|
response::{IntoResponse, Response},
|
||||||
routing::get,
|
routing::get,
|
||||||
Router,
|
Json, Router,
|
||||||
};
|
};
|
||||||
use tokio::sync::watch::Sender;
|
use tokio::sync::watch::Sender;
|
||||||
|
use tower_http::services::ServeDir;
|
||||||
|
|
||||||
use crate::database::Database;
|
use crate::database::Database;
|
||||||
|
|
||||||
@@ -31,6 +32,8 @@ pub async fn http_serve(database: &Database, mpris_producer: Sender<(String, Str
|
|||||||
};
|
};
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
|
.fallback_service(ServeDir::new("static"))
|
||||||
|
.route("/stats", get(get_stats))
|
||||||
.route("/", get(root))
|
.route("/", get(root))
|
||||||
.route("/rating/:rating", get(cache_rating_only))
|
.route("/rating/:rating", get(cache_rating_only))
|
||||||
.route("/userid/:user_id", get(add_userid))
|
.route("/userid/:user_id", get(add_userid))
|
||||||
@@ -127,3 +130,17 @@ async fn add_userid_by_card(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_stats(State(shared): State<SharedState>) -> Response {
|
||||||
|
match shared.database.get_user_most_ratings().await {
|
||||||
|
Ok(stats) => {
|
||||||
|
// axum::Json automatically serializes the Vec<UserStats> into a JSON array
|
||||||
|
// and sets the correct "Content-Type: application/json" headers.
|
||||||
|
(StatusCode::OK, Json(stats)).into_response()
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Database error: {e}");
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to fetch stats").into_response()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user