aboutsummaryrefslogtreecommitdiff
path: root/planetwars-server/src/routes
diff options
context:
space:
mode:
Diffstat (limited to 'planetwars-server/src/routes')
-rw-r--r--planetwars-server/src/routes/bots.rs32
-rw-r--r--planetwars-server/src/routes/demo.rs44
-rw-r--r--planetwars-server/src/routes/matches.rs113
-rw-r--r--planetwars-server/src/routes/users.rs6
4 files changed, 59 insertions, 136 deletions
diff --git a/planetwars-server/src/routes/bots.rs b/planetwars-server/src/routes/bots.rs
index 3bbaa1a..9ddb109 100644
--- a/planetwars-server/src/routes/bots.rs
+++ b/planetwars-server/src/routes/bots.rs
@@ -1,7 +1,7 @@
use axum::extract::{Multipart, Path};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
-use axum::{body, Json};
+use axum::{body, Extension, Json};
use diesel::OptionalExtension;
use rand::distributions::Alphanumeric;
use rand::Rng;
@@ -9,13 +9,14 @@ use serde::{Deserialize, Serialize};
use serde_json::{self, json, value::Value as JsonValue};
use std::io::Cursor;
use std::path::PathBuf;
+use std::sync::Arc;
use thiserror;
-use crate::db::bots::{self, CodeBundle};
-use crate::db::ratings::{RankedBot, self};
+use crate::db::bots::{self, BotVersion};
+use crate::db::ratings::{self, RankedBot};
use crate::db::users::User;
-use crate::modules::bots::save_code_bundle;
-use crate::{DatabaseConnection, BOTS_DIR};
+use crate::modules::bots::save_code_string;
+use crate::{DatabaseConnection, GlobalConfig};
use bots::Bot;
#[derive(Serialize, Deserialize, Debug)]
@@ -96,6 +97,7 @@ pub async fn save_bot(
Json(params): Json<SaveBotParams>,
user: User,
conn: DatabaseConnection,
+ Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<Json<Bot>, SaveBotError> {
let res = bots::find_bot_by_name(&params.bot_name, &conn)
.optional()
@@ -119,8 +121,8 @@ pub async fn save_bot(
bots::create_bot(&new_bot, &conn).expect("could not create bot")
}
};
- let _code_bundle =
- save_code_bundle(&params.code, Some(bot.id), &conn).expect("failed to save code bundle");
+ let _code_bundle = save_code_string(&params.code, Some(bot.id), &conn, &config)
+ .expect("failed to save code bundle");
Ok(Json(bot))
}
@@ -148,8 +150,8 @@ pub async fn get_bot(
Path(bot_id): Path<i32>,
) -> Result<Json<JsonValue>, StatusCode> {
let bot = bots::find_bot(bot_id, &conn).map_err(|_| StatusCode::NOT_FOUND)?;
- let bundles = bots::find_bot_code_bundles(bot.id, &conn)
- .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
+ let bundles =
+ bots::find_bot_versions(bot.id, &conn).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(Json(json!({
"bot": bot,
"bundles": bundles,
@@ -183,8 +185,9 @@ pub async fn upload_code_multipart(
user: User,
Path(bot_id): Path<i32>,
mut multipart: Multipart,
-) -> Result<Json<CodeBundle>, StatusCode> {
- let bots_dir = PathBuf::from(BOTS_DIR);
+ Extension(config): Extension<Arc<GlobalConfig>>,
+) -> Result<Json<BotVersion>, StatusCode> {
+ let bots_dir = PathBuf::from(&config.bots_directory);
let bot = bots::find_bot(bot_id, &conn).map_err(|_| StatusCode::NOT_FOUND)?;
@@ -213,12 +216,13 @@ pub async fn upload_code_multipart(
.extract(bots_dir.join(&folder_name))
.map_err(|_| StatusCode::BAD_REQUEST)?;
- let bundle = bots::NewCodeBundle {
+ let bot_version = bots::NewBotVersion {
bot_id: Some(bot.id),
- path: &folder_name,
+ code_bundle_path: Some(&folder_name),
+ container_digest: None,
};
let code_bundle =
- bots::create_code_bundle(&bundle, &conn).expect("Failed to create code bundle");
+ bots::create_bot_version(&bot_version, &conn).expect("Failed to create code bundle");
Ok(Json(code_bundle))
}
diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs
index 7f7ba71..69838f3 100644
--- a/planetwars-server/src/routes/demo.rs
+++ b/planetwars-server/src/routes/demo.rs
@@ -1,8 +1,11 @@
+use std::sync::Arc;
+
use crate::db;
use crate::db::matches::{FullMatchData, FullMatchPlayerData};
-use crate::modules::bots::save_code_bundle;
-use crate::modules::matches::RunMatch;
+use crate::modules::bots::save_code_string;
+use crate::modules::matches::{MatchPlayer, RunMatch};
use crate::ConnectionPool;
+use crate::GlobalConfig;
use axum::extract::Extension;
use axum::Json;
use hyper::StatusCode;
@@ -30,6 +33,7 @@ pub struct SubmitBotResponse {
pub async fn submit_bot(
Json(params): Json<SubmitBotParams>,
Extension(pool): Extension<ConnectionPool>,
+ Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<Json<SubmitBotResponse>, StatusCode> {
let conn = pool.get().await.expect("could not get database connection");
@@ -37,20 +41,32 @@ pub async fn submit_bot(
.opponent_name
.unwrap_or_else(|| DEFAULT_OPPONENT_NAME.to_string());
- let opponent =
+ let opponent_bot =
db::bots::find_bot_by_name(&opponent_name, &conn).map_err(|_| StatusCode::BAD_REQUEST)?;
- let opponent_code_bundle =
- db::bots::active_code_bundle(opponent.id, &conn).map_err(|_| StatusCode::BAD_REQUEST)?;
+ let opponent_bot_version = db::bots::active_bot_version(opponent_bot.id, &conn)
+ .map_err(|_| StatusCode::BAD_REQUEST)?;
- let player_code_bundle = save_code_bundle(&params.code, None, &conn)
+ let player_bot_version = save_code_string(&params.code, None, &conn, &config)
// TODO: can we recover from this?
.expect("could not save bot code");
- let mut run_match = RunMatch::from_players(vec![&player_code_bundle, &opponent_code_bundle]);
- let match_data = run_match
- .store_in_database(&conn)
- .expect("failed to save match");
- run_match.spawn(pool.clone());
+ let run_match = RunMatch::from_players(
+ config,
+ vec![
+ MatchPlayer::BotVersion {
+ bot: None,
+ version: player_bot_version.clone(),
+ },
+ MatchPlayer::BotVersion {
+ bot: Some(opponent_bot.clone()),
+ version: opponent_bot_version.clone(),
+ },
+ ],
+ );
+ let (match_data, _) = run_match
+ .run(pool.clone())
+ .await
+ .expect("failed to run match");
// TODO: avoid clones
let full_match_data = FullMatchData {
@@ -58,13 +74,13 @@ pub async fn submit_bot(
match_players: vec![
FullMatchPlayerData {
base: match_data.match_players[0].clone(),
- code_bundle: player_code_bundle,
+ bot_version: Some(player_bot_version),
bot: None,
},
FullMatchPlayerData {
base: match_data.match_players[1].clone(),
- code_bundle: opponent_code_bundle,
- bot: Some(opponent),
+ bot_version: Some(opponent_bot_version),
+ bot: Some(opponent_bot),
},
],
};
diff --git a/planetwars-server/src/routes/matches.rs b/planetwars-server/src/routes/matches.rs
index b61008d..a980daa 100644
--- a/planetwars-server/src/routes/matches.rs
+++ b/planetwars-server/src/routes/matches.rs
@@ -1,102 +1,13 @@
-use std::path::PathBuf;
-
-use axum::{
- extract::{Extension, Path},
- Json,
-};
+use axum::{extract::Path, Extension, 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, sync::Arc};
use crate::{
- db::{
- bots,
- matches::{self, MatchState},
- users::User,
- },
- ConnectionPool, DatabaseConnection, BOTS_DIR, MAPS_DIR, MATCHES_DIR,
+ db::matches::{self, MatchState},
+ DatabaseConnection, GlobalConfig,
};
-#[derive(Serialize, Deserialize, Debug)]
-pub struct MatchParams {
- // Just bot ids for now
- players: Vec<i32>,
-}
-
-pub async fn play_match(
- _user: User,
- Extension(pool): Extension<ConnectionPool>,
- Json(params): Json<MatchParams>,
-) -> Result<(), StatusCode> {
- let conn = pool.get().await.expect("could not get database connection");
- let map_path = PathBuf::from(MAPS_DIR).join("hex.json");
-
- let slug: String = rand::thread_rng()
- .sample_iter(&Alphanumeric)
- .take(16)
- .map(char::from)
- .collect();
- let log_file_name = format!("{}.log", slug);
-
- let mut players = Vec::new();
- let mut bot_ids = Vec::new();
- for bot_name in params.players {
- let bot = bots::find_bot(bot_name, &conn).map_err(|_| StatusCode::BAD_REQUEST)?;
- let code_bundle =
- bots::active_code_bundle(bot.id, &conn).map_err(|_| StatusCode::BAD_REQUEST)?;
-
- let bundle_path = PathBuf::from(BOTS_DIR).join(&code_bundle.path);
- let bot_config: BotConfig = std::fs::read_to_string(bundle_path.join("botconfig.toml"))
- .and_then(|config_str| toml::from_str(&config_str).map_err(|e| e.into()))
- .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
-
- players.push(MatchPlayer {
- bot_spec: Box::new(DockerBotSpec {
- code_path: PathBuf::from(BOTS_DIR).join(code_bundle.path),
- image: "python:3.10-slim-buster".to_string(),
- argv: shlex::split(&bot_config.run_command)
- .ok_or(StatusCode::INTERNAL_SERVER_ERROR)?,
- }),
- });
-
- bot_ids.push(matches::MatchPlayerData {
- code_bundle_id: code_bundle.id,
- });
- }
-
- let match_config = MatchConfig {
- map_name: "hex".to_string(),
- map_path,
- log_path: PathBuf::from(MATCHES_DIR).join(&log_file_name),
- players,
- };
-
- tokio::spawn(run_match_task(
- match_config,
- log_file_name,
- bot_ids,
- pool.clone(),
- ));
- Ok(())
-}
-
-async fn run_match_task(
- config: MatchConfig,
- log_file_name: String,
- match_players: Vec<matches::MatchPlayerData>,
- pool: ConnectionPool,
-) {
- let match_data = matches::NewMatch {
- state: MatchState::Finished,
- log_path: &log_file_name,
- };
-
- run_match(config).await;
- let conn = pool.get().await.expect("could not get database connection");
- matches::create_match(&match_data, &match_players, &conn).expect("could not create match");
-}
-
#[derive(Serialize, Deserialize)]
pub struct ApiMatch {
id: i32,
@@ -107,7 +18,7 @@ pub struct ApiMatch {
#[derive(Serialize, Deserialize)]
pub struct ApiMatchPlayer {
- code_bundle_id: i32,
+ bot_version_id: Option<i32>,
bot_id: Option<i32>,
bot_name: Option<String>,
}
@@ -127,7 +38,7 @@ pub fn match_data_to_api(data: matches::FullMatchData) -> ApiMatch {
.match_players
.iter()
.map(|_p| ApiMatchPlayer {
- code_bundle_id: _p.code_bundle.id,
+ bot_version_id: _p.bot_version.as_ref().map(|cb| cb.id),
bot_id: _p.bot.as_ref().map(|b| b.id),
bot_name: _p.bot.as_ref().map(|b| b.name.clone()),
})
@@ -135,15 +46,6 @@ pub fn match_data_to_api(data: matches::FullMatchData) -> ApiMatch {
}
}
-// TODO: this is duplicated from planetwars-cli
-// clean this up and move to matchrunner crate
-#[derive(Serialize, Deserialize)]
-pub struct BotConfig {
- pub name: String,
- pub run_command: String,
- pub build_command: Option<String>,
-}
-
pub async fn get_match_data(
Path(match_id): Path<i32>,
conn: DatabaseConnection,
@@ -157,10 +59,11 @@ pub async fn get_match_data(
pub async fn get_match_log(
Path(match_id): Path<i32>,
conn: DatabaseConnection,
+ Extension(config): Extension<Arc<GlobalConfig>>,
) -> Result<Vec<u8>, StatusCode> {
let match_base =
matches::find_match_base(match_id, &conn).map_err(|_| StatusCode::NOT_FOUND)?;
- let log_path = PathBuf::from(MATCHES_DIR).join(&match_base.log_path);
+ let log_path = PathBuf::from(&config.match_logs_directory).join(&match_base.log_path);
let log_contents = std::fs::read(log_path).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
Ok(log_contents)
}
diff --git a/planetwars-server/src/routes/users.rs b/planetwars-server/src/routes/users.rs
index 54ddd09..1989904 100644
--- a/planetwars-server/src/routes/users.rs
+++ b/planetwars-server/src/routes/users.rs
@@ -5,7 +5,7 @@ use axum::extract::{FromRequest, RequestParts, TypedHeader};
use axum::headers::authorization::Bearer;
use axum::headers::Authorization;
use axum::http::StatusCode;
-use axum::response::{Headers, IntoResponse, Response};
+use axum::response::{IntoResponse, Response};
use axum::{async_trait, Json};
use serde::{Deserialize, Serialize};
use serde_json::json;
@@ -163,9 +163,9 @@ pub async fn login(conn: DatabaseConnection, params: Json<LoginParams>) -> Respo
Some(user) => {
let session = sessions::create_session(&user, &conn);
let user_data: UserData = user.into();
- let headers = Headers(vec![("Token", &session.token)]);
+ let headers = [("Token", &session.token)];
- (headers, Json(user_data)).into_response()
+ (StatusCode::OK, headers, Json(user_data)).into_response()
}
}
}