chiark / gitweb /
wip new account etc., adding acctid etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Oct 2020 12:49:44 +0000 (12:49 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 25 Oct 2020 12:49:44 +0000 (12:49 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
src/accounts.rs
src/cmdlistener.rs
src/commands.rs
src/gamestate.rs
src/global.rs

index 9a0b02156cf5a95a308fc9c3bbe613283d5dec17..17cb68acc648757c6938915749a1a0f3ec57c0cd 100644 (file)
@@ -141,8 +141,8 @@ impl FromStr for AccountName {
 pub struct AccountRecord {
   pub nick: String,
   pub timezone: String,
-  pub access: Arc<dyn PlayerAccessSpec>,
   pub tokens_revealed: HashMap<Html, TokenRevelation>,
+  access: Arc<dyn PlayerAccessSpec>,
 }
 
 #[derive(Copy,Clone,Debug,Ord,PartialOrd,Eq,PartialEq)]
@@ -231,6 +231,7 @@ impl AccountRecord {
   #[throws(MgmtError)]
   pub fn with_entry_mut<T, F>(account: &AccountName,
                               auth: Authorisation<AccountName>,
+                              set_access: Option<Arc<dyn PlayerAccessSpec>>,
                               f: F)
                               -> Result<T, (InternalError, T)>
   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<AccountName>)
+  {
+    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")
   }
index 07a6db599be2671c28518a5dc83d57e9f4f42592..ed7fca36d4b76ad5dd255ee0483832c077979f0d 100644 (file)
@@ -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<AccountName>,
 }
@@ -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;
index a3ff0ad0522242d6fe0a196aaa624cc7c5f54adb..e9bc99a9c4b626eeb85235d30e3a47466af632f2 100644 (file)
@@ -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<MgmtGameInstruction>,
     how: MgmtGameUpdateMode,
   },
+  DestroyGame {
+    game: InstanceName,
+  },
 
   LibraryListByGlob {
     glob: shapelib::ItemSpec,
index 916af8d0a38a29bf4b83722835e5df5b84277f9e..43dd12cb5c2b12da59c846250a36e0b207891fd6 100644 (file)
@@ -46,7 +46,7 @@ pub struct GameState {
   pub gen : Generation,
   pub log : VecDeque<(Generation, Arc<CommittedLogEntry>)>,
   pub max_z : ZCoord,
-  pub players : DenseSlotMap<PlayerId, AccountName>,
+  pub players : DenseSlotMap<PlayerId, String /* nick */>,
 }
 
 #[derive(Debug,Serialize,Deserialize)]
index 8676f1788b13228ca5e7771de81c85de79b6deb6..ba0395d160b8eca33c213b1f723977b26eb01f36 100644 (file)
@@ -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<HashMap<Arc<InstanceName>,InstanceRef>>,
   players : RwLock<TokenTable<PlayerId>>,
@@ -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<AccountName>,
@@ -1047,6 +1053,25 @@ pub fn record_token<Id : AccessId> (
   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 {