From: Ian Jackson Date: Mon, 27 Jul 2020 00:40:10 +0000 (+0100) Subject: save, errors, etc. X-Git-Tag: otter-0.2.0~1227 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=8d48620d3359791c1f7186c4b5311ae5be821bab;p=otter.git save, errors, etc. --- diff --git a/src/commands.rs b/src/commands.rs index fc48610e..fa0a97b5 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -45,6 +45,12 @@ pub enum MgmtError { LimitExceeded, SVGProcessingFailed(#[from] SVGProcessingError), GameError(#[from] GameError), + ServerFailure(String), } display_as_debug!{MgmtError} +impl From for MgmtError { + fn from(e: ServerFailure) -> MgmtError { + MgmtError::ServerFailure(format!("ServerFailure {}\n", &e)) + } +} diff --git a/src/error.rs b/src/error.rs index 5d2a71b9..1ec7908c 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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; diff --git a/src/global.rs b/src/global.rs index 7aa5e0d4..435c1307 100644 --- a/src/global.rs +++ b/src/global.rs @@ -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) @@ -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(name: &InstanceName, prefix: &str) -> T { let inp = Self::savefile(name, prefix, ""); let mut f = BufReader::new(fs::File::open(&inp)?); diff --git a/src/http.rs b/src/http.rs index e9a85753..15065f01 100644 --- a/src/http.rs +++ b/src/http.rs @@ -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,