chiark / gitweb /
Break out functions into manipgame.rs
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 2 Jun 2021 22:59:39 +0000 (23:59 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 2 Jun 2021 22:59:39 +0000 (23:59 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
cli/manipgame.rs [new file with mode: 0644]
cli/otter.rs

diff --git a/cli/manipgame.rs b/cli/manipgame.rs
new file mode 100644 (file)
index 0000000..235136d
--- /dev/null
@@ -0,0 +1,398 @@
+// Copyright 2020-2021 Ian Jackson and contributors to Otter
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use super::*;
+
+//---------- list-games ----------
+
+mod list_games {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    all: bool,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.all)
+      .add_option(&["--all"],StoreTrue,
+                  "user superuser access to list *all* games");
+    ap
+  }
+
+  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let mut conn = connect(&ma)?;
+    let mut games = match conn.cmd(&MC::ListGames { all: Some(args.all) })? {
+      MR::GamesList(g) => g,
+      x => throw!(anyhow!("unexpected response to ListGames: {:?}", &x)),
+    };
+    games.sort();
+    for g in games {
+      writeln!(out, "{}", &g)?;
+    }
+    Ok(())
+  }
+
+  inventory_subcmd!{
+    "list-games",
+    "List games",
+  }
+}
+
+// todo: list-players
+// todo: delete-account
+
+//---------- reset-game ----------
+
+mod reset_game {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    table_file: Option<String>,
+    game_spec: String,
+    bundles: Vec<String>,
+    bundles_only: bool,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.table_file).metavar("TABLE-SPEC[-TOML]")
+      .add_option(&["--reset-table"],StoreOption,
+                  "reset the players and access too");
+    ap.refer(&mut sa.game_spec).required()
+      .add_argument("GAME-SPEC",Store,
+                    "game spec, as found in server, \
+                     or local filename if it contains a '/')");
+    ap.refer(&mut sa.bundles).required()
+      .add_argument("BUNDLES",Collect,
+                    "Bundle files to use.  If any are specified, \
+                     all needed bundles must be specified, as any \
+                     not mentioned will be cleared from the server.");
+    let mut bundles_only = ap.refer(&mut sa.bundles_only);
+    bundles_only.add_option(&["--bundles-only"],StoreTrue,
+              "insist that server has only the specified BUNDLES \
+               (clearing out the server if no BUNDLES were specified)");
+    bundles_only.add_option(&["--bundles-at-least"],StoreFalse,
+              "don't care if the server has additional bundles uploaded \
+               earlier (default)");
+    ap
+  }
+
+  fn call(SCCA{ ma, args,.. }:SCCA) -> Result<(),AE> {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let instance_name = ma.instance();
+    let mut chan = ma.access_game()?;
+
+    let reset_insn =
+      if let Some(filename) = spec_arg_is_path(&args.game_spec) {
+        let spec_toml = read_spec_from_path(
+          filename, SpecRaw::<GameSpec>::new())?;
+        MGI::ResetFromGameSpec { spec_toml }
+      } else {
+        MGI::ResetFromNamedSpec { spec: args.game_spec.clone() }
+      };
+
+    let mut insns = vec![];
+
+    if let Some(table_file) = args.table_file {
+      let table_spec = read_spec(&ma, &table_file, SpecParseToml::new())?;
+      let game = chan.game.clone();
+      chan.cmd(&MgmtCommand::CreateGame {
+        game,
+        insns: vec![],
+      }).map(|_|()).or_else(|e| {
+        if let Some(&MgmtError::AlreadyExists) = e.downcast_ref() {
+          return Ok(())
+        }
+        Err(e)
+      })?;
+
+      insns.extend(setup_table(&ma, &instance_name, &table_spec)?);
+    }
+
+    if args.bundles_only || args.bundles.len() != 0 {
+      let local = args.bundles.into_iter().map(|file| {
+        BundleForUpload::prepare(file)
+      }).collect::<Result<Vec<_>,_>>()?;
+
+      let resp = chan.cmd(&MgmtCommand::ListBundles { game: ma.instance() })?;
+      let remote = match resp {
+        MR::Bundles { bundles } => bundles,
+        x => throw!(anyhow!("unexpected response to ListBundles: {:?}",x)),
+      };
+
+      let bundles_only = args.bundles_only;
+      match Itertools::zip_longest(
+        local.iter().rev(),
+        remote.iter().rev(),
+      ).map(|eob| {
+        use EitherOrBoth::*;
+        use bundles::State::*;
+        match eob {
+          Right((id, remote)) => if bundles_only {
+            Err(format!("server has additional bundle(s) eg {} {}",
+                        id, remote))
+          } else {
+            Ok(())
+          },
+          Left(local) => {
+            Err(format!("server is missing {} {} {}",
+                        local.kind, local.hash, local.file))
+          },
+          Both(_local, (id, Uploading)) => {
+            Err(format!("server has incomplete upload :{}", id))
+          },
+          Both(local, (id, Loaded(remote))) => {
+            if (local.size,  local.hash) !=
+               (remote.size, remote.hash) {
+               Err(format!("server's {} does not match {}", id, &local.file))
+            } else {
+               Ok(())
+            }
+          }
+        }
+      }).find_map(Result::err).map_or_else(|| Ok(()), Err) {
+        Ok(()) => {
+          if ma.verbose >= 0 {
+            eprintln!("Reusing server's existing bundles");
+          }
+        },
+        Err(why) => {
+          if ma.verbose >= 0 {
+            eprintln!("Re-uploading bundles: {}", why);
+          }
+          if bundles_only {
+            clear_game(&ma, &mut chan)?;
+          }
+          let progress = ma.progressbar()?;
+          let mut progress = termprogress::Nest::new(local.len(), progress);
+          for bundle in local {
+            bundle.upload(&ma, &mut chan, &mut progress)?;
+          }
+        },
+      }
+    }
+
+    insns.push(reset_insn);
+
+    chan.alter_game(insns, None)?;
+
+    if ma.verbose >= 0 {
+      eprintln!("reset successful.");
+    }
+    Ok(())
+  }
+
+  inventory_subcmd!{
+    "reset",
+    "Reset the state of the game table",
+  }
+}
+
+//---------- set-link ----------
+
+mod set_link {
+
+  use super::*;
+
+  #[derive(Debug,Default)]
+  struct Args {
+    kind: Option<LinkKind>,
+    url: Option<String>,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.kind)
+      .add_argument("LINK-KIND",StoreOption,"link kind");
+    ap.refer(&mut sa.url)
+      .add_argument("URL",StoreOption,"url (or empty for none)");
+    ap
+  }
+
+  #[throws(AE)]
+  fn call(SCCA{ mut out, ma, args,.. }:SCCA) {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let mut chan = ma.access_game()?;
+
+    match args.url {
+      None => {
+        let MgmtGameResponseGameInfo { links, .. } = chan.info()?;
+        for (tk, v) in links {
+          let v: Url = (&v).try_into().context("reparse sererr's UrlSpec")?;
+          match args.kind {
+            None => {
+              writeln!(out, "{:<10} {}", tk, &v)?;
+            }
+            Some(wk) => {
+              if wk == tk {
+                writeln!(out, "{}", &v)?;
+              }
+            }
+          }
+        }
+      },
+
+      Some(url) => {
+        let kind = args.kind.unwrap();
+        chan.alter_game(vec![
+          if url == "" {
+            MGI::RemoveLink { kind }
+          } else {
+            MGI::SetLink { kind, url: UrlSpec(url) }
+          }
+        ], None)?;
+      },
+    }
+  }
+
+  inventory_subcmd!{
+    "set-link",
+    "Set one of the info links visible from within the game",
+  }
+}
+
+//---------- join-game ----------
+
+mod join_game {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    reset_access: bool,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.reset_access)
+      .add_option(&["--reset"],StoreTrue,
+                  "generate and deliver new player access token");
+    ap
+  }
+
+  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+    let mut chan = ma.access_game()?;
+
+    let mut insns = vec![];
+    match chan.has_player(&ma.account)? {
+      None => {
+        let nick = ma.nick.clone()
+          .unwrap_or_else(|| ma.account.default_nick());
+        let details = MgmtPlayerDetails { nick: Some(nick) };
+        insns.push(MGI::JoinGame { details });
+      }
+      Some((player, mpi)) => {
+        writeln!(out, "already in game, as player #{} {:?}",
+                 player.0.get_idx_version().0, &mpi.nick)?;
+        let MgmtPlayerInfo { nick, account:_ } = mpi;
+        if let Some(new_nick) = &ma.nick {
+          if &nick != new_nick {
+            writeln!(out, "changing nick to {:?}", &new_nick)?;
+            let details = MgmtPlayerDetails { nick: ma.nick.clone() };
+            insns.push(MGI::UpdatePlayer { player, details });
+          }
+        }
+        if args.reset_access {
+          writeln!(out, "resetting access token (invalidating other URLs)")?;
+          insns.push(MGI::ResetPlayerAccess(player));
+        } else {
+          writeln!(out, "redelivering existing access token")?;
+          insns.push(MGI::RedeliverPlayerAccess(player));
+        }
+      }
+    };
+
+    fn deliver(out: &mut CookedStdout, token: &AccessTokenReport) {
+      for l in &token.lines {
+        if l.contains(char::is_control) {
+          writeln!(out, "Server token info contains control chars! {:?}", &l)
+        } else {
+          writeln!(out, " {}", &l)
+        }.unwrap()
+      }
+    }
+
+    for resp in chan.alter_game(insns, None)? {
+      match resp {
+        MGR::JoinGame { nick, player, token } => {
+          writeln!(out, "joined game as player #{} {:?}",
+                   player.0.get_idx_version().0,
+                   &nick)?;
+          deliver(&mut out, &token);
+        }
+        MGR::PlayerAccessToken(token) => {
+          deliver(&mut out, &token);
+        }
+        MGR::Fine => {}
+        _ => throw!(anyhow!("unexpected response to instruction(s)")),
+      }
+    }
+
+    Ok(())
+  }
+
+  inventory_subcmd!{
+    "join-game",
+    "Join a game or reset access token (creating or updating account)",
+  }
+}
+
+//---------- leave-game ----------
+
+mod leave_game {
+  use super::*;
+
+  type Args = NoArgs;
+
+  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
+    let _args = parse_args::<Args,_>(args, &noargs, &ok_id, None);
+    let mut chan = ma.access_game()?;
+
+    let player = match chan.has_player(&ma.account)? {
+      None => {
+        writeln!(out, "this account is not a player in that game")?;
+        exit(EXIT_NOTFOUND);
+      }
+      Some((player, _)) => player,
+    };
+
+    chan.alter_game(vec![MGI::LeaveGame(player)], None)?;
+
+    Ok(())
+  }
+
+  inventory_subcmd!{
+    "leave-game",
+    "Leave a game",
+  }
+}
+
+//---------- delete-game ----------
+
+mod delete_game {
+  use super::*;
+
+  type Args = NoArgs;
+
+  fn call(SCCA{ ma, args,.. }:SCCA) -> Result<(),AE> {
+    let _args = parse_args::<Args,_>(args, &noargs, &ok_id, None);
+    let mut chan = ma.access_game()?;
+    let game = chan.game.clone();
+    chan.cmd(&MC::DestroyGame { game })?;
+    Ok(())
+  }
+
+  inventory_subcmd!{
+    "delete-game",
+    "Delete a game (throwing all the players out of it)",
+  }
+}
index bce86444cb0591d315f78ea7648b27741dd04cca..d7b01e0f3d4b6e8ad1ead0c59309231f9263bc0e 100644 (file)
@@ -29,6 +29,8 @@ pub use argparse::action::ParseResult::Parsed;
 pub mod clisupport;
 use clisupport::*;
 
+mod manipgame;
+
 #[derive(Debug)]
 enum ServerLocation {
   Socket(String),
@@ -318,399 +320,6 @@ fn main() {
     .unwrap_or_else(|e| e.end_process(12));
 }
 
-//---------- list-games ----------
-
-mod list_games {
-  use super::*;
-
-  #[derive(Default,Debug)]
-  struct Args {
-    all: bool,
-  }
-
-  fn subargs(sa: &mut Args) -> ArgumentParser {
-    use argparse::*;
-    let mut ap = ArgumentParser::new();
-    ap.refer(&mut sa.all)
-      .add_option(&["--all"],StoreTrue,
-                  "user superuser access to list *all* games");
-    ap
-  }
-
-  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
-    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
-    let mut conn = connect(&ma)?;
-    let mut games = match conn.cmd(&MC::ListGames { all: Some(args.all) })? {
-      MR::GamesList(g) => g,
-      x => throw!(anyhow!("unexpected response to ListGames: {:?}", &x)),
-    };
-    games.sort();
-    for g in games {
-      writeln!(out, "{}", &g)?;
-    }
-    Ok(())
-  }
-
-  inventory_subcmd!{
-    "list-games",
-    "List games",
-  }
-}
-
-// todo: list-players
-// todo: delete-account
-
-//---------- reset-game ----------
-
-mod reset_game {
-  use super::*;
-
-  #[derive(Default,Debug)]
-  struct Args {
-    table_file: Option<String>,
-    game_spec: String,
-    bundles: Vec<String>,
-    bundles_only: bool,
-  }
-
-  fn subargs(sa: &mut Args) -> ArgumentParser {
-    use argparse::*;
-    let mut ap = ArgumentParser::new();
-    ap.refer(&mut sa.table_file).metavar("TABLE-SPEC[-TOML]")
-      .add_option(&["--reset-table"],StoreOption,
-                  "reset the players and access too");
-    ap.refer(&mut sa.game_spec).required()
-      .add_argument("GAME-SPEC",Store,
-                    "game spec, as found in server, \
-                     or local filename if it contains a '/')");
-    ap.refer(&mut sa.bundles).required()
-      .add_argument("BUNDLES",Collect,
-                    "Bundle files to use.  If any are specified, \
-                     all needed bundles must be specified, as any \
-                     not mentioned will be cleared from the server.");
-    let mut bundles_only = ap.refer(&mut sa.bundles_only);
-    bundles_only.add_option(&["--bundles-only"],StoreTrue,
-              "insist that server has only the specified BUNDLES \
-               (clearing out the server if no BUNDLES were specified)");
-    bundles_only.add_option(&["--bundles-at-least"],StoreFalse,
-              "don't care if the server has additional bundles uploaded \
-               earlier (default)");
-    ap
-  }
-
-  fn call(SCCA{ ma, args,.. }:SCCA) -> Result<(),AE> {
-    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
-    let instance_name = ma.instance();
-    let mut chan = ma.access_game()?;
-
-    let reset_insn =
-      if let Some(filename) = spec_arg_is_path(&args.game_spec) {
-        let spec_toml = read_spec_from_path(
-          filename, SpecRaw::<GameSpec>::new())?;
-        MGI::ResetFromGameSpec { spec_toml }
-      } else {
-        MGI::ResetFromNamedSpec { spec: args.game_spec.clone() }
-      };
-
-    let mut insns = vec![];
-
-    if let Some(table_file) = args.table_file {
-      let table_spec = read_spec(&ma, &table_file, SpecParseToml::new())?;
-      let game = chan.game.clone();
-      chan.cmd(&MgmtCommand::CreateGame {
-        game,
-        insns: vec![],
-      }).map(|_|()).or_else(|e| {
-        if let Some(&MgmtError::AlreadyExists) = e.downcast_ref() {
-          return Ok(())
-        }
-        Err(e)
-      })?;
-
-      insns.extend(setup_table(&ma, &instance_name, &table_spec)?);
-    }
-
-    if args.bundles_only || args.bundles.len() != 0 {
-      let local = args.bundles.into_iter().map(|file| {
-        BundleForUpload::prepare(file)
-      }).collect::<Result<Vec<_>,_>>()?;
-
-      let resp = chan.cmd(&MgmtCommand::ListBundles { game: ma.instance() })?;
-      let remote = match resp {
-        MR::Bundles { bundles } => bundles,
-        x => throw!(anyhow!("unexpected response to ListBundles: {:?}",x)),
-      };
-
-      let bundles_only = args.bundles_only;
-      match Itertools::zip_longest(
-        local.iter().rev(),
-        remote.iter().rev(),
-      ).map(|eob| {
-        use EitherOrBoth::*;
-        use bundles::State::*;
-        match eob {
-          Right((id, remote)) => if bundles_only {
-            Err(format!("server has additional bundle(s) eg {} {}",
-                        id, remote))
-          } else {
-            Ok(())
-          },
-          Left(local) => {
-            Err(format!("server is missing {} {} {}",
-                        local.kind, local.hash, local.file))
-          },
-          Both(_local, (id, Uploading)) => {
-            Err(format!("server has incomplete upload :{}", id))
-          },
-          Both(local, (id, Loaded(remote))) => {
-            if (local.size,  local.hash) !=
-               (remote.size, remote.hash) {
-               Err(format!("server's {} does not match {}", id, &local.file))
-            } else {
-               Ok(())
-            }
-          }
-        }
-      }).find_map(Result::err).map_or_else(|| Ok(()), Err) {
-        Ok(()) => {
-          if ma.verbose >= 0 {
-            eprintln!("Reusing server's existing bundles");
-          }
-        },
-        Err(why) => {
-          if ma.verbose >= 0 {
-            eprintln!("Re-uploading bundles: {}", why);
-          }
-          if bundles_only {
-            clear_game(&ma, &mut chan)?;
-          }
-          let progress = ma.progressbar()?;
-          let mut progress = termprogress::Nest::new(local.len(), progress);
-          for bundle in local {
-            bundle.upload(&ma, &mut chan, &mut progress)?;
-          }
-        },
-      }
-    }
-
-    insns.push(reset_insn);
-
-    chan.alter_game(insns, None)?;
-
-    if ma.verbose >= 0 {
-      eprintln!("reset successful.");
-    }
-    Ok(())
-  }
-
-  inventory_subcmd!{
-    "reset",
-    "Reset the state of the game table",
-  }
-}
-
-//---------- set-link ----------
-
-mod set_link {
-
-  use super::*;
-
-  #[derive(Debug,Default)]
-  struct Args {
-    kind: Option<LinkKind>,
-    url: Option<String>,
-  }
-
-  fn subargs(sa: &mut Args) -> ArgumentParser {
-    use argparse::*;
-    let mut ap = ArgumentParser::new();
-    ap.refer(&mut sa.kind)
-      .add_argument("LINK-KIND",StoreOption,"link kind");
-    ap.refer(&mut sa.url)
-      .add_argument("URL",StoreOption,"url (or empty for none)");
-    ap
-  }
-
-  #[throws(AE)]
-  fn call(SCCA{ mut out, ma, args,.. }:SCCA) {
-    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
-    let mut chan = ma.access_game()?;
-
-    match args.url {
-      None => {
-        let MgmtGameResponseGameInfo { links, .. } = chan.info()?;
-        for (tk, v) in links {
-          let v: Url = (&v).try_into().context("reparse sererr's UrlSpec")?;
-          match args.kind {
-            None => {
-              writeln!(out, "{:<10} {}", tk, &v)?;
-            }
-            Some(wk) => {
-              if wk == tk {
-                writeln!(out, "{}", &v)?;
-              }
-            }
-          }
-        }
-      },
-
-      Some(url) => {
-        let kind = args.kind.unwrap();
-        chan.alter_game(vec![
-          if url == "" {
-            MGI::RemoveLink { kind }
-          } else {
-            MGI::SetLink { kind, url: UrlSpec(url) }
-          }
-        ], None)?;
-      },
-    }
-  }
-
-  inventory_subcmd!{
-    "set-link",
-    "Set one of the info links visible from within the game",
-  }
-}
-
-//---------- join-game ----------
-
-mod join_game {
-  use super::*;
-
-  #[derive(Default,Debug)]
-  struct Args {
-    reset_access: bool,
-  }
-
-  fn subargs(sa: &mut Args) -> ArgumentParser {
-    use argparse::*;
-    let mut ap = ArgumentParser::new();
-    ap.refer(&mut sa.reset_access)
-      .add_option(&["--reset"],StoreTrue,
-                  "generate and deliver new player access token");
-    ap
-  }
-
-  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
-    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
-    let mut chan = ma.access_game()?;
-
-    let mut insns = vec![];
-    match chan.has_player(&ma.account)? {
-      None => {
-        let nick = ma.nick.clone()
-          .unwrap_or_else(|| ma.account.default_nick());
-        let details = MgmtPlayerDetails { nick: Some(nick) };
-        insns.push(MGI::JoinGame { details });
-      }
-      Some((player, mpi)) => {
-        writeln!(out, "already in game, as player #{} {:?}",
-                 player.0.get_idx_version().0, &mpi.nick)?;
-        let MgmtPlayerInfo { nick, account:_ } = mpi;
-        if let Some(new_nick) = &ma.nick {
-          if &nick != new_nick {
-            writeln!(out, "changing nick to {:?}", &new_nick)?;
-            let details = MgmtPlayerDetails { nick: ma.nick.clone() };
-            insns.push(MGI::UpdatePlayer { player, details });
-          }
-        }
-        if args.reset_access {
-          writeln!(out, "resetting access token (invalidating other URLs)")?;
-          insns.push(MGI::ResetPlayerAccess(player));
-        } else {
-          writeln!(out, "redelivering existing access token")?;
-          insns.push(MGI::RedeliverPlayerAccess(player));
-        }
-      }
-    };
-
-    fn deliver(out: &mut CookedStdout, token: &AccessTokenReport) {
-      for l in &token.lines {
-        if l.contains(char::is_control) {
-          writeln!(out, "Server token info contains control chars! {:?}", &l)
-        } else {
-          writeln!(out, " {}", &l)
-        }.unwrap()
-      }
-    }
-
-    for resp in chan.alter_game(insns, None)? {
-      match resp {
-        MGR::JoinGame { nick, player, token } => {
-          writeln!(out, "joined game as player #{} {:?}",
-                   player.0.get_idx_version().0,
-                   &nick)?;
-          deliver(&mut out, &token);
-        }
-        MGR::PlayerAccessToken(token) => {
-          deliver(&mut out, &token);
-        }
-        MGR::Fine => {}
-        _ => throw!(anyhow!("unexpected response to instruction(s)")),
-      }
-    }
-
-    Ok(())
-  }
-
-  inventory_subcmd!{
-    "join-game",
-    "Join a game or reset access token (creating or updating account)",
-  }
-}
-
-//---------- leave-game ----------
-
-mod leave_game {
-  use super::*;
-
-  type Args = NoArgs;
-
-  fn call(SCCA{ mut out, ma, args,.. }:SCCA) -> Result<(),AE> {
-    let _args = parse_args::<Args,_>(args, &noargs, &ok_id, None);
-    let mut chan = ma.access_game()?;
-
-    let player = match chan.has_player(&ma.account)? {
-      None => {
-        writeln!(out, "this account is not a player in that game")?;
-        exit(EXIT_NOTFOUND);
-      }
-      Some((player, _)) => player,
-    };
-
-    chan.alter_game(vec![MGI::LeaveGame(player)], None)?;
-
-    Ok(())
-  }
-
-  inventory_subcmd!{
-    "leave-game",
-    "Leave a game",
-  }
-}
-
-//---------- delete-game ----------
-
-mod delete_game {
-  use super::*;
-
-  type Args = NoArgs;
-
-  fn call(SCCA{ ma, args,.. }:SCCA) -> Result<(),AE> {
-    let _args = parse_args::<Args,_>(args, &noargs, &ok_id, None);
-    let mut chan = ma.access_game()?;
-    let game = chan.game.clone();
-    chan.cmd(&MC::DestroyGame { game })?;
-    Ok(())
-  }
-
-  inventory_subcmd!{
-    "delete-game",
-    "Delete a game (throwing all the players out of it)",
-  }
-}
-
 //---------- library-list ----------
 
 #[derive(Debug,Default)]