minimal port of start_match logic

This commit is contained in:
Ilion Beyst 2022-01-01 16:32:55 +01:00
parent 4a077c7c65
commit bdb77f97d6
5 changed files with 82 additions and 9 deletions

View file

@ -21,6 +21,11 @@ chrono = { version = "0.4", features = ["serde"] }
serde_json = "1.0" serde_json = "1.0"
base64 = "0.13.0" base64 = "0.13.0"
zip = "0.5" zip = "0.5"
toml = "0.5"
planetwars-matchrunner = { path = "../planetwars-matchrunner" }
# TODO: remove me
shlex = "1.1"
[dev-dependencies] [dev-dependencies]
parking_lot = "0.11" parking_lot = "0.11"

View file

@ -68,3 +68,10 @@ pub fn find_bot_code_bundles(bot_id: i32, conn: &PgConnection) -> QueryResult<Ve
.filter(code_bundles::bot_id.eq(bot_id)) .filter(code_bundles::bot_id.eq(bot_id))
.get_results(conn) .get_results(conn)
} }
pub fn active_code_bundle(bot_id: i32, conn: &PgConnection) -> QueryResult<CodeBundle> {
code_bundles::table
.filter(code_bundles::bot_id.eq(bot_id))
.order(code_bundles::created_at.desc())
.first(conn)
}

View file

@ -22,6 +22,11 @@ use axum::{
AddExtensionLayer, Router, AddExtensionLayer, Router,
}; };
// TODO: make these configurable
const BOTS_DIR: &str = "./data/bots";
const MATCHES_DIR: &str = "./data/matches";
const MAPS_DIR: &str = "./data/maps";
type ConnectionPool = bb8::Pool<DieselConnectionManager<PgConnection>>; type ConnectionPool = bb8::Pool<DieselConnectionManager<PgConnection>>;
pub async fn api() -> Router { pub async fn api() -> Router {

View file

@ -1,22 +1,18 @@
use axum::extract::{Multipart, Path, RawBody}; use axum::extract::{Multipart, Path};
use axum::http::StatusCode; use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::Json; use axum::Json;
use rand::distributions::Alphanumeric; use rand::distributions::Alphanumeric;
use rand::Rng; use rand::Rng;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{json, value::Value as JsonValue}; use serde_json::{json, value::Value as JsonValue};
use std::io::Cursor; use std::io::Cursor;
use std::path::{self, PathBuf}; use std::path::PathBuf;
use crate::db::bots::{self, CodeBundle}; use crate::db::bots::{self, CodeBundle};
use crate::db::users::User; use crate::db::users::User;
use crate::DatabaseConnection; use crate::{DatabaseConnection, BOTS_DIR};
use bots::Bot; use bots::Bot;
// TODO: make this a parameter
const BOTS_DIR: &str = "./data/bots";
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct BotParams { pub struct BotParams {
name: String, name: String,

View file

@ -1,12 +1,72 @@
use std::path::PathBuf;
use axum::Json; use axum::Json;
use hyper::StatusCode;
use planetwars_matchrunner::{run_match, MatchConfig, MatchPlayer};
use rand::{distributions::Alphanumeric, Rng};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{
db::{bots, users::User},
DatabaseConnection, BOTS_DIR, MAPS_DIR, MATCHES_DIR,
};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct MatchParams { pub struct MatchParams {
// Just bot ids for now // Just bot ids for now
players: Vec<i32>, players: Vec<i32>,
} }
pub async fn play_match(params: Json<MatchParams>) { pub async fn play_match(
println!("start match: {:#?}", params); user: User,
conn: DatabaseConnection,
Json(params): Json<MatchParams>,
) -> Result<(), StatusCode> {
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_path = PathBuf::from(MATCHES_DIR).join(&format!("{}.log", slug));
let mut players = 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 {
name: bot.name.clone(),
path: PathBuf::from(BOTS_DIR).join(code_bundle.path),
argv: shlex::split(&bot_config.run_command)
// TODO: this is an user error, should ideally be handled before we get here
.ok_or_else(|| StatusCode::INTERNAL_SERVER_ERROR)?,
});
}
let match_config = MatchConfig {
map_name: "hex".to_string(),
map_path,
log_path: log_path.clone(),
players,
};
tokio::spawn(run_match(match_config));
Ok(())
}
// 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>,
} }