diff options
Diffstat (limited to 'planetwars-server/src/routes')
-rw-r--r-- | planetwars-server/src/routes/demo.rs | 14 | ||||
-rw-r--r-- | planetwars-server/src/routes/maps.rs | 19 | ||||
-rw-r--r-- | planetwars-server/src/routes/matches.rs | 75 | ||||
-rw-r--r-- | planetwars-server/src/routes/mod.rs | 1 |
4 files changed, 101 insertions, 8 deletions
diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs index dad9453..1ec8825 100644 --- a/planetwars-server/src/routes/demo.rs +++ b/planetwars-server/src/routes/demo.rs @@ -14,12 +14,13 @@ use serde::{Deserialize, Serialize}; use super::matches::ApiMatch; const DEFAULT_OPPONENT_NAME: &str = "simplebot"; +const DEFAULT_MAP_NAME: &str = "hex"; #[derive(Serialize, Deserialize, Debug)] pub struct SubmitBotParams { pub code: String, - // TODO: would it be better to pass an ID here? pub opponent_name: Option<String>, + pub map_name: Option<String>, } #[derive(Serialize, Deserialize)] @@ -40,16 +41,24 @@ pub async fn submit_bot( .opponent_name .unwrap_or_else(|| DEFAULT_OPPONENT_NAME.to_string()); + let map_name = params + .map_name + .unwrap_or_else(|| DEFAULT_MAP_NAME.to_string()); + let (opponent_bot, opponent_bot_version) = db::bots::find_bot_with_version_by_name(&opponent_name, &conn) .map_err(|_| StatusCode::BAD_REQUEST)?; + let map = db::maps::find_map_by_name(&map_name, &conn).map_err(|_| StatusCode::BAD_REQUEST)?; + let player_bot_version = save_code_string(¶ms.code, None, &conn, &config) // TODO: can we recover from this? .expect("could not save bot code"); - let run_match = RunMatch::from_players( + let run_match = RunMatch::new( config, + false, + map.clone(), vec![ MatchPlayer::BotVersion { bot: None, @@ -81,6 +90,7 @@ pub async fn submit_bot( bot: Some(opponent_bot), }, ], + map: Some(map), }; let api_match = super::matches::match_data_to_api(full_match_data); diff --git a/planetwars-server/src/routes/maps.rs b/planetwars-server/src/routes/maps.rs new file mode 100644 index 0000000..689b11e --- /dev/null +++ b/planetwars-server/src/routes/maps.rs @@ -0,0 +1,19 @@ +use crate::{db, DatabaseConnection}; +use axum::Json; +use hyper::StatusCode; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +pub struct ApiMap { + pub name: String, +} + +pub async fn list_maps(conn: DatabaseConnection) -> Result<Json<Vec<ApiMap>>, StatusCode> { + let maps = db::maps::list_maps(&conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + let api_maps = maps + .into_iter() + .map(|map| ApiMap { name: map.name }) + .collect(); + Ok(Json(api_maps)) +} 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 }), } } diff --git a/planetwars-server/src/routes/mod.rs b/planetwars-server/src/routes/mod.rs index b3decb8..9510fd4 100644 --- a/planetwars-server/src/routes/mod.rs +++ b/planetwars-server/src/routes/mod.rs @@ -1,4 +1,5 @@ pub mod bots; pub mod demo; +pub mod maps; pub mod matches; pub mod users; |