From: Ian Jackson Date: Sun, 25 Oct 2020 12:49:44 +0000 (+0000) Subject: wip new account etc., adding acctid etc. X-Git-Tag: otter-0.2.0~593 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=e875584ee47a009c6c5a284b67b4369c629bd8d8;p=otter.git wip new account etc., adding acctid etc. Signed-off-by: Ian Jackson --- diff --git a/src/accounts.rs b/src/accounts.rs index 9a0b0215..17cb68ac 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -141,8 +141,8 @@ impl FromStr for AccountName { pub struct AccountRecord { pub nick: String, pub timezone: String, - pub access: Arc, pub tokens_revealed: HashMap, + access: Arc, } #[derive(Copy,Clone,Debug,Ord,PartialOrd,Eq,PartialEq)] @@ -231,6 +231,7 @@ impl AccountRecord { #[throws(MgmtError)] pub fn with_entry_mut(account: &AccountName, auth: Authorisation, + set_access: Option>, f: F) -> Result where F: FnOnce(&mut AccountRecord, AccountId) -> T @@ -238,14 +239,12 @@ impl AccountRecord { let (entry, acctid) = AccountRecord::lookup_mut_caller_must_save(account, auth) .ok_or(MgmtError::AccountNotFound)?; - let old_access = entry.access.clone(); + + if let Some(new_access) = set_access() { + invalidate_all_tokens_for_account(acctid)?; + entry.access = new_access; + } let output = f(&mut *entry, acctid); - let mut ok = true; - if ! Arc::ptr_eq(&old_access, &entry.access) { - // xxx actually do this -// invalidate_all_tokens_for_account(accid) -// .dont_just_questionmark - }; let ok = save_accounts_now(); match ok { Ok(()) => Ok(output), @@ -279,6 +278,25 @@ impl AccountRecord { save_accounts_now()?; } + #[throws(MgmtError)] + pub fn remove_entry(account: &AccountName, + _auth: Authorisation) + { + let accounts = ACCOUNTS.write(); + let oe = if_chain! { + if let Some(accounts) = accounts.as_mut(); + let entry = accounts.names.entry(account); + if let hash_map::Entry::Occupied(oe) = entry; + then { oe } + else { throw!(AccountNotFound) } + }; + let acctid = *oe.key(); + process_all_players_for_account(acctid, InstanceGuard::player_remove)?; + oe.remove(); + accounts.records.remove(acctid); + save_accounts_now()?; + } + pub fn expire_tokens_revealed(&mut self) { panic!("xxx") } diff --git a/src/cmdlistener.rs b/src/cmdlistener.rs index 07a6db59..ed7fca36 100644 --- a/src/cmdlistener.rs +++ b/src/cmdlistener.rs @@ -55,7 +55,7 @@ struct CommandStream<'d> { #[derive(Debug,Clone)] struct AccountSpecified { - account: AccountName, + notional_account: AccountName, // might not exist cooked: String, // account.to_string() auth: Authorisation, } @@ -118,6 +118,12 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse { .map_err(|(e,_)|e) ? } + DeleteAccount(account) => { + let auth = authorise_for_account(cs, &account)?; + AccountRecord::remove_entry(&account auth)?; + Fine + } + SetAccount(wanted_account) => { let auth = authorise_scope_direct(cs, &wanted_account.scope)?; cs.account = Some(AccountSpecified { @@ -207,7 +213,7 @@ fn execute_game_insn<'ig>( use MgmtGameResponse::*; type Insn = MgmtGameInstruction; type Resp = MgmtGameResponse; - let who = &cs.who; + let who = &cs.who; // todo show player nick when it's a player #[throws(MgmtError)] fn readonly<'ig, @@ -310,7 +316,6 @@ fn execute_game_insn<'ig>( })?, RemovePlayer(account) => { - // todo let you remove yourself unconditionally let ig = cs.check_acl(ig, PCH::InstanceOrOnlyAffectedAccount(&account), &[TP::RemovePlayer])?.0; diff --git a/src/commands.rs b/src/commands.rs index a3ff0ad0..e9bc99a9 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -11,9 +11,9 @@ pub enum MgmtCommand { CreateAccont(AccountDetails), UpdateAccont(AccountDetails), - DeleteAccount(AccountDetails), + DeleteAccount(AccountName), - SetAccount(AccountName), + SetAccount(AccountName), // success does not mean account exists CreateGame { game: InstanceName, @@ -27,6 +27,9 @@ pub enum MgmtCommand { insns: Vec, how: MgmtGameUpdateMode, }, + DestroyGame { + game: InstanceName, + }, LibraryListByGlob { glob: shapelib::ItemSpec, diff --git a/src/gamestate.rs b/src/gamestate.rs index 916af8d0..43dd12cb 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -46,7 +46,7 @@ pub struct GameState { pub gen : Generation, pub log : VecDeque<(Generation, Arc)>, pub max_z : ZCoord, - pub players : DenseSlotMap, + pub players : DenseSlotMap, } #[derive(Debug,Serialize,Deserialize)] diff --git a/src/global.rs b/src/global.rs index 8676f178..ba0395d1 100644 --- a/src/global.rs +++ b/src/global.rs @@ -55,8 +55,7 @@ pub struct PlayerRecord { #[derive(Debug,Clone,Serialize,Deserialize)] pub struct PlayerState { - pub account: AccountName, - pub nick: String, + pub acctid: AccountId, pub tz: Timezone, } @@ -181,7 +180,7 @@ lazy_static! { #[derive(Default)] pub struct Global { - // lock hierarchy: InstanceContainer < games < {players, clients} + // lock hierarchy: games < InstanceContainer < {players, clients} // (in order of criticality (perf impact); outermost first, innermost last) games : RwLock,InstanceRef>>, players : RwLock>, @@ -343,6 +342,7 @@ impl Instance { let a_savefile = savefilename(&g.name, "a-", ""); let mut gw = GLOBAL.games.write().unwrap(); + // xxx lock order wrong, this function should unlock and then relock let g_file = savefilename(&g.name, "g-", ""); fs::remove_file(&g_file).context("remove").context(g_file)?; @@ -562,6 +562,12 @@ impl InstanceGuard<'_> { Ok((old_account, old_pst)) } + #[throws(InternalError)] + pub fn invalidate_tokens(&mut self, player: PlayerId) { + let old_tokens = self.tokens_players.get(player).clone(); + xxx much of middle of the infallible bit of player_remove + } + #[throws(MgmtError)] fn player_access_reset_redeliver(&mut self, player: PlayerId, authorised: Authorisation, @@ -1047,6 +1053,25 @@ pub fn record_token ( token } +#[throws(E)] +pub fn process_all_players_for_account< + E: Error, + F: FnMut(&mut InstanceGuard, player: PlayerId) -> Result<(),E> + > + (acctid: AccountId, f: F) +{ + let games = GLOBAL.games.write().unlock(); + for gref in games.values() { + let ig = gref.lock(); + let remove : Vec<_> = ig.iplayers.filter_map(|(player,pr)| { + if pr.pst.acctid == acctid { Some(player) } else { None } + }).collect(); + for player in remove.drain(..) { + f(player)?; + } + } +} + // ========== instance pieces data access ========== impl PiecesLoaded {