From: Ian Jackson Date: Sun, 8 Nov 2020 13:10:48 +0000 (+0000) Subject: wip new game joining, remove players X-Git-Tag: otter-0.2.0~545 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=0f593b75ecbd10cd88015bd282c5a2f1ccfaa9da;p=otter.git wip new game joining, remove players Signed-off-by: Ian Jackson --- diff --git a/src/accounts.rs b/src/accounts.rs index e87cb490..fe017f5d 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -426,7 +426,7 @@ pub mod loaded_acl { pub struct PermSet (u64, PhantomData<&'static P>); #[derive(Debug,Clone)] - pub struct EffectiveAcl<'i, P: Perm> { + pub struct EffectiveACL<'i, P: Perm> { pub owner_account: Option<&'i str>, pub acl: &'i LoadedAcl

, } @@ -457,7 +457,7 @@ pub mod loaded_acl { ptype: PhantomData<&'static P>, } - impl<'e, P:Perm> EffectiveAcl<'e, P> { + impl<'e, P:Perm> EffectiveACL<'e, P> { fn entries(&self) -> impl Iterator> { self.owner_account.iter().map( |owner| diff --git a/src/bin/otter.rs b/src/bin/otter.rs index cff7739d..face07ad 100644 --- a/src/bin/otter.rs +++ b/src/bin/otter.rs @@ -126,6 +126,8 @@ fn parse_args( completed } +pub fn ok_id(t: T) -> Result { Ok(t) } + fn main() { #[derive(Default,Debug)] struct RawMainArgs { @@ -365,8 +367,8 @@ const PLAYER_DEFAULT_PERMS : &[TablePermission] = &[ TP::ChangePieces, ]; -fn setup_table(ma: &MainOpts, chan: &mut ConnForGame, - spec: &TableSpec, purge_old_players: bool) -> Result<(),AE> { +#[throws(AE)] +fn setup_table(ma: &MainOpts, spec: &TableSpec) -> Vec { let TableSpec { players, player_perms, acl } = spec; let mut player_perms = player_perms.clone() .unwrap_or(PLAYER_DEFAULT_PERMS.iter().cloned().collect()); @@ -388,6 +390,10 @@ fn setup_table(ma: &MainOpts, chan: &mut ConnForGame, let mut insns = vec![]; insns.push(Insn::ClearLog); insns.push(Insn::SetACL { acl }); + insns +} + + /* @@ -452,8 +458,6 @@ fn setup_table(ma: &MainOpts, chan: &mut ConnForGame, } } */ - Ok(()) -} #[throws(AE)] fn read_spec(filename: &str, what: &str) -> T { @@ -489,22 +493,19 @@ mod create_table { #[throws(E)] fn call(_sc: &Subcommand, ma: MainOpts, args: Vec) { - let args = parse_args::(args, &subargs, None, None); + let args = parse_args::(args, &subargs, &ok_id, None); let spec : TableSpec = read_spec(&args.file, "table spec")?; let mut chan = connect(&ma)?; + let insns = setup_table(&ma, &spec)?; chan.cmd(&MgmtCommand::CreateGame { - name: args.name.clone(), insns: vec![] + insns, + game: InstanceName { + game: args.name.clone(), + account: ma.account.clone(), + }, })?; - let mut chan = ConnForGame { - conn: chan, - name: args.name.clone(), - how: MgmtGameUpdateMode::Bulk, - }; - - setup_table(&ma, &mut chan, &spec)?; - if ma.verbose >= 0 { eprintln!("create-table successful. game still needs setup."); } @@ -563,8 +564,8 @@ mod reset_game { Err(e) })?; - setup_table(&ma, &mut chan, &table_spec)?; - } + setup_table(&ma, &table_spec)?; + } let mut insns = vec![]; diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index cc1454f1..a904232f 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -300,7 +300,7 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( } => { let account = &cs.current_account()?.notional_account; let (_arecord, acctid) = ag.lookup(account)?; - let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::AddPlayer])?; + let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::Play])?; let nick = nick.ok_or(ME::ParameterMissing)?; let logentry = LogEntry { html: Html(format!("{} ({}) joined the game", @@ -352,23 +352,6 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( Ok(Resp::Pieces(pieces)) })?, - RemovePlayer { player } => { - let ig = cs.check_acl_modify_player(ag, ig, player, - &[TP::RemovePlayer])?.0; - let (gpl, _ipl) = ig.player_remove(player)?; - let show = if let Some(gpl) = gpl { - htmlescape::encode_minimal(&gpl.nick) - } else { - "partial data?!".to_string() - }; - (U{ pcs: vec![], - log: vec![ LogEntry { - html: Html(format!("{} removed a player: {}", &who, &show)), - }], - raw: None}, - Fine, ig) - }, - UpdatePlayer { player, details: MgmtPlayerDetails { nick, timezone }, @@ -518,11 +501,50 @@ fn execute_game_insn<'cs, 'igr, 'ig : 'igr>( let ag = AccountsGuard::lock(); let (ig, _) = cs.check_acl(&ag, ig, PCH::Instance, &[TP::Super])?; ig.acl = acl.into(); + let mut log = vec![ LogEntry { + html: Html(format!("{} set the table access control list", + &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) { + let mut remove = vec![]; + for (player, ipr) in ig.players { + if_chain! { + let acctid = ipr.ipl.acctid; + if let Some(record,_) = ag.lookup(acctid); + if let Ok(_) = eacl.check(&*record.name, &[TP::Play]); + then { + /* ok */ + } + else { + remove.push(player); + } + }; + }; + for (gpl, _ipl) in ig.players_remove(&remove)? { + let show = if let Some(gpl) = gpl { + htmlescape::encode_minimal(&gpl.nick) + } else { + "partial data?!".to_string() + }; + log.push(LogEntry { + html: Html(format!("{} removed a player {}", &who, &show)), + }); + } + } + + remove_old_players(ag, ig, &who, &eacl, &mut log)?; + (U{ pcs: vec![ ], - log: vec![ LogEntry { - html: Html(format!("{} set the table access control list", - &who)), - } ], + log, raw: None }, Fine, ig) }, @@ -878,7 +900,7 @@ impl CommandStream<'_> { }; let owner_account = owner.to_string(); let owner_account = Some(owner_account.as_str()); - let eacl = EffectiveAcl { owner_account, acl }; + let eacl = EffectiveACL { owner_account, acl }; eacl.check(subject, p)? }; auth diff --git a/src/global.rs b/src/global.rs index db86fe56..834f5856 100644 --- a/src/global.rs +++ b/src/global.rs @@ -499,18 +499,21 @@ impl<'ig> InstanceGuard<'ig> { self.tokens_deregister_for_id(|id| clients_to_remove.contains(&id)); } - // #[throws(ServerFailure)] + // #[throws(InternalError)] // https://github.com/withoutboats/fehler/issues/62 - pub fn player_remove(&mut self, oldplayer: PlayerId) - -> Result<(Option, Option), - InternalError> { + pub fn players_remove(&mut self, oldplayers: HashSet) + -> + Result, Option) + >, InternalError> + { // We have to filter this player out of everything // Then save // Then send updates // 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(oldplayer); + let old_gpl = players.remove(oldplayers); // New state let mut gs = GameState { @@ -530,16 +533,23 @@ impl<'ig> InstanceGuard<'ig> { // after all the things it will reference let mut undo : Vec> = 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 p.held == Some(oldplayer) { + if held_by_old(p) { p.held = None; updated_pieces.push(piece); } } undo.push(Box::new(|ig| for &piece in &updated_pieces { (||Some({ - ig.c.g.gs.pieces.get_mut(piece)?.held = Some(oldplayer); + held_by_old(ig.c.g.gs.pieces.get_mut(piece)?); }))(); })); @@ -578,9 +588,9 @@ impl<'ig> InstanceGuard<'ig> { } buf.finish(); - self.remove_clients(oldplayer, ErrorSignaledViaUpdate::PlayerRemoved); - self.tokens_deregister_for_id(|id:PlayerId| id==oldplayer); - let iplayer = self.iplayers.remove(oldplayer); + 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.save_access_now().unwrap_or_else( |e| warn!( diff --git a/src/imports.rs b/src/imports.rs index a673c5d6..68cdfeac 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -128,7 +128,7 @@ pub use crate::debugreader::DebugReader; pub use crate::shapelib; pub use crate::tz::*; pub use crate::accounts::*; -pub use crate::accounts::loaded_acl::{self,LoadedAcl,EffectiveAcl,PermSet}; +pub use crate::accounts::loaded_acl::{self,LoadedAcl,EffectiveACL,PermSet}; pub use zcoord::{self, ZCoord}; diff --git a/src/spec.rs b/src/spec.rs index 04c2f1e7..0f8ffdc1 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -94,12 +94,11 @@ pub struct AclEntry { pub enum TablePermission { TestExistence, ViewPublic, - AddPlayer, + Play, ChangePieces, ResetOthersAccess, RedeliverOthersAccess, ModifyOtherPlayer, - RemovePlayer, Super, }