chiark / gitweb /
save, errors, etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 27 Jul 2020 00:40:10 +0000 (01:40 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 27 Jul 2020 00:40:10 +0000 (01:40 +0100)
src/commands.rs
src/error.rs
src/global.rs
src/http.rs

index fc48610e25064442fb6d330d0fe0b08ce71b9962..fa0a97b59d5130be603e439e592147ab2bde25bf 100644 (file)
@@ -45,6 +45,12 @@ pub enum MgmtError {
   LimitExceeded,
   SVGProcessingFailed(#[from] SVGProcessingError),
   GameError(#[from] GameError),
+  ServerFailure(String),
 }
 display_as_debug!{MgmtError}
 
+impl From<ServerFailure> for MgmtError {
+  fn from(e: ServerFailure) -> MgmtError {
+    MgmtError::ServerFailure(format!("ServerFailure {}\n", &e))
+  }
+}
index 5d2a71b9672b025f64a1993c7e47682da2298d22..1ec7908c6c74c238be13a6495485375ab38312e5 100644 (file)
@@ -27,14 +27,20 @@ pub enum OnlineError {
   JSONSerializeFailed(#[from] serde_json::error::Error),
   #[error("SVG processing/generation error {0:?}")]
   SVGProcessingFailed(#[from] SVGProcessingError),
+  #[error("Server operational problems: {0:?}")]
+  ServerFailure(#[from] ServerFailure),
+}
+from_instance_lock_error!{OnlineError}
+
+#[derive(Error,Debug)]
+pub enum ServerFailure {
   #[error("Server IO error {0:?}")]
-  ServerIOError(#[from] io::Error),
+  IO(#[from] io::Error),
   #[error("Server MessagePack encoding error {0:?}")]
-  ServerMessagePackEncodeFail(#[from] rmp_serde::encode::Error),
+  MessagePackEncodeFail(#[from] rmp_serde::encode::Error),
   #[error("Server MessagePack decoding error (game load failed) {0:?}")]
-  ServerMessagePackDecodeFail(#[from] rmp_serde::decode::Error),
+  MessagePackDecodeFail(#[from] rmp_serde::decode::Error),
 }
-from_instance_lock_error!{OnlineError}
 
 pub type StartupError = anyhow::Error;
 
index 7aa5e0d42b6114b0a12ee139d701cbe0c62cb2ff..435c1307397b76ae4a8f4a6daeeefd4af8ba6295 100644 (file)
@@ -148,18 +148,27 @@ impl Instance {
 
     let gref = InstanceRef(Arc::new(Mutex::new(cont)));
 
-    let mut games = GLOBAL.games.write().unwrap();
-    let entry = games.entry(name);
+    {
+      // access without save means it's deleted
+      // save without access menas no accesses
+      // we save first since that's more fallible
+      let mut ig = gref.lock()?;
+      ig.save_access_now()?;
+      ig.save_game_now()?;
+    }
 
-    use hash_map::Entry::*;
-    let entry = match entry {
-      Vacant(ve) => ve,
-      Occupied(_) => throw!(MgmtError::AlreadyExists),
-    };
+    {
+      let mut games = GLOBAL.games.write().unwrap();
+      let entry = games.entry(name);
 
-    entry.insert(gref.clone());
+      use hash_map::Entry::*;
+      let entry = match entry {
+        Vacant(ve) => ve,
+        Occupied(_) => throw!(MgmtError::AlreadyExists),
+      };
 
-    // xxx save, but first release the GLOBAL.games lock
+      entry.insert(gref.clone());
+    }
 
     gref
   }
@@ -251,7 +260,7 @@ impl InstanceGuard<'_> {
       .chain( iter::once(suffix) )
       .collect()
   }
-  #[throws(OE)]
+  #[throws(ServerFailure)]
   fn save_something(
     &self, prefix: &str,
     w: fn(s: &Self, w: &mut BufWriter<fs::File>)
@@ -267,14 +276,14 @@ impl InstanceGuard<'_> {
     eprintln!("saved to {}", &out);
   }
 
-  #[throws(OE)]
+  #[throws(ServerFailure)]
   pub fn save_game_now(&mut self) {
     self.save_something("g-", |s,w| {
       rmp_serde::encode::write_named(w, &s.c.g.gs)
     })?;
   }
 
-  #[throws(OE)]
+  #[throws(ServerFailure)]
   fn save_access_now(&mut self) {
     self.save_something("a-", |s,w| {
       let global_players = GLOBAL.players.read().unwrap();
@@ -291,7 +300,7 @@ impl InstanceGuard<'_> {
     })?;
   }
 
-  #[throws(OE)]
+  #[throws(ServerFailure)]
   fn load_something<T:DeserializeOwned>(name: &InstanceName, prefix: &str) -> T {
     let inp = Self::savefile(name, prefix, "");
     let mut f = BufReader::new(fs::File::open(&inp)?);
index e9a85753a259ca157f2e22cb75a00807f78317b0..15065f01a21400d851cfe54a9a7d4ee2a44b7366 100644 (file)
@@ -15,9 +15,7 @@ impl<'r> Responder<'r> for OnlineError {
     use OnlineError::*;
     let status = match self {
       GameCorrupted | JSONSerializeFailed(_) | SVGProcessingFailed(_)
-        | ServerIOError(_)
-        | ServerMessagePackEncodeFail(_)
-        | ServerMessagePackDecodeFail(_)
+        | ServerFailure(_)
         => Status::InternalServerError,
       NoClient | NoPlayer | GameBeingDestroyed => Status::NotFound,
       InvalidZCoord => Status::BadRequest,