chiark / gitweb /
wip new game joining, remove players
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 8 Nov 2020 14:50:28 +0000 (14:50 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 8 Nov 2020 14:50:28 +0000 (14:50 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/accounts.rs
src/cmdlistener.rs
src/commands.rs
src/global.rs

index fe017f5d3cbd98f2bec480cc16b2adefeba0e0a8..0fdd50d05a2144af8048df02fdd852cca52c6c4a 100644 (file)
@@ -338,7 +338,7 @@ impl AccountsGuard {
       else { throw!(AccountNotFound) }
     };
     process_all_players_for_account(acctid, |ig,player| {
-      ig.player_remove(player)?;
+      ig.players_remove(&[player].iter().cloned().collect())?;
       Ok::<_,ME>(())
     })?;
     accounts.names.remove(account);
index a904232f417d2bcae7950f041b4264efa5b474c9..496055966f2ae2da67a5fb30bb6b7a2b8a79fb6b 100644 (file)
@@ -506,29 +506,32 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>(
                            &who)),
       } ];
 
-      let eacl = EffectiveACL {
-        owner_account: &ig.account,
-        acl: &ig.acl,
-      };
-
       #[throws(InternalError)]
       fn remove_old_players(ag: &AccountsGuard, ig: &mut InstanceGuard,
-                            who: &str, eacl: &EffectiveACL<'_, TP>,
-                            log: &mut Vec<LogEntry>) {
-        let mut remove = vec![];
-        for (player, ipr) in ig.players {
+                            who: &Who, log: &mut Vec<LogEntry>) {
+        let owner_account = ig.name.account.to_string();
+        let eacl = EffectiveACL {
+          owner_account: Some(&owner_account),
+          acl: &ig.acl,
+        };
+
+        let mut remove = HashSet::new();
+        for (player, ipr) in &ig.iplayers {
           if_chain! {
             let acctid = ipr.ipl.acctid;
-            if let Some(record,_) = ag.lookup(acctid);
-            if let Ok(_) = eacl.check(&*record.name, &[TP::Play]);
+            if let Ok((record,_)) = ag.lookup(acctid);
+            let perm = &[TP::Play];
+            if let Ok(_) = eacl.check(&record.account.to_string(),
+                                      perm.into());
             then {
               /* ok */
             }
             else {
-              remove.push(player);
+              remove.insert(player);
             }
           };
         };
+
         for (gpl, _ipl) in ig.players_remove(&remove)? {
           let show = if let Some(gpl) = gpl {
             htmlescape::encode_minimal(&gpl.nick)
@@ -541,7 +544,7 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>(
         }
       }
 
-      remove_old_players(ag, ig, &who, &eacl, &mut log)?;
+      remove_old_players(&ag, ig, who, &mut log)?;
 
       (U{ pcs: vec![ ],
           log,
index ad3ae0c40401c9dd303f3881d2b349b86dbfcc01..7a7bd8cdf3c18e2f3d7ce567f5dd0116e940b2cc 100644 (file)
@@ -80,10 +80,10 @@ pub enum MgmtGameInstruction {
 
   JoinGame { details: MgmtPlayerDetails },
   UpdatePlayer { player: PlayerId, details: MgmtPlayerDetails },
-  RemovePlayer { player: PlayerId },
 
   ClearLog,
   SetACL { acl: Acl<TablePermission> },
+  // RemovePlayer { player: PlayerId },  todo, does a special setacl
 }
 
 // xxx facilitator name?
index 834f58562e09e7927a4967dc2725ceb2174f3411..2d2ea9b499c0657a18d281f36a498bb59b256591 100644 (file)
@@ -476,32 +476,34 @@ impl<'ig> InstanceGuard<'ig> {
   }
 
   pub fn remove_clients(&mut self,
-                        player: PlayerId,
+                        players: &HashSet<PlayerId>,
                         signal: ErrorSignaledViaUpdate) {
     let mut clients_to_remove = HashSet::new();
     self.clients.retain(|k,v| {
-      let remove = v.player == player;
+      let remove = players.contains(&v.player);
       if remove { clients_to_remove.insert(k); }
       !remove
     });
 
     let gen = self.c.g.gs.gen;
-    if let Some(iplayer) = self.iplayers.get_mut(player) {
-      iplayer.u.push(PreparedUpdate {
-        gen,
-        when: Instant::now(),
-        us : vec![ PreparedUpdateEntry::Error(
-          None,
-          signal,
-        )],
-      });
-    };
+    for &player in players {
+      if let Some(iplayer) = self.iplayers.get_mut(player) {
+        iplayer.u.push(PreparedUpdate {
+          gen,
+          when: Instant::now(),
+          us : vec![ PreparedUpdateEntry::Error(
+            None,
+            signal.clone(),
+          )],
+        });
+      };
+    }
     self.tokens_deregister_for_id(|id| clients_to_remove.contains(&id));
   }
 
   //  #[throws(InternalError)]
   //  https://github.com/withoutboats/fehler/issues/62
-  pub fn players_remove(&mut self, oldplayers: HashSet<PlayerId>)
+  pub fn players_remove(&mut self, oldplayers: &HashSet<PlayerId>)
                         ->
     Result<Vec<
         (Option<GPlayerState>, Option<IPlayerState>)
@@ -513,7 +515,9 @@ impl<'ig> InstanceGuard<'ig> {
     // We make a copy so if the save fails, we can put everything back
 
     let mut players = self.c.g.gs.players.clone();
-    let old_gpl = players.remove(oldplayers);
+    let old_gpls : Vec<_> = oldplayers.iter().cloned().map(|oldplayer| {
+      players.remove(oldplayer)
+    }).collect();
 
     // New state
     let mut gs = GameState {
@@ -527,19 +531,19 @@ impl<'ig> InstanceGuard<'ig> {
       pieces : Default::default(),
     };
 
+    let held_by_old = |p: &PieceState| if_chain! {
+      if let Some(held) = p.held;
+      if oldplayers.contains(&held);
+      then { true }
+      else { false }
+    };
+
     let mut updated_pieces = vec![];
     
     // drop order is reverse of creation order, so create undo
     // after all the things it will reference
     let mut undo : Vec<Box<dyn FnOnce(&mut InstanceGuard)>> = vec![];
 
-    let held_by_old = |p: PieceState| if_chain! {
-      if let Some(held) = p.held;
-      if oldplayers.contains(held);
-      then { true }
-      else { false }
-    };
-
     // Arrange gs.pieces
     for (piece,p) in &mut self.c.g.gs.pieces {
       if held_by_old(p) {
@@ -573,7 +577,7 @@ impl<'ig> InstanceGuard<'ig> {
     // point of no return
     mem::drop(undo);
 
-    let old_ipl = (||{
+    let old_ipls = (||{
       for &piece in &updated_pieces {
         (||Some({
           self.c.g.gs.pieces.get_mut(piece)?.gen = self.c.g.gs.gen;
@@ -589,18 +593,24 @@ impl<'ig> InstanceGuard<'ig> {
       buf.finish();
 
       self.remove_clients(oldplayers, ErrorSignaledViaUpdate::PlayerRemoved);
-      self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(id));
-      let iplayer = self.iplayers.remove(oldplayers);
-      let ipl = iplayer.map(|iplayer| iplayer.ipl);
+      self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(&id));
+      let old_ipls : Vec<_> = oldplayers.iter().cloned().map(
+        |oldplayer| self.iplayers.remove(oldplayer)
+          .map(|ipr| ipr.ipl)
+      ).collect();
       self.save_access_now().unwrap_or_else(
         |e| warn!(
           "trouble garbage collecting accesses for deleted player: {:?}",
           &e)
       );
-      ipl
+      old_ipls
     })(); // <- No ?, ensures that IEFE is infallible (barring panics)
 
-    Ok((old_gpl, old_ipl))
+    let old = itertools::zip(
+      old_gpls,
+      old_ipls,
+    ).collect();
+    Ok(old)
   }
 
   #[throws(InternalError)]
@@ -619,7 +629,8 @@ impl<'ig> InstanceGuard<'ig> {
     })?;
     // ppoint of no return
     (||{
-      self.remove_clients(player, ErrorSignaledViaUpdate::TokenRevoked);
+      self.remove_clients(&[player].iter().cloned().collect(),
+                          ErrorSignaledViaUpdate::TokenRevoked);
     })(); // <- No ?, ensures that IEFE is infallible (barring panics)
   }