chiark / gitweb /
specs: Support ResetFromNamesSpec
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 19 May 2021 22:19:49 +0000 (23:19 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 19 May 2021 22:59:15 +0000 (23:59 +0100)
And the associated config.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
apitest/apitest.rs
daemon/cmdlistener.rs
server-test-zealot.toml
src/bundles.rs
src/commands.rs
src/config.rs

index 04aeaef14dda01e08ec53b9645ba540d42ba64cb..49aded72255a9dc8f05e3d4a617acc79df86a386 100644 (file)
@@ -615,6 +615,7 @@ public_url = "@url@"
 save_dir = "."
 command_socket = "@command_socket@"
 template_dir = "@src@/templates"
+specs_dir = "@src@/specs"
 nwtemplate_dir = "@src@/nwtemplates"
 bundled_sources = "@target@/bundled-sources"
 wasm_dir = "@target@/packed-wasm"
index 22cebb717c28ec553e33463b616c4ad41f67b4d0..3ad736b8e86022a8a9620a45c7f06d406c75882a 100644 (file)
@@ -690,6 +690,22 @@ fn execute_game_insn<'cs, 'igr, 'ig: 'igr>(
         Ok(LogEntry { html })
       }))?
     }
+
+    MGI::ResetFromNamedSpec { spec } => {
+      reset_game_from_spec(cs,ag,ig,who, Box::new(move |ig| {
+        let (mut spec_f, what) = bundles::load_spec_to_read(ig,&spec)?;
+        let mut buf = String::new();
+        spec_f.read_to_string(&mut buf).map_err(|e| match e.kind() {
+          ErrorKind::InvalidData => ME::GameSpecInvalidData,
+          ErrorKind::UnexpectedEof => ME::BadBundle(e.to_string()),
+          _ => IE::from(
+            AE::from(e).context(what).context("read spec")
+          ).into()
+        })?;
+        Ok::<_,ME>(buf)
+      }))?
+    }
+
     MGI::ResetFromGameSpec { spec_toml: spec } => {
       reset_game_from_spec(cs,ag,ig,who, Box::new(|_| Ok::<_,ME>(spec)))?
     }
index e78230f6320aa536c86b7fa1d9818e63e1107466..af0776b3b1bf0cf7a754c6b67902ce107001850f 100644 (file)
@@ -12,6 +12,7 @@ save_dir = "/home/rustcargo/Rustup/Game/server"
 command_socket = "/home/rustcargo/Rustup/Game/server/command.socket"
 template_dir = "/home/ian/Rustup/Game/server/templates"
 nwtemplate_dir = "/home/ian/Rustup/Game/server/nwtemplates"
+specs_dir = "/home/ian/Rustup/Game/server/specs"
 bundled_sources = "/home/rustcargo/Rustup/Game/server/target/bundled-sources"
 wasm_dir = "/home/rustcargo/Rustup/Game/server/target/packed-wasm"
 libexec_dir = "/home/rustcargo/Rustup/Game/server/target/debug"
index c7bc2c9b8903e58541348c9b81047c62e6d198fc..30a9b7556f5dfa08f181ce79a48bbb207512c41b 100644 (file)
@@ -708,6 +708,34 @@ fn make_usvg(za: &mut IndexedZip, progress_count: &mut usize,
   }
 }
 
+//---------- specs ----------
+
+#[throws(MgmtError)]
+pub fn load_spec_to_read(ig: &Instance, spec_name: &str)
+  -> (Box<dyn Read>, String)
+{
+  let spec_leaf = format!("{}.game.toml", spec_name);
+
+  // todo: game specs from bundles
+
+  if spec_name.chars().all(
+    |c| c.is_ascii_alphanumeric() || c=='-' || c =='_'
+  ) {
+    let path = format!("{}/{}", config().specs_dir, &spec_leaf);
+    debug!("{}: trying to loading builtin spec from {}",
+           &ig.name, &path);
+    match File::open(&path) {
+      Ok(f) => return (Box::new(f) as _, path),
+      Err(e) if e.kind() == ErrorKind::NotFound => { },
+      Err(e) => throw!(IE::from(
+        AE::from(e).context(path).context("try open game spec")
+      )),
+    }
+  }
+
+  Err(ME::GameSpecNotFound)?
+}
+
 //---------- scanning/incorporating/uploading ----------
 
 #[throws(InternalError)]
index a390124474b95894abb1be641a353904742be06e..056ce1a203073056703fbb5e574fef696f227883 100644 (file)
@@ -119,6 +119,7 @@ pub enum MgmtGameInstruction {
   DefinePieceAlias { alias: String, target: Box<dyn PieceSpec> },
 
   ClearGame { },
+  ResetFromNamedSpec { spec: String },
   ResetFromGameSpec { spec_toml: String },
 
   ResetPlayerAccess(PlayerId),
@@ -249,6 +250,8 @@ pub enum MgmtError {
   #[error("bad bundle: {0}")]                        BadBundle(String),
   #[error("bundle not found")]                       BundleNotFound,
   #[error("bundle(s) in use, cannot clear ({0})")]   BundlesInUse(String),
+  #[error("game spec not found")]                    GameSpecNotFound,
+  #[error("game contains invalid UTF-8")]            GameSpecInvalidData,
   #[error("idle timeout waiting for mgmt command")]  IdleTimeout,
   #[error("upload took too long (timed out)")]       UploadTimeout,
 }
index b8041ab2bcc135dec9671e7599b65738506ef827..ce97d6962f10b53357af6404219644cad4910dbc 100644 (file)
@@ -36,6 +36,7 @@ pub struct ServerConfigSpec {
   pub log: Option<toml::Value>,
   pub bundled_sources: Option<String>,
   pub shapelibs: Option<Vec<shapelib::Config1>>,
+  pub specs_dir: Option<String>,
   pub sendmail: Option<String>,
   pub debug_js_inject_file: Option<String>,
   #[serde(default)] pub fake_rng: FakeRngSpec,
@@ -65,6 +66,7 @@ pub struct ServerConfig {
   pub usvg_bin: String,
   pub bundled_sources: String,
   pub shapelibs: Vec<shapelib::Config1>,
+  pub specs_dir: String,
   pub sendmail: String,
   pub debug_js_inject: Arc<String>,
   pub check_bundled_sources: bool,
@@ -115,7 +117,7 @@ impl ServerConfigSpec {
     let ServerConfigSpec {
       change_directory, base_dir, save_dir, command_socket, debug,
       http_port, public_url, sse_wildcard_url, rocket_workers,
-      template_dir, nwtemplate_dir, wasm_dir, libexec_dir, usvg_bin,
+      template_dir, specs_dir, nwtemplate_dir, wasm_dir, libexec_dir, usvg_bin,
       log, bundled_sources, shapelibs, sendmail,
       debug_js_inject_file, check_bundled_sources, fake_rng,
     } = self;
@@ -139,6 +141,7 @@ impl ServerConfigSpec {
     };
 
     let save_dir        = defpath(save_dir,        "save"              );
+    let specs_dir       = defpath(specs_dir,       "specs"             );
     let command_socket  = defpath(command_socket,  "var/command.socket");
     let template_dir    = defpath(template_dir,    "assets"            );
     let wasm_dir        = defpath(wasm_dir,        "assets"            );
@@ -228,7 +231,7 @@ impl ServerConfigSpec {
     let server = ServerConfig {
       save_dir, command_socket, debug,
       http_port, public_url, sse_wildcard_url, rocket_workers,
-      template_dir, nwtemplate_dir, wasm_dir, libexec_dir,
+      template_dir, specs_dir, nwtemplate_dir, wasm_dir, libexec_dir,
       bundled_sources, shapelibs, sendmail, usvg_bin,
       debug_js_inject, check_bundled_sources, game_rng, prctx,
     };