diff options
Diffstat (limited to 'planetwars-server/src/routes/matches.rs')
-rw-r--r-- | planetwars-server/src/routes/matches.rs | 75 |
1 files changed, 69 insertions, 6 deletions
diff --git a/planetwars-server/src/routes/matches.rs b/planetwars-server/src/routes/matches.rs index 58ca478..10b4507 100644 --- a/planetwars-server/src/routes/matches.rs +++ b/planetwars-server/src/routes/matches.rs @@ -1,19 +1,30 @@ -use axum::{extract::Path, Extension, Json}; +use axum::{ + extract::{Path, Query}, + Extension, Json, +}; +use chrono::NaiveDateTime; use hyper::StatusCode; use serde::{Deserialize, Serialize}; use std::{path::PathBuf, sync::Arc}; use crate::{ - db::matches::{self, MatchState}, + db::{ + self, + matches::{self, MatchState}, + }, DatabaseConnection, GlobalConfig, }; +use super::maps::ApiMap; + #[derive(Serialize, Deserialize)] pub struct ApiMatch { id: i32, timestamp: chrono::NaiveDateTime, state: MatchState, players: Vec<ApiMatchPlayer>, + winner: Option<i32>, + map: Option<ApiMap>, } #[derive(Serialize, Deserialize)] @@ -23,10 +34,60 @@ pub struct ApiMatchPlayer { bot_name: Option<String>, } -pub async fn list_matches(conn: DatabaseConnection) -> Result<Json<Vec<ApiMatch>>, StatusCode> { - matches::list_matches(100, &conn) - .map_err(|_| StatusCode::BAD_REQUEST) - .map(|matches| Json(matches.into_iter().map(match_data_to_api).collect())) +#[derive(Serialize, Deserialize)] +pub struct ListRecentMatchesParams { + count: Option<usize>, + // TODO: should timezone be specified here? + before: Option<NaiveDateTime>, + after: Option<NaiveDateTime>, + + bot: Option<String>, +} + +const MAX_NUM_RETURNED_MATCHES: usize = 100; +const DEFAULT_NUM_RETURNED_MATCHES: usize = 50; + +#[derive(Serialize, Deserialize)] +pub struct ListMatchesResponse { + matches: Vec<ApiMatch>, + has_next: bool, +} + +pub async fn list_recent_matches( + Query(params): Query<ListRecentMatchesParams>, + conn: DatabaseConnection, +) -> Result<Json<ListMatchesResponse>, StatusCode> { + let requested_count = std::cmp::min( + params.count.unwrap_or(DEFAULT_NUM_RETURNED_MATCHES), + MAX_NUM_RETURNED_MATCHES, + ); + + // fetch one additional record to check whether a next page exists + let count = (requested_count + 1) as i64; + + let matches_result = match params.bot { + Some(bot_name) => { + let bot = db::bots::find_bot_by_name(&bot_name, &conn) + .map_err(|_| StatusCode::BAD_REQUEST)?; + matches::list_bot_matches(bot.id, count, params.before, params.after, &conn) + } + None => matches::list_public_matches(count, params.before, params.after, &conn), + }; + + let mut matches = matches_result.map_err(|_| StatusCode::BAD_REQUEST)?; + + let mut has_next = false; + if matches.len() > requested_count { + has_next = true; + matches.truncate(requested_count); + } + + let api_matches = matches.into_iter().map(match_data_to_api).collect(); + + Ok(Json(ListMatchesResponse { + matches: api_matches, + has_next, + })) } pub fn match_data_to_api(data: matches::FullMatchData) -> ApiMatch { @@ -43,6 +104,8 @@ pub fn match_data_to_api(data: matches::FullMatchData) -> ApiMatch { bot_name: _p.bot.as_ref().map(|b| b.name.clone()), }) .collect(), + winner: data.base.winner, + map: data.map.map(|m| ApiMap { name: m.name }), } } |