chiark / gitweb /
wip join-game
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 14 Nov 2020 12:26:00 +0000 (12:26 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 14 Nov 2020 12:26:00 +0000 (12:26 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/bin/otter.rs
src/commands.rs

index aac62c3b3ca80f036e023625af1d6b6f156ee0e5..9ea72f2d31de22ebbfa370b7538a7d6d5a6c16b9 100644 (file)
@@ -55,14 +55,18 @@ impl<'x, T, F: FnMut(&str) -> Result<T,String>>
   }
 }
 
-const EXIT_SPACE :    i32 =  2;
-const EXIT_USAGE :    i32 = 12;
-const EXIT_DISASTER : i32 = 16;
+const EXIT_SPACE     : i32 =  2;
+const EXIT_SITUATION : i32 =  8;
+const EXIT_USAGE     : i32 = 12;
+const EXIT_DISASTER  : i32 = 16;
 
 #[derive(Debug)]
 struct MainOpts {
   account: AccountName,
   gaccount: AccountName,
+  nick: Option<String>,
+  timezone: Option<String>,
+  access: Option<Box<dyn PlayerAccessSpec>>,
   socket_path: String,
   verbose: i32,
 }
@@ -601,6 +605,109 @@ mod reset_game {
   )}
 }
 
+//---------- join-game ----------
+
+mod join_game {
+  use super::*;
+
+  #[derive(Default,Debug)]
+  struct Args {
+    table_name: String,
+  }
+
+  fn subargs(sa: &mut Args) -> ArgumentParser {
+    use argparse::*;
+    let mut ap = ArgumentParser::new();
+    ap.refer(&mut sa.table_name).required()
+      .add_argument("TABLE-NAME",Store,"table name");
+    ap
+  }
+
+  fn call(_sc: &Subcommand, ma: MainOpts, args: Vec<String>) ->Result<(),AE> {
+    let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
+
+    let conn = connect(&ma)?;
+
+    #[derive(Debug)]
+    struct Wantup(bool);
+    impl Wantup {
+      fn u<T:Clone>(&mut self, rhs: &Option<T>) -> Option<T> {
+        if rhs.is_some() { self.0 = true }
+        rhs.clone()
+      }
+    }
+    let mut wantup = Wantup(false);
+    let ad = AccountDetails {
+      account:  ma.account.clone(),
+      nick:     ma.nick.clone(),
+      timezone: wantup.y[&ma.timezone],
+      access:   wantup.u[&ma.access],
+    };
+
+    fn is_no_account<T>(r: &Result<T, anyhow::Error>) -> bool {
+      match r {
+        Err(e) if let Some(&ME::AccountNotFound) = e.downcast_ref() => true,
+        _ => false,
+      }
+    }
+    fn fail_need_access() -> Impossible {
+      eprintln!("Need to make your account and set your access token delivery method.  Please pass the --access option.");
+      exit(EXIT_SITUATION);
+    }
+
+    if wantup.0 {
+      let resp = conn.cmd(&MC::UpdateAccount(ad.clone()));
+      let resp = if is_no_account(&resp) {
+        if ad.access.is_none() { fail_need_access(); }
+        conn.cmd(&ME::CreateAccount(ad.clone()O))
+      } else {
+        resp
+      };
+      match resp {
+        Ok(MR::Fine) => (),
+        Ok(x) => anyhow!("unexpected response to UpdateAccount: {:?}", &x)?,
+        Err(x) => throw!(x),
+      }
+    }
+
+    let mut chan = ConnForGame {
+      conn,
+      game: ma.instance_name(&args.table_name),
+      how: MgmtGameUpdateMode::Online,
+    };
+
+    let insns = vec![
+      MGI::JoinGame { nick: ma.nick.clone() },
+    ];
+    let resp = chan.alter_game(insns, |_| Ok(()));
+    if is_no_account(&resp) { fail_need_access(); }
+    match resp? {
+      [MGR::JoinGame { nick, player. token }] => {
+        println!("joined game as player #{} {:?}",
+                 player.get_idx_version().0,
+                 &nick);
+        for l in &token.lines {
+          if l.contains(char::is_control) {
+            println!("Server token info contains control chars! {:?}",
+                     &l);
+          } else {
+            println!(" {}", &l);
+          }
+        }
+      }
+      x => anyhow!("unexpected response to JoinGame: {:?}", &x)?,
+    }
+
+    Ok(())
+  }
+
+  inventory::submit!{Subcommand(
+    "join-game",
+    "Join a game or reset access token (creating or updating account)",
+    call,
+  )}
+}
+
 //---------- library-list ----------
 
 #[derive(Debug)]
index b39df217290a43733e17566ef2e654ec27d7ad14..c8cec6929eba551ea1ad488cb3ccce082cecb3cb 100644 (file)
@@ -20,7 +20,7 @@ pub enum MgmtCommand {
     insns: Vec<MgmtGameInstruction>,
   },
   ListGames {
-    all: Option<bool>, // in same scope by default
+    all: Option<bool>, // in scope of selected account by default
   },
   AlterGame {
     game: InstanceName,
@@ -87,7 +87,6 @@ pub enum MgmtGameInstruction {
 
 #[derive(Debug,Serialize,Deserialize)]
 pub struct MgmtPlayerDetails {
-  pub timezone: Option<String>,
   pub nick: Option<String>,
 }
 
@@ -101,14 +100,14 @@ pub enum MgmtGameResponse {
   JoinGame {
     nick: String,
     player: PlayerId,
-    token: Option<AccessTokenReport>,
+    token: AccessTokenReport,
   },
-  PlayerAccessToken(Option<AccessTokenReport>),
+  PlayerAccessToken(AccessTokenReport),
 }
 
 #[derive(Debug,Clone,Serialize,Deserialize)]
 pub struct AccessTokenReport {
-  pub url: String,
+  lines: Vec<String>,
 }
 
 #[derive(Debug,Clone,Serialize,Deserialize)]