added report id in returned reports, and added a get-per-id route

This commit is contained in:
2026-03-26 21:18:30 +01:00
parent 9e6eab77e2
commit d973d362f8
2 changed files with 40 additions and 9 deletions

View File

@@ -2,9 +2,9 @@ use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration};
use axum::{ use axum::{
Json, Router, Json, Router,
extract::{Query, State}, extract::{Path, Query, State},
http::{Method, StatusCode, header}, http::{Method, StatusCode, header},
routing::post, routing::{get, post},
}; };
use clap::Parser; use clap::Parser;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@@ -42,6 +42,8 @@ pub struct BenchmarkReport {
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct FullReport { pub struct FullReport {
#[serde(skip_deserializing)]
pub id: Option<i64>,
pub mac_address: String, pub mac_address: String,
pub timestamp: String, pub timestamp: String,
pub slimes: Option<HashMap<String, Vec<String>>>, pub slimes: Option<HashMap<String, Vec<String>>>,
@@ -63,16 +65,17 @@ pub struct AppState {
async fn submit( async fn submit(
State(state): State<Arc<AppState>>, State(state): State<Arc<AppState>>,
Json(payload): Json<FullReport>, Json(payload): Json<FullReport>,
) -> Result<StatusCode, (StatusCode, String)> { ) -> Result<(StatusCode, Json<i64>), (StatusCode, String)> {
let score = payload let score = payload
.benchmark .benchmark
.as_ref() .as_ref()
.map(|b| b.multi_thread.score) .map(|b| b.multi_thread.score)
.unwrap_or(0); .unwrap_or(0);
let raw_json = serde_json::to_string(&payload) let raw_json = serde_json::to_string(&payload)
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
sqlx::query( let result = sqlx::query(
"INSERT INTO reports (mac_address, score, timestamp, client_version, signature, data) "INSERT INTO reports (mac_address, score, timestamp, client_version, signature, data)
VALUES (?, ?, ?, ?, ?, ?)", VALUES (?, ?, ?, ?, ?, ?)",
) )
@@ -86,7 +89,14 @@ async fn submit(
.await .await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?; .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
Ok(StatusCode::CREATED) let id = result.last_insert_rowid();
Ok((StatusCode::CREATED, Json(id)))
}
fn parse_report_row(id: i64, data: String) -> Option<FullReport> {
let mut report: FullReport = serde_json::from_str(&data).ok()?;
report.id = Some(id);
Some(report)
} }
async fn get_leaderboard( async fn get_leaderboard(
@@ -96,9 +106,9 @@ async fn get_leaderboard(
let limit = pagination.limit.unwrap_or(10); let limit = pagination.limit.unwrap_or(10);
let offset = pagination.offset.unwrap_or(0); let offset = pagination.offset.unwrap_or(0);
let rows: Vec<String> = sqlx::query_scalar( let rows: Vec<(i64, String)> = sqlx::query_as(
r#" r#"
SELECT data FROM reports r SELECT id, data FROM reports r
WHERE score = (SELECT MAX(score) FROM reports WHERE mac_address = r.mac_address) WHERE score = (SELECT MAX(score) FROM reports WHERE mac_address = r.mac_address)
GROUP BY mac_address GROUP BY mac_address
ORDER BY score DESC ORDER BY score DESC
@@ -113,15 +123,35 @@ async fn get_leaderboard(
let results = rows let results = rows
.into_iter() .into_iter()
.filter_map(|row| serde_json::from_str(&row).ok()) .filter_map(|(id, data)| parse_report_row(id, data))
.collect(); .collect();
Ok(Json(results)) Ok(Json(results))
} }
async fn get_report_by_id(
State(state): State<Arc<AppState>>,
Path(id): Path<i64>,
) -> Result<Json<FullReport>, (StatusCode, String)> {
let row: (i64, String) = sqlx::query_as("SELECT id, data FROM reports WHERE id = ?")
.bind(id)
.fetch_optional(&state.db)
.await
.map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?
.ok_or((StatusCode::NOT_FOUND, "Report not found".to_string()))?;
let report = parse_report_row(row.0, row.1).ok_or((
StatusCode::INTERNAL_SERVER_ERROR,
"Failed to parse stored data".to_string(),
))?;
Ok(Json(report))
}
pub fn routes(state: Arc<AppState>) -> Router { pub fn routes(state: Arc<AppState>) -> Router {
Router::new() Router::new()
.route("/", post(submit).get(get_leaderboard)) .route("/", post(submit).get(get_leaderboard))
.route("/{id}", get(get_report_by_id))
.with_state(state) .with_state(state)
} }

View File

@@ -207,7 +207,8 @@ fn send_to_server(url: &str, report: &FullReport) {
eprintln!( eprintln!(
"{} Error sending to server: {}", "{} Error sending to server: {}",
"Error:".red(), "Error:".red(),
resp.status() resp.status(),
// resp.text().unwrap_or_default()
); );
} }
} }