From fc103599974240cbd5abcfbf2a6f93678e57c2ee Mon Sep 17 00:00:00 2001 From: Ilion Beyst Date: Tue, 8 Feb 2022 20:13:24 +0100 Subject: store demo matches in database --- .../migrations/2021-12-13-145111_users/down.sql | 2 +- .../migrations/2022-01-02-105610_matches/up.sql | 2 +- planetwars-server/src/db/matches.rs | 21 ++++---- planetwars-server/src/db/users.rs | 2 +- planetwars-server/src/lib.rs | 4 -- planetwars-server/src/routes/demo.rs | 63 +++++++++++++--------- planetwars-server/src/routes/matches.rs | 2 +- 7 files changed, 54 insertions(+), 42 deletions(-) (limited to 'planetwars-server') diff --git a/planetwars-server/migrations/2021-12-13-145111_users/down.sql b/planetwars-server/migrations/2021-12-13-145111_users/down.sql index 49285a1..b08a12c 100644 --- a/planetwars-server/migrations/2021-12-13-145111_users/down.sql +++ b/planetwars-server/migrations/2021-12-13-145111_users/down.sql @@ -1,2 +1,2 @@ -DROP INDEX users_username_index +DROP INDEX users_username_index; DROP TABLE users; \ No newline at end of file diff --git a/planetwars-server/migrations/2022-01-02-105610_matches/up.sql b/planetwars-server/migrations/2022-01-02-105610_matches/up.sql index ace13fd..28db0df 100644 --- a/planetwars-server/migrations/2022-01-02-105610_matches/up.sql +++ b/planetwars-server/migrations/2022-01-02-105610_matches/up.sql @@ -1,4 +1,4 @@ -CREATE TYPE match_state AS ENUM ('playing', 'ended'); +CREATE TYPE match_state AS ENUM ('playing', 'finished'); CREATE TABLE matches ( id SERIAL PRIMARY KEY NOT NULL, diff --git a/planetwars-server/src/db/matches.rs b/planetwars-server/src/db/matches.rs index 36c2200..efaa1eb 100644 --- a/planetwars-server/src/db/matches.rs +++ b/planetwars-server/src/db/matches.rs @@ -46,16 +46,16 @@ pub struct MatchPlayerData { } pub fn create_match( - match_data: &NewMatch, - match_players: &[MatchPlayerData], + new_match_base: &NewMatch, + new_match_players: &[MatchPlayerData], conn: &PgConnection, -) -> QueryResult { +) -> QueryResult { conn.transaction(|| { let match_base = diesel::insert_into(matches::table) - .values(match_data) + .values(new_match_base) .get_result::(conn)?; - let match_players = match_players + let new_match_players = new_match_players .iter() .enumerate() .map(|(num, player_data)| NewMatchPlayer { @@ -65,11 +65,14 @@ pub fn create_match( }) .collect::>(); - diesel::insert_into(match_players::table) - .values(&match_players) - .execute(conn)?; + let match_players = diesel::insert_into(match_players::table) + .values(&new_match_players) + .get_results::(conn)?; - Ok(match_base.id) + Ok(MatchData { + base: match_base, + match_players, + }) }) } diff --git a/planetwars-server/src/db/users.rs b/planetwars-server/src/db/users.rs index 663f173..a97ade5 100644 --- a/planetwars-server/src/db/users.rs +++ b/planetwars-server/src/db/users.rs @@ -2,7 +2,7 @@ use crate::schema::users; use argon2; use diesel::{prelude::*, PgConnection}; use rand::Rng; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; #[derive(Debug, Deserialize)] pub struct Credentials<'a> { diff --git a/planetwars-server/src/lib.rs b/planetwars-server/src/lib.rs index 90e0b44..ccd5a02 100644 --- a/planetwars-server/src/lib.rs +++ b/planetwars-server/src/lib.rs @@ -55,10 +55,6 @@ pub async fn api() -> Router { ) .route("/matches/:match_id", get(routes::matches::get_match_log)) .route("/submit_bot", post(routes::demo::submit_bot)) - .route( - "/submission_match_log/:match_id", - get(routes::demo::get_submission_match_log), - ) .layer(AddExtensionLayer::new(pool)); api } diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs index ea57079..11d8d72 100644 --- a/planetwars-server/src/routes/demo.rs +++ b/planetwars-server/src/routes/demo.rs @@ -1,12 +1,14 @@ -use std::path::PathBuf; - -use axum::{extract::Path, Json}; +use crate::db::matches::{self, MatchState}; +use crate::{ConnectionPool, BOTS_DIR, MAPS_DIR, MATCHES_DIR}; +use axum::extract::Extension; +use axum::Json; use hyper::StatusCode; use planetwars_matchrunner::{docker_runner::DockerBotSpec, run_match, MatchConfig, MatchPlayer}; use rand::{distributions::Alphanumeric, Rng}; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; -use crate::{DatabaseConnection, BOTS_DIR, MAPS_DIR, MATCHES_DIR}; +use super::matches::ApiMatch; const PYTHON_IMAGE: &'static str = "python:3.10-slim-buster"; const SIMPLEBOT_PATH: &'static str = "../simplebot"; @@ -16,38 +18,36 @@ pub struct SubmitBotParams { pub code: String, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize)] pub struct SubmitBotResponse { - pub match_id: String, -} - -pub fn gen_alphanumeric(length: usize) -> String { - rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(length) - .map(char::from) - .collect() + #[serde(rename = "match")] + pub match_data: ApiMatch, } /// submit python code for a bot, which will face off /// with a demo bot. Return a played match. pub async fn submit_bot( Json(params): Json, + Extension(pool): Extension, ) -> Result, StatusCode> { - let uploaded_bot_id: String = gen_alphanumeric(16); - let match_id = gen_alphanumeric(16); + let conn = pool.get().await.expect("could not get database connection"); + + let uploaded_bot_uuid: String = gen_alphanumeric(16); + let log_file_name = format!("{}.log", gen_alphanumeric(16)); - let uploaded_bot_dir = PathBuf::from(BOTS_DIR).join(&uploaded_bot_id); + // store uploaded bot + let uploaded_bot_dir = PathBuf::from(BOTS_DIR).join(&uploaded_bot_uuid); std::fs::create_dir(&uploaded_bot_dir).unwrap(); std::fs::write(uploaded_bot_dir.join("bot.py"), params.code.as_bytes()).unwrap(); + // play the match run_match(MatchConfig { map_path: PathBuf::from(MAPS_DIR).join("hex.json"), map_name: "hex".to_string(), - log_path: PathBuf::from(MATCHES_DIR).join(format!("{}.log", match_id)), + log_path: PathBuf::from(MATCHES_DIR).join(&log_file_name), players: vec![ MatchPlayer { - name: "bot".to_string(), + name: "player".to_string(), bot_spec: Box::new(DockerBotSpec { code_path: uploaded_bot_dir, image: PYTHON_IMAGE.to_string(), @@ -66,12 +66,25 @@ pub async fn submit_bot( }) .await; - Ok(Json(SubmitBotResponse { match_id })) -} + // store match in database + let new_match_data = matches::NewMatch { + state: MatchState::Finished, + log_path: &log_file_name, + }; + // TODO: set match players + let match_data = + matches::create_match(&new_match_data, &[], &conn).expect("failed to create match"); -// TODO: unify this with existing match API -pub async fn get_submission_match_log(Path(match_id): Path) -> Result { - let log_path = PathBuf::from(MATCHES_DIR).join(format!("{}.log", match_id)); + let api_match = super::matches::match_data_to_api(match_data); + Ok(Json(SubmitBotResponse { + match_data: api_match, + })) +} - std::fs::read_to_string(&log_path).map_err(|_| StatusCode::NOT_FOUND) +pub fn gen_alphanumeric(length: usize) -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(length) + .map(char::from) + .collect() } diff --git a/planetwars-server/src/routes/matches.rs b/planetwars-server/src/routes/matches.rs index 94a5f45..089bd71 100644 --- a/planetwars-server/src/routes/matches.rs +++ b/planetwars-server/src/routes/matches.rs @@ -115,7 +115,7 @@ pub async fn list_matches(conn: DatabaseConnection) -> Result .map(|matches| Json(matches.into_iter().map(match_data_to_api).collect())) } -fn match_data_to_api(data: matches::MatchData) -> ApiMatch { +pub fn match_data_to_api(data: matches::MatchData) -> ApiMatch { ApiMatch { id: data.base.id, timestamp: data.base.created_at, -- cgit v1.2.3