aboutsummaryrefslogtreecommitdiff
path: root/planetwars-server
diff options
context:
space:
mode:
authorIlion Beyst <ilion.beyst@gmail.com>2022-02-27 20:35:22 +0100
committerIlion Beyst <ilion.beyst@gmail.com>2022-02-27 20:35:22 +0100
commit22a8f3d619e8ef89eeb9a60ab0a27aed01aa93f7 (patch)
tree1d6307c96ebd3456e74509203e1155a2c82ffee1 /planetwars-server
parent6ef6a872fe3bbe389e92145b39fd88d864f6a790 (diff)
downloadplanetwars.dev-22a8f3d619e8ef89eeb9a60ab0a27aed01aa93f7.tar.xz
planetwars.dev-22a8f3d619e8ef89eeb9a60ab0a27aed01aa93f7.zip
save all uploaded code bundles in database
Diffstat (limited to 'planetwars-server')
-rw-r--r--planetwars-server/migrations/2021-12-18-130837_bots/up.sql2
-rw-r--r--planetwars-server/src/db/bots.rs4
-rw-r--r--planetwars-server/src/lib.rs17
-rw-r--r--planetwars-server/src/modules/bots.rs23
-rw-r--r--planetwars-server/src/modules/mod.rs3
-rw-r--r--planetwars-server/src/routes/bots.rs2
-rw-r--r--planetwars-server/src/routes/demo.rs24
-rw-r--r--planetwars-server/src/schema.rs2
-rw-r--r--planetwars-server/src/util.rs9
9 files changed, 60 insertions, 26 deletions
diff --git a/planetwars-server/migrations/2021-12-18-130837_bots/up.sql b/planetwars-server/migrations/2021-12-18-130837_bots/up.sql
index 22e250b..a23fbf7 100644
--- a/planetwars-server/migrations/2021-12-18-130837_bots/up.sql
+++ b/planetwars-server/migrations/2021-12-18-130837_bots/up.sql
@@ -8,7 +8,7 @@ CREATE UNIQUE INDEX bots_index ON bots(owner_id, name);
CREATE TABLE code_bundles (
id serial PRIMARY KEY,
- bot_id integer REFERENCES bots(id) NOT NULL,
+ bot_id integer REFERENCES bots(id),
path text NOT NULL,
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
); \ No newline at end of file
diff --git a/planetwars-server/src/db/bots.rs b/planetwars-server/src/db/bots.rs
index f7d8373..baabd5a 100644
--- a/planetwars-server/src/db/bots.rs
+++ b/planetwars-server/src/db/bots.rs
@@ -42,14 +42,14 @@ pub fn find_all_bots(conn: &PgConnection) -> QueryResult<Vec<Bot>> {
#[derive(Insertable)]
#[table_name = "code_bundles"]
pub struct NewCodeBundle<'a> {
- pub bot_id: i32,
+ pub bot_id: Option<i32>,
pub path: &'a str,
}
#[derive(Queryable, Serialize, Deserialize, Debug)]
pub struct CodeBundle {
pub id: i32,
- pub bot_id: i32,
+ pub bot_id: Option<i32>,
pub path: String,
pub created_at: chrono::NaiveDateTime,
}
diff --git a/planetwars-server/src/lib.rs b/planetwars-server/src/lib.rs
index b74525b..89b3d7a 100644
--- a/planetwars-server/src/lib.rs
+++ b/planetwars-server/src/lib.rs
@@ -3,15 +3,17 @@ extern crate diesel;
pub mod db;
pub mod db_types;
+pub mod modules;
pub mod routes;
pub mod schema;
+pub mod util;
use std::ops::Deref;
use axum;
-use bb8::PooledConnection;
+use bb8::{Pool, PooledConnection};
use bb8_diesel::{self, DieselConnectionManager};
-use diesel::PgConnection;
+use diesel::{Connection, PgConnection};
use serde::Deserialize;
use axum::{
@@ -29,9 +31,14 @@ const MAPS_DIR: &str = "./data/maps";
type ConnectionPool = bb8::Pool<DieselConnectionManager<PgConnection>>;
-pub async fn api(configuration: Configuration) -> Router {
- let manager = DieselConnectionManager::<PgConnection>::new(configuration.database_url);
+pub async fn prepare_db(database_url: &str) -> Pool<DieselConnectionManager<PgConnection>> {
+ let manager = DieselConnectionManager::<PgConnection>::new(database_url);
let pool = bb8::Pool::builder().build(manager).await.unwrap();
+ return pool;
+}
+
+pub async fn api(configuration: Configuration) -> Router {
+ let db_pool = prepare_db(&configuration.database_url).await;
let api = Router::new()
.route("/register", post(routes::users::register))
@@ -57,7 +64,7 @@ pub async fn api(configuration: Configuration) -> Router {
get(routes::matches::get_match_log),
)
.route("/submit_bot", post(routes::demo::submit_bot))
- .layer(AddExtensionLayer::new(pool));
+ .layer(AddExtensionLayer::new(db_pool));
api
}
diff --git a/planetwars-server/src/modules/bots.rs b/planetwars-server/src/modules/bots.rs
new file mode 100644
index 0000000..843e48d
--- /dev/null
+++ b/planetwars-server/src/modules/bots.rs
@@ -0,0 +1,23 @@
+use std::path::PathBuf;
+
+use diesel::{PgConnection, QueryResult};
+
+use crate::{db, util::gen_alphanumeric, BOTS_DIR};
+
+pub fn save_code_bundle(
+ bot_code: &str,
+ bot_id: Option<i32>,
+ conn: &PgConnection,
+) -> QueryResult<db::bots::CodeBundle> {
+ let bundle_name = gen_alphanumeric(16);
+
+ let code_bundle_dir = PathBuf::from(BOTS_DIR).join(&bundle_name);
+ std::fs::create_dir(&code_bundle_dir).unwrap();
+ std::fs::write(code_bundle_dir.join("bot.py"), bot_code).unwrap();
+
+ let new_code_bundle = db::bots::NewCodeBundle {
+ bot_id,
+ path: &bundle_name,
+ };
+ db::bots::create_code_bundle(&new_code_bundle, conn)
+}
diff --git a/planetwars-server/src/modules/mod.rs b/planetwars-server/src/modules/mod.rs
new file mode 100644
index 0000000..57c1ef5
--- /dev/null
+++ b/planetwars-server/src/modules/mod.rs
@@ -0,0 +1,3 @@
+// This module implements general domain logic, not directly
+// tied to the database or API layers.
+pub mod bots;
diff --git a/planetwars-server/src/routes/bots.rs b/planetwars-server/src/routes/bots.rs
index 0edfaa9..66b4d82 100644
--- a/planetwars-server/src/routes/bots.rs
+++ b/planetwars-server/src/routes/bots.rs
@@ -97,7 +97,7 @@ pub async fn upload_code_multipart(
.map_err(|_| StatusCode::BAD_REQUEST)?;
let bundle = bots::NewCodeBundle {
- bot_id: bot.id,
+ bot_id: Some(bot.id),
path: &folder_name,
};
let code_bundle =
diff --git a/planetwars-server/src/routes/demo.rs b/planetwars-server/src/routes/demo.rs
index dbcdb64..28eab97 100644
--- a/planetwars-server/src/routes/demo.rs
+++ b/planetwars-server/src/routes/demo.rs
@@ -1,10 +1,11 @@
use crate::db::matches::{self, 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::{docker_runner::DockerBotSpec, run_match, MatchConfig, MatchPlayer};
-use rand::{distributions::Alphanumeric, Rng};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
@@ -15,6 +16,7 @@ const SIMPLEBOT_PATH: &'static str = "../simplebot";
#[derive(Serialize, Deserialize, Debug)]
pub struct SubmitBotParams {
+ pub bot_name: Option<String>,
pub code: String,
}
@@ -32,14 +34,12 @@ pub async fn submit_bot(
) -> Result<Json<SubmitBotResponse>, StatusCode> {
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));
-
- // 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();
+ let code_bundle = save_code_bundle(&params.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"),
@@ -95,11 +95,3 @@ async fn run_match_task(match_id: i32, match_config: MatchConfig, connection_poo
matches::set_match_state(match_id, MatchState::Finished, &conn)
.expect("failed to update match state");
}
-
-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/schema.rs b/planetwars-server/src/schema.rs
index e67ef3a..0ebddf3 100644
--- a/planetwars-server/src/schema.rs
+++ b/planetwars-server/src/schema.rs
@@ -18,7 +18,7 @@ table! {
code_bundles (id) {
id -> Int4,
- bot_id -> Int4,
+ bot_id -> Nullable<Int4>,
path -> Text,
created_at -> Timestamp,
}
diff --git a/planetwars-server/src/util.rs b/planetwars-server/src/util.rs
new file mode 100644
index 0000000..44fcf1c
--- /dev/null
+++ b/planetwars-server/src/util.rs
@@ -0,0 +1,9 @@
+use rand::{distributions::Alphanumeric, Rng};
+
+pub fn gen_alphanumeric(length: usize) -> String {
+ rand::thread_rng()
+ .sample_iter(&Alphanumeric)
+ .take(length)
+ .map(char::from)
+ .collect()
+}