diff --git a/planetwars-server/src/db/bots.rs b/planetwars-server/src/db/bots.rs index baabd5a..d99a459 100644 --- a/planetwars-server/src/db/bots.rs +++ b/planetwars-server/src/db/bots.rs @@ -34,6 +34,10 @@ pub fn find_bots_by_owner(owner_id: i32, conn: &PgConnection) -> QueryResult QueryResult { + bots::table.filter(bots::name.eq(name)).first(conn) +} + pub fn find_all_bots(conn: &PgConnection) -> QueryResult> { // TODO: filter out bots that cannot be run (have no valid code bundle associated with them) bots::table.get_results(conn) diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs index 28eab97..8642577 100644 --- a/planetwars-server/src/routes/demo.rs +++ b/planetwars-server/src/routes/demo.rs @@ -1,10 +1,12 @@ -use crate::db::matches::{self, MatchState}; +use crate::db; +use crate::db::matches::MatchState; use crate::modules::bots::save_code_bundle; use crate::util::gen_alphanumeric; use crate::{ConnectionPool, BOTS_DIR, MAPS_DIR, MATCHES_DIR}; use axum::extract::Extension; use axum::Json; use hyper::StatusCode; +use planetwars_matchrunner::BotSpec; use planetwars_matchrunner::{docker_runner::DockerBotSpec, run_match, MatchConfig, MatchPlayer}; use serde::{Deserialize, Serialize}; use std::path::PathBuf; @@ -12,7 +14,7 @@ use std::path::PathBuf; use super::matches::ApiMatch; const PYTHON_IMAGE: &'static str = "python:3.10-slim-buster"; -const SIMPLEBOT_PATH: &'static str = "../simplebot"; +const OPPONENT_NAME: &'static str = "simplebot"; #[derive(Serialize, Deserialize, Debug)] pub struct SubmitBotParams { @@ -26,6 +28,16 @@ pub struct SubmitBotResponse { pub match_data: ApiMatch, } +fn code_bundle_to_botspec(code_bundle: &db::bots::CodeBundle) -> Box { + let bundle_path = PathBuf::from(BOTS_DIR).join(&code_bundle.path); + + Box::new(DockerBotSpec { + code_path: bundle_path, + image: PYTHON_IMAGE.to_string(), + argv: vec!["python".to_string(), "bot.py".to_string()], + }) +} + /// submit python code for a bot, which will face off /// with a demo bot. Return a played match. pub async fn submit_bot( @@ -34,12 +46,16 @@ pub async fn submit_bot( ) -> Result, StatusCode> { let conn = pool.get().await.expect("could not get database connection"); - let code_bundle = save_code_bundle(¶ms.code, None, &conn) + let opponent = + db::bots::find_bot_by_name(OPPONENT_NAME, &conn).expect("could not find opponent bot"); + let opponent_code_bundle = + db::bots::active_code_bundle(opponent.id, &conn).expect("opponent bot has no code bundles"); + + let player_code_bundle = save_code_bundle(¶ms.code, None, &conn) // TODO: can we recover from this? .expect("could not save bot code"); let log_file_name = format!("{}.log", gen_alphanumeric(16)); - let uploaded_bot_dir = PathBuf::from(BOTS_DIR).join(&code_bundle.path); // play the match let match_config = MatchConfig { map_path: PathBuf::from(MAPS_DIR).join("hex.json"), @@ -48,31 +64,23 @@ pub async fn submit_bot( players: vec![ MatchPlayer { name: "player".to_string(), - bot_spec: Box::new(DockerBotSpec { - code_path: uploaded_bot_dir, - image: PYTHON_IMAGE.to_string(), - argv: vec!["python".to_string(), "bot.py".to_string()], - }), + bot_spec: code_bundle_to_botspec(&player_code_bundle), }, MatchPlayer { - name: "simplebot".to_string(), - bot_spec: Box::new(DockerBotSpec { - code_path: PathBuf::from(SIMPLEBOT_PATH), - image: PYTHON_IMAGE.to_string(), - argv: vec!["python".to_string(), "simplebot.py".to_string()], - }), + name: OPPONENT_NAME.to_string(), + bot_spec: code_bundle_to_botspec(&opponent_code_bundle), }, ], }; // store match in database - let new_match_data = matches::NewMatch { + let new_match_data = db::matches::NewMatch { state: MatchState::Playing, log_path: &log_file_name, }; // TODO: set match players let match_data = - matches::create_match(&new_match_data, &[], &conn).expect("failed to create match"); + db::matches::create_match(&new_match_data, &[], &conn).expect("failed to create match"); tokio::spawn(run_match_task( match_data.base.id, @@ -92,6 +100,6 @@ async fn run_match_task(match_id: i32, match_config: MatchConfig, connection_poo .get() .await .expect("could not get database connection"); - matches::set_match_state(match_id, MatchState::Finished, &conn) + db::matches::set_match_state(match_id, MatchState::Finished, &conn) .expect("failed to update match state"); }