chiark / gitweb /
reorganise token registries nfc
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 17 Jul 2020 23:02:41 +0000 (00:02 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 17 Jul 2020 23:02:41 +0000 (00:02 +0100)
src/bin/server.rs
src/global.rs
src/imports.rs
src/session.rs

index 0c9609f5151f0cd0c925092dbcaa7b5abc4727d1..46181ebb817be8063af73a452c95b9fdf0b5e657 100644 (file)
@@ -69,7 +69,7 @@ fn resource(leaf : CheckedResourceLeaf) -> io::Result<NamedFile> {
 }  
 
 fn main() {
-  xxx_global_setup();
+  xxx_global_setup().expect("global setup failed");
 
   let helmet = SpaceHelmet::default()
     .enable(NoSniff::Enable)
index e57e2ce951741fe94bd9a30e8126261604b58596..2e751434597aad2ac7e6bd7b0eb4bee9fc38f1e6 100644 (file)
@@ -16,6 +16,8 @@ pub struct Instance {
   pub gs : GameState,
   pub clients : DenseSlotMap<ClientId,Client>,
   pub updates : SecondarySlotMap<PlayerId, PlayerUpdates>,
+  pub tokens_players : TokenRegistry<PlayerId>,
+  pub tokens_clients : TokenRegistry<ClientId>,
 }
 
 #[derive(Debug)] 
@@ -23,6 +25,12 @@ pub struct Client {
   pub player : PlayerId,
 }
 
+#[derive(Debug)]
+pub struct InstanceGuard<'g> {
+  ig : MutexGuard<'g,Instance>,
+  amu : Arc<Mutex<Instance>>,
+}
+
 #[derive(Default)]
 struct Global {
   // lock hierarchy: this is the innermost lock
@@ -31,6 +39,12 @@ struct Global {
   // xxx delete instances at some point!
 }
 
+#[derive(Debug,Default)]
+pub struct TokenRegistry<Id: AccessId> {
+  tr : HashSet<RawToken>,
+  id : PhantomData<Id>,
+}
+
 // ---------- API ----------
 
 #[derive(Clone,Debug)]
@@ -49,6 +63,7 @@ pub type TokenTable<Id> = HashMap<RawToken, InstanceAccessDetails<Id>>;
 
 pub trait AccessId : Copy + Clone + 'static {
   fn global_tokens() -> &'static RwLock<TokenTable<Self>>;
+  fn tokens_registry(ig: &mut Instance) -> &mut TokenRegistry<Self>;
   const ERROR : OnlineError;
 }
 
@@ -66,15 +81,81 @@ lazy_static! {
   static ref GLOBAL : Global = Default::default();
 }
 
-// ---------- API ----------
+// ---------- Player and instance API ----------
+
+impl Instance {
+  #[throws(OE)]
+  pub fn new(gs: GameState) -> Instance {
+    Instance {
+      gs,
+      clients : Default::default(),
+      updates : Default::default(),
+      tokens_players : Default::default(),
+      tokens_clients : Default::default(),
+    }
+  }
+
+  #[throws(OE)]
+  pub fn lock<'g>(amu : &'g Arc<Mutex<Instance>>) -> InstanceGuard<'g> {
+    let ig = amu.lock()?;
+    InstanceGuard { ig, amu: amu.clone() }
+  }
+}
+
+impl Deref for InstanceGuard<'_> {
+  type Target = Instance;
+  fn deref(&self) -> &Instance { &self.ig }
+}
+impl DerefMut for InstanceGuard<'_> {
+  fn deref_mut(&mut self) -> &mut Instance { &mut self.ig }
+}
+
+impl InstanceGuard<'_> {
+  #[throws(OE)]
+  pub fn player_new(&mut self, newplayer: PlayerState) -> PlayerId {
+    let player = self.ig.gs.players.insert(newplayer);
+    self.ig.updates.insert(player, Default::default());
+    self.save_game_now()?;
+    player
+  }
+
+  #[throws(OE)]
+  pub fn player_access_register(&mut self, token: RawToken, player: PlayerId) {
+    let iad = InstanceAccessDetails { g : self.amu.clone(), ident : player };
+    self.token_register(token, iad);
+    self.save_access_now()?;
+  }
+
+  fn token_register<Id:AccessId>(
+    &mut self,
+    token: RawToken,
+    iad: InstanceAccessDetails<Id>
+  ) {
+    Id::tokens_registry(&mut *self.ig).tr.insert(token.clone());
+    Id::global_tokens().write().unwrap().insert(token, iad);
+  }
+
+  #[throws(OE)]
+  fn save_game_now(&mut self) { eprintln!("xxx would save!"); }
+  #[throws(OE)]
+  fn save_access_now(&mut self) { eprintln!("xxx would save!"); }
+}
+
+// ---------- Lookup and token API ----------
 
 impl AccessId for PlayerId {
   const ERROR : OnlineError = NoPlayer;
   fn global_tokens() -> &'static RwLock<TokenTable<Self>> { &GLOBAL.players }
+  fn tokens_registry(ig: &mut Instance) -> &mut TokenRegistry<Self> {
+    &mut ig.tokens_players
+  }
 }
 impl AccessId for ClientId {
   const ERROR : OnlineError = NoClient;
   fn global_tokens() -> &'static RwLock<TokenTable<Self>> { &GLOBAL.clients }
+  fn tokens_registry(ig: &mut Instance) -> &mut TokenRegistry<Self> {
+    &mut ig.tokens_clients
+  }
 }
 
 pub fn lookup_token<Id : AccessId>(s : &str)
@@ -95,15 +176,17 @@ impl<'r, Id> FromParam<'r> for InstanceAccess<'r, Id>
     InstanceAccess { raw_token : token, i : i.clone() }
   }
 }
-
-pub fn record_token<Id : AccessId>(iad : InstanceAccessDetails<Id>)
-                                   -> RawToken {
+  
+pub fn record_token<Id : AccessId>(
+  ig : &mut InstanceGuard,
+  iad : InstanceAccessDetails<Id>
+) -> RawToken {
   let mut rng = thread_rng();
   let token = RawToken (
     repeat_with(|| rng.sample(Alphanumeric))
       .take(64).collect()
   );
-  Id::global_tokens().write().unwrap().insert(token.clone(), iad);
+  ig.token_register(token.clone(), iad);
   token
 }
 
@@ -114,23 +197,16 @@ const XXX_PLAYERS_TOKENS : &[(&str, &str)] = &[
   ("ccg9kzoTh758QrVE1xMY7BQWB36dNJTx", "bob"),
 ];
 
+#[throws(OE)]
 pub fn xxx_global_setup() {
-  let gi = Instance {
-    gs : xxx_gamestate_init(),
-    clients : Default::default(),
-    updates : Default::default(),
-  };
+  let gs = xxx_gamestate_init();
+  let gi = Instance::new(gs)?;
   let amu = Arc::new(Mutex::new(gi));
-  let mut ig = amu.lock().unwrap();
+  let mut ig = Instance::lock(&amu)?;
   for (token, nick) in XXX_PLAYERS_TOKENS {
-    let np = PlayerState {
+    let player = ig.player_new(PlayerState {
       nick : nick.to_string(),
-    };
-    let player = ig.gs.players.insert(np);
-    let ia = InstanceAccessDetails { g : amu.clone(), ident : player };
-    GLOBAL.players.write().unwrap().insert(
-      RawToken(token.to_string()), ia
-    );
-    ig.updates.insert(player, Default::default());
+    })?;
+    ig.player_access_register(RawToken(token.to_string()), player)?;
   }
 }
index 717464c58e05f3d781a326632f9d0ba45267a0e7..472d02ae83ac9972d648ba2c187f185ea6d37a7c 100644 (file)
@@ -6,8 +6,8 @@ pub use std::fmt::Formatter;
 pub use std::fmt::{self,Display,Debug};
 pub use std::thread;
 pub use std::time::Duration;
-pub use std::sync::{Arc,Mutex,RwLock,Condvar};
-pub use std::collections::HashMap;
+pub use std::sync::{Arc,Mutex,MutexGuard,RwLock,Condvar};
+pub use std::collections::{HashMap,HashSet};
 pub use std::borrow::Borrow;
 pub use std::convert::{TryFrom,TryInto};
 pub use std::str;
@@ -18,6 +18,8 @@ pub use std::collections::VecDeque;
 pub use std::num::Wrapping;
 pub use std::cmp;
 pub use std::error::Error;
+pub use std::marker::PhantomData;
+pub use std::ops::{Deref,DerefMut};
   
 pub use thiserror::Error;
 pub use anyhow::{Context,anyhow};
index 5ae52ac4ce2b2deeaca027604b9048c5418233da..2253c2a512270ede7c9096e79e3df4dc18975fe1 100644 (file)
@@ -47,8 +47,7 @@ fn session(form : Json<SessionForm>) -> Result<Template,OE> {
   let iad = lookup_token(&form.ptoken)?;
   let player = iad.ident;
   let c = {
-    let mut ig = iad.g.lock()?;
-    let ig = &mut *ig;
+    let mut ig = Instance::lock(&iad.g)?;
     let cl = Client { player };
     let client = ig.clients.insert(cl);
 
@@ -56,7 +55,8 @@ fn session(form : Json<SessionForm>) -> Result<Template,OE> {
       g : iad.g.clone(),
       ident : client,
     };
-    let ctoken = record_token(ciad);
+    let ctoken = record_token(&mut ig, ciad);
+    let ig = &mut *ig;
 
     let mut uses = vec![];
     let mut alldefs = vec![];