aboutsummaryrefslogtreecommitdiff
path: root/planetwars-cli
diff options
context:
space:
mode:
authorIlion Beyst <ilion.beyst@gmail.com>2022-07-21 19:19:40 +0200
committerIlion Beyst <ilion.beyst@gmail.com>2022-07-21 19:19:40 +0200
commitc6293d8e328bb96c368921fe922092d4f27f0bc9 (patch)
tree1c374345ba911b79167ae70a654dd0618efa9446 /planetwars-cli
parent31f8271db6735a1c7abea4d93bb3b8d7a3ce4628 (diff)
downloadplanetwars.dev-c6293d8e328bb96c368921fe922092d4f27f0bc9.tar.xz
planetwars.dev-c6293d8e328bb96c368921fe922092d4f27f0bc9.zip
delete old planetwars-cli code
Diffstat (limited to 'planetwars-cli')
-rw-r--r--planetwars-cli/Cargo.toml25
-rw-r--r--planetwars-cli/README.md57
-rw-r--r--planetwars-cli/assets/hex.json43
-rw-r--r--planetwars-cli/assets/pw_workspace.toml6
-rw-r--r--planetwars-cli/assets/simplebot/botconfig.toml2
-rw-r--r--planetwars-cli/assets/simplebot/simplebot.py33
-rw-r--r--planetwars-cli/src/bin/pwcli.rs6
-rw-r--r--planetwars-cli/src/commands/build.rs27
-rw-r--r--planetwars-cli/src/commands/init.rs38
-rw-r--r--planetwars-cli/src/commands/mod.rs40
-rw-r--r--planetwars-cli/src/commands/run_match.rs51
-rw-r--r--planetwars-cli/src/commands/serve.rs17
-rw-r--r--planetwars-cli/src/lib.rs11
-rw-r--r--planetwars-cli/src/web/mod.rs175
-rw-r--r--planetwars-cli/src/workspace/bot.rs50
-rw-r--r--planetwars-cli/src/workspace/mod.rs77
16 files changed, 0 insertions, 658 deletions
diff --git a/planetwars-cli/Cargo.toml b/planetwars-cli/Cargo.toml
deleted file mode 100644
index 972a02b..0000000
--- a/planetwars-cli/Cargo.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-[package]
-name = "planetwars-cli"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-[[bin]]
-name = "pwcli"
-
-[dependencies]
-futures-core = "0.3"
-futures = "0.3"
-tokio = { version = "1", features = ["full"] }
-rand = "0.6"
-serde = { version = "1.0", features = ["derive"] }
-serde_json = "1.0"
-toml = "0.5"
-clap = { version = "3.0.0-rc.8", features = ["derive"] }
-chrono = { version = "0.4", features = ["serde"] }
-shlex = "1.1"
-planetwars-matchrunner = { path = "../planetwars-matchrunner" }
-
-rust-embed = "6.3.0"
-axum = { version = "0.4", features = ["ws"] }
-mime_guess = "2" \ No newline at end of file
diff --git a/planetwars-cli/README.md b/planetwars-cli/README.md
deleted file mode 100644
index dbf8d26..0000000
--- a/planetwars-cli/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# planetwars-cli
-ATTENTION: this package is currently out-of-date.
-
-Note: this project is under active development. All file and configuration formats will take some time to stabilize, so be prepared for breakage when you upgrade to a new version.
-## Building
-
-The cli comes with a local webserver for visualizing matches.
-Therefore, you'll have to build the web application first, so that it can be embedded in the binary.
-
-You will need:
-- rust
-- wasm-pack
-- npm
-
-First, build the frontend:
-```bash
-cd web/pw-frontend
-npm install
-npm run build-wasm
-npm run build
-```
-
-Then build the backend:
-```bash
-cd planetwars-cli
-cargo build --bin pwcli --release
-```
-
-You can install the binary by running
-```bash
-cargo install --path .
-```
-
-## Getting started
-First, initialize your workspace:
-```bash
-pwcli init my-planetwars-workspace
-```
-This creates all required files and directories for your planetwars workspace:
-- `pw_workspace.toml`: workspace configuration
-- `maps/`: for storing maps
-- `matches/`: match logs will be written here
-- `bots/simplebot/` an example bot to get started
-
-All subsequent commands should be run from the root directory of your workspace.
-
-Try playing an example match:
-```bash
-pwcli run-match hex simplebot simplebot
-```
-
-You can now watch a visualization of the match in the web interface:
-```bash
-pwcli serve
-```
-
-You can now try writing your own bot by copying the `simplebot` example. Don't forget to add it in your workspace configuration!
diff --git a/planetwars-cli/assets/hex.json b/planetwars-cli/assets/hex.json
deleted file mode 100644
index 5ef4f31..0000000
--- a/planetwars-cli/assets/hex.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
- "planets": [
- {
- "name": "protos",
- "x": -6,
- "y": 0,
- "owner": 1,
- "ship_count": 6
- },
- {
- "name": "duteros",
- "x": -3,
- "y": 5,
- "ship_count": 6
- },
- {
- "name": "tritos",
- "x": 3,
- "y": 5,
- "ship_count": 6
- },
- {
- "name": "tetartos",
- "x": 6,
- "y": 0,
- "owner": 2,
- "ship_count": 6
- },
- {
- "name": "pemptos",
- "x": 3,
- "y": -5,
- "ship_count": 6
- },
- {
- "name": "extos",
- "x": -3,
- "y": -5,
- "ship_count": 6
- }
- ]
-}
-
diff --git a/planetwars-cli/assets/pw_workspace.toml b/planetwars-cli/assets/pw_workspace.toml
deleted file mode 100644
index d82840f..0000000
--- a/planetwars-cli/assets/pw_workspace.toml
+++ /dev/null
@@ -1,6 +0,0 @@
-[paths]
-maps_dir = "maps"
-matches_dir = "matches"
-
-[bots.simplebot]
-path = "bots/simplebot"
diff --git a/planetwars-cli/assets/simplebot/botconfig.toml b/planetwars-cli/assets/simplebot/botconfig.toml
deleted file mode 100644
index b3a4163..0000000
--- a/planetwars-cli/assets/simplebot/botconfig.toml
+++ /dev/null
@@ -1,2 +0,0 @@
-name = "simplebot"
-run_command = "python3 simplebot.py" \ No newline at end of file
diff --git a/planetwars-cli/assets/simplebot/simplebot.py b/planetwars-cli/assets/simplebot/simplebot.py
deleted file mode 100644
index b2a6b8f..0000000
--- a/planetwars-cli/assets/simplebot/simplebot.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import sys, json
-
-def move(command):
- """ print a command record to stdout """
- moves = []
- if command is not None:
- moves.append(command)
-
- print(json.dumps({ 'moves': moves }))
- # flush the buffer, so that the gameserver can receive the json-encoded line.
- sys.stdout.flush()
-
-
-for line in sys.stdin:
- state = json.loads(line)
- # you are always player 1.
- my_planets = [p for p in state['planets'] if p['owner'] == 1]
- other_planets = [p for p in state['planets'] if p['owner'] != 1]
-
- if not my_planets or not other_planets:
- # we don't own any planets, so we can't make any moves.
- move(None)
- else:
- # find my planet that has the most ships
- planet = max(my_planets, key=lambda p: p['ship_count'])
- # find enemy planet that has the least ships
- destination = min(other_planets, key=lambda p: p['ship_count'])
- # attack!
- move({
- 'origin': planet['name'],
- 'destination': destination['name'],
- 'ship_count': planet['ship_count'] - 1
- })
diff --git a/planetwars-cli/src/bin/pwcli.rs b/planetwars-cli/src/bin/pwcli.rs
deleted file mode 100644
index 438d3bc..0000000
--- a/planetwars-cli/src/bin/pwcli.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use planetwars_cli;
-
-#[tokio::main]
-async fn main() {
- planetwars_cli::run().await
-}
diff --git a/planetwars-cli/src/commands/build.rs b/planetwars-cli/src/commands/build.rs
deleted file mode 100644
index 1df0bb6..0000000
--- a/planetwars-cli/src/commands/build.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-use clap::Parser;
-use std::io;
-use tokio::process;
-
-use crate::workspace::Workspace;
-
-#[derive(Parser)]
-pub struct BuildCommand {
- /// Name of the bot to build
- bot: String,
-}
-
-impl BuildCommand {
- pub async fn run(self) -> io::Result<()> {
- let workspace = Workspace::open_current_dir()?;
- let bot = workspace.get_bot(&self.bot)?;
- if let Some(argv) = bot.config.get_build_argv() {
- process::Command::new(&argv[0])
- .args(&argv[1..])
- .current_dir(&bot.path)
- .spawn()?
- .wait()
- .await?;
- }
- Ok(())
- }
-}
diff --git a/planetwars-cli/src/commands/init.rs b/planetwars-cli/src/commands/init.rs
deleted file mode 100644
index c95626b..0000000
--- a/planetwars-cli/src/commands/init.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-use std::path::PathBuf;
-
-use clap::Parser;
-use futures::io;
-
-#[derive(Parser)]
-pub struct InitCommand {
- /// workspace root directory
- path: String,
-}
-
-macro_rules! copy_asset {
- ($path:expr, $file_name:literal) => {
- ::std::fs::write(
- $path.join($file_name),
- include_bytes!(concat!("../../assets/", $file_name)),
- )?;
- };
-}
-
-impl InitCommand {
- pub async fn run(self) -> io::Result<()> {
- let path = PathBuf::from(&self.path);
-
- // create directories
- std::fs::create_dir_all(&path)?;
- std::fs::create_dir(path.join("maps"))?;
- std::fs::create_dir(path.join("matches"))?;
- std::fs::create_dir_all(path.join("bots/simplebot"))?;
-
- // create files
- copy_asset!(path, "pw_workspace.toml");
- copy_asset!(path.join("maps"), "hex.json");
- copy_asset!(path.join("bots/"), "simplebot/botconfig.toml");
- copy_asset!(path.join("bots/"), "simplebot/simplebot.py");
- Ok(())
- }
-}
diff --git a/planetwars-cli/src/commands/mod.rs b/planetwars-cli/src/commands/mod.rs
deleted file mode 100644
index 52fed5c..0000000
--- a/planetwars-cli/src/commands/mod.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-mod build;
-mod init;
-mod run_match;
-mod serve;
-
-use clap::{Parser, Subcommand};
-use std::io;
-
-#[derive(Parser)]
-#[clap(name = "pwcli")]
-#[clap(author, version, about)]
-pub struct Cli {
- #[clap(subcommand)]
- command: Command,
-}
-
-impl Cli {
- pub async fn run() -> io::Result<()> {
- let cli = Self::parse();
-
- match cli.command {
- Command::Init(command) => command.run().await,
- Command::RunMatch(command) => command.run().await,
- Command::Serve(command) => command.run().await,
- Command::Build(command) => command.run().await,
- }
- }
-}
-
-#[derive(Subcommand)]
-enum Command {
- /// Initialize a new workspace
- Init(init::InitCommand),
- /// Run a match
- RunMatch(run_match::RunMatchCommand),
- /// Host local webserver
- Serve(serve::ServeCommand),
- /// Run build command for a bot
- Build(build::BuildCommand),
-}
diff --git a/planetwars-cli/src/commands/run_match.rs b/planetwars-cli/src/commands/run_match.rs
deleted file mode 100644
index 03868ae..0000000
--- a/planetwars-cli/src/commands/run_match.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-use std::io;
-
-use clap::Parser;
-use planetwars_matchrunner::{run_match, MatchConfig, MatchPlayer};
-
-use crate::workspace::Workspace;
-#[derive(Parser)]
-pub struct RunMatchCommand {
- /// map name
- map: String,
- /// bot names
- bots: Vec<String>,
-}
-
-impl RunMatchCommand {
- pub async fn run(self) -> io::Result<()> {
- let workspace = Workspace::open_current_dir()?;
-
- let map_path = workspace.map_path(&self.map);
- let timestamp = chrono::Local::now().format("%Y-%m-%d-%H-%M-%S");
- let log_path = workspace.match_path(&format!("{}-{}", &self.map, &timestamp));
-
- let mut players = Vec::new();
- for bot_name in &self.bots {
- let bot = workspace.get_bot(&bot_name)?;
- players.push(MatchPlayer {
- name: bot_name.clone(),
- path: bot.path.clone(),
- argv: bot.config.get_run_argv(),
- });
- }
-
- let match_config = MatchConfig {
- map_name: self.map,
- map_path,
- log_path: log_path.clone(),
- players,
- };
-
- run_match(match_config).await;
- println!("match completed successfully");
- // TODO: maybe print the match result as well?
-
- let relative_path = match log_path.strip_prefix(&workspace.root_path) {
- Ok(path) => path.to_str().unwrap(),
- Err(_) => log_path.to_str().unwrap(),
- };
- println!("wrote match log to {}", relative_path);
- Ok(())
- }
-}
diff --git a/planetwars-cli/src/commands/serve.rs b/planetwars-cli/src/commands/serve.rs
deleted file mode 100644
index aa8d149..0000000
--- a/planetwars-cli/src/commands/serve.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use std::io;
-
-use clap::Parser;
-
-use crate::web;
-use crate::workspace::Workspace;
-
-#[derive(Parser)]
-pub struct ServeCommand;
-
-impl ServeCommand {
- pub async fn run(self) -> io::Result<()> {
- let workspace = Workspace::open_current_dir()?;
- web::run(workspace).await;
- Ok(())
- }
-}
diff --git a/planetwars-cli/src/lib.rs b/planetwars-cli/src/lib.rs
deleted file mode 100644
index f67b67f..0000000
--- a/planetwars-cli/src/lib.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-mod commands;
-mod web;
-mod workspace;
-
-pub async fn run() {
- let res = commands::Cli::run().await;
- if let Err(err) = res {
- eprintln!("{}", err);
- std::process::exit(1);
- }
-}
diff --git a/planetwars-cli/src/web/mod.rs b/planetwars-cli/src/web/mod.rs
deleted file mode 100644
index f66b0c6..0000000
--- a/planetwars-cli/src/web/mod.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use axum::{
- body::{boxed, Full},
- extract::{ws::WebSocket, Extension, Path, WebSocketUpgrade},
- handler::Handler,
- http::{header, StatusCode, Uri},
- response::{IntoResponse, Response},
- routing::{get, Router},
- AddExtensionLayer, Json,
-};
-use mime_guess;
-use planetwars_matchrunner::MatchMeta;
-use rust_embed::RustEmbed;
-use serde::{Deserialize, Serialize};
-use std::{
- fs,
- io::{self, BufRead},
- net::SocketAddr,
- path,
- sync::Arc,
-};
-
-use crate::workspace::Workspace;
-
-struct State {
- workspace: Workspace,
-}
-
-impl State {
- fn new(workspace: Workspace) -> Self {
- Self { workspace }
- }
-}
-
-pub async fn run(workspace: Workspace) {
- let shared_state = Arc::new(State::new(workspace));
-
- // build our application with a route
- let app = Router::new()
- .route("/", get(index_handler))
- .route("/ws", get(ws_handler))
- .route("/api/matches", get(list_matches))
- .route("/api/matches/:match_id", get(get_match))
- .fallback(static_handler.into_service())
- .layer(AddExtensionLayer::new(shared_state));
-
- // run it
- let addr = SocketAddr::from(([127, 0, 0, 1], 5000));
- println!("serving at http://{}", addr);
- axum::Server::bind(&addr)
- .serve(app.into_make_service())
- .await
- .unwrap();
-}
-
-async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
- ws.on_upgrade(handle_socket)
-}
-
-async fn handle_socket(mut socket: WebSocket) {
- while let Some(msg) = socket.recv().await {
- let msg = if let Ok(msg) = msg {
- msg
- } else {
- // client disconnected
- return;
- };
-
- if socket.send(msg).await.is_err() {
- // client disconnected
- return;
- }
- }
-}
-
-#[derive(Serialize, Deserialize)]
-struct MatchData {
- name: String,
- #[serde(flatten)]
- meta: MatchMeta,
-}
-
-async fn list_matches(Extension(state): Extension<Arc<State>>) -> Json<Vec<MatchData>> {
- let mut matches = state
- .workspace
- .matches_dir()
- .read_dir()
- .unwrap()
- .filter_map(|entry| {
- let entry = entry.unwrap();
- get_match_data(&entry).ok()
- })
- .collect::<Vec<_>>();
- matches.sort_by(|a, b| {
- let a = a.meta.timestamp;
- let b = b.meta.timestamp;
- a.cmp(&b).reverse()
- });
- Json(matches)
-}
-
-// extracts 'filename' if the entry matches'$filename.log'.
-fn get_match_data(entry: &fs::DirEntry) -> io::Result<MatchData> {
- let file_name = entry.file_name();
- let path = path::Path::new(&file_name);
-
- let name = get_match_name(&path)
- .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "invalid match name"))?;
-
- let meta = read_match_meta(&entry.path())?;
-
- Ok(MatchData { name, meta })
-}
-
-fn get_match_name(path: &path::Path) -> Option<String> {
- if path.extension() != Some("log".as_ref()) {
- return None;
- }
-
- path.file_stem()
- .and_then(|name| name.to_str())
- .map(|name| name.to_string())
-}
-
-fn read_match_meta(path: &path::Path) -> io::Result<MatchMeta> {
- let file = fs::File::open(path)?;
- let mut reader = io::BufReader::new(file);
- let mut line = String::new();
- reader.read_line(&mut line)?;
- let meta: MatchMeta = serde_json::from_str(&line)?;
- Ok(meta)
-}
-
-async fn get_match(Extension(state): Extension<Arc<State>>, Path(id): Path<String>) -> String {
- let mut match_path = state.workspace.matches_dir().join(id);
- match_path.set_extension("log");
- fs::read_to_string(match_path).unwrap()
-}
-
-async fn index_handler() -> impl IntoResponse {
- static_handler("/index.html".parse::<Uri>().unwrap()).await
-}
-
-// static_handler is a handler that serves static files from the
-async fn static_handler(uri: Uri) -> impl IntoResponse {
- let path = uri.path().trim_start_matches('/').to_string();
- StaticFile(path)
-}
-
-#[derive(RustEmbed)]
-#[folder = "../web/pw-frontend/dist/"]
-struct Asset;
-pub struct StaticFile<T>(pub T);
-
-impl<T> IntoResponse for StaticFile<T>
-where
- T: Into<String>,
-{
- fn into_response(self) -> Response {
- let path = self.0.into();
- match Asset::get(path.as_str()) {
- Some(content) => {
- let body = boxed(Full::from(content.data));
- let mime = mime_guess::from_path(path).first_or_octet_stream();
- Response::builder()
- .header(header::CONTENT_TYPE, mime.as_ref())
- .body(body)
- .unwrap()
- }
- None => Response::builder()
- .status(StatusCode::NOT_FOUND)
- .body(boxed(Full::from("404")))
- .unwrap(),
- }
- }
-}
diff --git a/planetwars-cli/src/workspace/bot.rs b/planetwars-cli/src/workspace/bot.rs
deleted file mode 100644
index a0ecb90..0000000
--- a/planetwars-cli/src/workspace/bot.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use shlex;
-use std::fs;
-use std::io;
-use std::path::{Path, PathBuf};
-
-use serde::{Deserialize, Serialize};
-
-const BOT_CONFIG_FILENAME: &str = "botconfig.toml";
-
-pub struct WorkspaceBot {
- pub path: PathBuf,
- pub config: BotConfig,
-}
-
-impl WorkspaceBot {
- pub fn open(path: &Path) -> io::Result<Self> {
- let config_path = path.join(BOT_CONFIG_FILENAME);
- let config_str = fs::read_to_string(config_path)?;
- let bot_config: BotConfig = toml::from_str(&config_str)?;
-
- Ok(WorkspaceBot {
- path: path.to_path_buf(),
- config: bot_config,
- })
- }
-}
-
-#[derive(Serialize, Deserialize)]
-pub struct BotConfig {
- pub name: String,
- pub run_command: String,
- pub build_command: Option<String>,
-}
-
-impl BotConfig {
- // TODO: these commands should not be here
- pub fn get_run_argv(&self) -> Vec<String> {
- // TODO: proper error handling
- shlex::split(&self.run_command)
- .expect("Failed to parse bot run command. Check for unterminated quotes.")
- }
-
- pub fn get_build_argv(&self) -> Option<Vec<String>> {
- // TODO: proper error handling
- self.build_command.as_ref().map(|cmd| {
- shlex::split(cmd)
- .expect("Failed to parse bot build command. Check for unterminated quotes.")
- })
- }
-}
diff --git a/planetwars-cli/src/workspace/mod.rs b/planetwars-cli/src/workspace/mod.rs
deleted file mode 100644
index 5a1a4ae..0000000
--- a/planetwars-cli/src/workspace/mod.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::collections::HashMap;
-use std::env;
-use std::fs;
-use std::io;
-use std::path::{Path, PathBuf};
-
-use self::bot::WorkspaceBot;
-
-const WORKSPACE_CONFIG_FILENAME: &str = "pw_workspace.toml";
-
-pub mod bot;
-
-pub struct Workspace {
- pub root_path: PathBuf,
- pub config: WorkspaceConfig,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct WorkspaceConfig {
- paths: WorkspacePaths,
- bots: HashMap<String, BotEntry>,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct WorkspacePaths {
- maps_dir: PathBuf,
- matches_dir: PathBuf,
-}
-
-#[derive(Serialize, Deserialize, Debug)]
-pub struct BotEntry {
- path: PathBuf,
-}
-
-impl Workspace {
- pub fn open(root_path: &Path) -> io::Result<Workspace> {
- let config_path = root_path.join(WORKSPACE_CONFIG_FILENAME);
- let config_str = fs::read_to_string(config_path)?;
- let workspace_config: WorkspaceConfig = toml::from_str(&config_str)?;
-
- Ok(Workspace {
- root_path: root_path.to_path_buf(),
- config: workspace_config,
- })
- }
-
- pub fn open_current_dir() -> io::Result<Workspace> {
- Workspace::open(&env::current_dir()?)
- }
-
- pub fn maps_dir(&self) -> PathBuf {
- self.root_path.join(&self.config.paths.maps_dir)
- }
-
- pub fn map_path(&self, map_name: &str) -> PathBuf {
- self.maps_dir().join(format!("{}.json", map_name))
- }
-
- pub fn matches_dir(&self) -> PathBuf {
- self.root_path.join(&self.config.paths.matches_dir)
- }
-
- pub fn match_path(&self, match_name: &str) -> PathBuf {
- self.matches_dir().join(format!("{}.log", match_name))
- }
-
- pub fn get_bot(&self, bot_name: &str) -> io::Result<WorkspaceBot> {
- let bot_entry = self.config.bots.get(bot_name).ok_or_else(|| {
- io::Error::new(
- io::ErrorKind::NotFound,
- format!("no such bot: {}", bot_name),
- )
- })?;
- WorkspaceBot::open(&self.root_path.join(&bot_entry.path))
- }
-}