chiark / gitweb /
wip reorg idents etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 28 Jun 2020 22:30:31 +0000 (23:30 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 28 Jun 2020 22:30:31 +0000 (23:30 +0100)
src/bin/server.rs
src/global.rs

index 83b322b3abfcc11d0389e2abd7985f8cc8486964..c085931fec33a09584ac2709fd8a9e2ff0ac9a4f 100644 (file)
@@ -45,7 +45,7 @@ struct LoadingRenderContext<'r> {
 }
 
 #[get("/<token>")]
-fn loading(token : InstanceAccess) -> Result<Template,RE> {
+fn loading(token : InstanceAccess<PlayerId>) -> Result<Template,RE> {
   let c = LoadingRenderContext { token : token.raw_token };
   Ok(Template::render("loading",&c))
 }
@@ -66,12 +66,13 @@ struct SessionForm {
 fn session(form : Json<SessionForm>) -> Result<Template,RE> {
   // make session in this game, log a message to other players
   let iad = lookup_token(&form.token).ok_or_else(|| anyhow!("unknown token"))?;
+  let player = iad.ident;
   let c = {
-    let mut ig = iad.i.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
-    let _player = ig.gs.players.get_mut(iad.player)
+    let mut ig = iad.g.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
+    let pl = ig.gs.players.get_mut(player)
       .ok_or_else(|| anyhow!("player deleted"))?;
-    let client = Client { };
-    let clientid = ig.clients[iad.player].insert(client);
+    let client = Client { player };
+    let clientid = ig.clients.insert(client);
 
     let mut uses = vec![];
     let mut defs = vec![];
@@ -104,7 +105,7 @@ fn session(form : Json<SessionForm>) -> Result<Template,RE> {
 
     SessionRenderContext {
       clientid,
-      player : iad.player,
+      player,
       defs,
       uses,
     }
@@ -123,7 +124,6 @@ enum OpError {
 #[derive(Debug,Serialize,Deserialize)]
 struct ApiGrab {
   t : String,
-  c : ClientId,
   p : VisiblePieceId,
   g : Counter,
   s : ClientSequence,
@@ -132,9 +132,12 @@ struct ApiGrab {
 #[throws(RE)]
 fn api_grab(form : Json<ApiGrab>) -> impl response::Responder<'static> {
   let iad = lookup_token(&form.t).ok_or_else(||anyhow!("unknown token"))?;
-  let mut g = iad.i.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
+  let client = iad.ident;
+  let mut g = iad.g.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
   let g = &mut *g;
-  let client = form.c;
+  let cl = &g.clients.get(client).ok_or_else(||anyhow!("unknown client"))?;
+  // ^ can only fail if we raced
+  let player = cl.player;
   let r : Result<(),OpError> = (||{
     let piece = decode_visible_pieceid(form.p);
     let gs = &mut g.gs;
@@ -145,7 +148,7 @@ fn api_grab(form : Json<ApiGrab>) -> impl response::Responder<'static> {
       else { p.gen_before_lastclient };
     if u_gen > form.g { Err(OpError::Conflict)? }
     if p.held != None { Err(OpError::PieceHeld)? };
-    p.held = Some(iad.player);
+    p.held = Some(player);
     gs.gen += 1;
     let gen = gs.gen;
     if client != p.lastclient {
@@ -157,17 +160,15 @@ fn api_grab(form : Json<ApiGrab>) -> impl response::Responder<'static> {
       u : UpdatePayload::PieceUpdate(piece, p.mk_update()),
     };
     p.gen_lastclient = gen;
-    for (tplayer, tpl) in &g.gs.players {
-      for (tclient, tcl) in &mut g.clients[tplayer] {
-        if tclient == client {
-          tcl.transmit_update(&Update {
-            gen,
-            u : UpdatePayload::ClientSequence(form.s),
-          });
-        } else {
-          tcl.transmit_update(&update);
-        }          
-      }
+    for (tclient, tcl) in &mut g.clients {
+      if tclient == client {
+        tcl.transmit_update(&Update {
+          gen,
+          u : UpdatePayload::ClientSequence(form.s),
+        });
+      } else {
+        tcl.transmit_update(&update);
+      }          
     }
     Ok(())
   })();
@@ -229,18 +230,17 @@ struct APIForm {
 }
  */
 
-#[get("/_/updates/<token>/<clientid>")]
+#[get("/_/updates/<token>")]
 #[throws(RE)]
-fn updates(token : &RawStr, clientid : String) -> impl response::Responder<'static> {
-  let iad = lookup_token(token.as_str()).ok_or_else(|| anyhow!("unknown token"))?;
-  let clientid = TryFrom::try_from(clientid.as_ref())?;
+fn updates(token : InstanceAccess<ClientId>)
+           -> impl response::Responder<'static> {
+  let iad = token.i;
+  let client = iad.ident;
   let _ = {
-    let mut ig = iad.i.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
+    let mut ig = iad.g.lock().map_err(|e| anyhow!("lock poison {:?}",&e))?;
     let g = &mut ig.gs;
-    let _player = g.players.get_mut(iad.player)
-      .ok_or_else(|| anyhow!("user deleted"))?;
-    let _client = ig.clients[iad.player].get_mut(clientid)
-      .ok_or_else(|| anyhow!("client deleted"))?;
+    let cl = ig.clients.get(client).ok_or_else(|| anyhow!("no client"))?;
+    let player = cl.player;
   };
   let tc = TestCounterInner { next : 0 };
   let tc = BufReader::new(tc);
index 357eb2ec7508f3725f66a5a33a796f2b8dfcad5e..b8180d3f9dad886223fff5e985e192166c4cf85a 100644 (file)
@@ -8,12 +8,13 @@ visible_slotmap_key!{ ClientId('C') }
 visible_slotmap_key!{ PlayerId('#') }
 
 #[derive(Clone,Debug,Eq,PartialEq,Ord,PartialOrd,Hash)]
-struct RawToken (String);
+pub struct RawToken (String);
 impl Borrow<str> for RawToken {
   fn borrow(&self) -> &str { &self.0 }
 }
 
 pub struct Client {
+  pub player : PlayerId,
 }
 
 impl Client {
@@ -23,27 +24,29 @@ impl Client {
 }
 
 pub struct Instance {
-  /* game state goes here */
   pub gs : GameState,
-  pub clients : SecondarySlotMap<PlayerId,DenseSlotMap<ClientId,Client>>,
+  pub clients : DenseSlotMap<ClientId,Client>,
 }
 
 #[derive(Clone)]
-pub struct InstanceAccessDetails {
-  pub i : Arc<Mutex<Instance>>,
-  pub player : PlayerId,
+pub struct InstanceAccessDetails<Id> {
+  pub g : Arc<Mutex<Instance>>,
+  pub ident : Id,
 }
 
 #[derive(Clone)]
-pub struct InstanceAccess<'i> {
+pub struct InstanceAccess<'i, Id> {
   pub raw_token : &'i str,
-  pub i : InstanceAccessDetails,
+  pub i : InstanceAccessDetails<Id>,
 }
 
+pub type TokenTable<Id> = HashMap<RawToken, InstanceAccessDetails<Id>>;
+
 #[derive(Default)]
 struct Global {
   // lock hierarchy: this is the innermost lock
-  tokens : RwLock<HashMap<RawToken, InstanceAccessDetails>>,
+  players : RwLock<TokenTable<PlayerId>>,
+  clients : RwLock<TokenTable<ClientId>>,
   // xxx delete instances at some point!
 }
 
@@ -51,8 +54,20 @@ lazy_static! {
   static ref GLOBAL : Global = Default::default();
 }
 
-pub fn lookup_token(s : &str) -> Option<InstanceAccessDetails> {
-  GLOBAL.tokens.read().unwrap().get(s).cloned()
+pub trait AccessId : Copy + Clone + 'static {
+  fn global_tokens() -> &'static RwLock<TokenTable<Self>>;
+}
+
+impl AccessId for PlayerId {
+  fn global_tokens() -> &'static RwLock<TokenTable<Self>> { &GLOBAL.players }
+}
+impl AccessId for ClientId {
+  fn global_tokens() -> &'static RwLock<TokenTable<Self>> { &GLOBAL.clients }
+}
+
+pub fn lookup_token<Id : AccessId>(s : &str)
+      -> Option<InstanceAccessDetails<Id>> {
+  Id::global_tokens().read().unwrap().get(s).cloned()
 }
 
 const XXX_PLAYERS_TOKENS : &[(&str, &str)] = &[
@@ -60,11 +75,13 @@ const XXX_PLAYERS_TOKENS : &[(&str, &str)] = &[
   ("ccg9kzoTh758QrVE1xMY7BQWB36dNJTx", "bob"),
 ];
 
-impl<'r> FromParam<'r> for InstanceAccess<'r> {
+impl<'r, Id> FromParam<'r> for InstanceAccess<'r, Id>
+  where Id : AccessId
+{
   type Error = E;
   #[throws(E)]
   fn from_param(param: &'r RawStr) -> Self {
-    let g = GLOBAL.tokens.read().unwrap();
+    let g = Id::global_tokens().read().unwrap();
     let token = param.as_str();
     let i = g.get(token).ok_or_else(|| anyhow!("unknown token"))?;
     InstanceAccess { raw_token : token, i : i.clone() }
@@ -72,20 +89,19 @@ impl<'r> FromParam<'r> for InstanceAccess<'r> {
 }
 
 pub fn xxx_global_setup() {
-  let i = Instance {
+  let gi = Instance {
     gs : xxx_gamestate_init(),
     clients : Default::default(),
   };
-  let i = Arc::new(Mutex::new(i));
-  let mut ig = i.lock().unwrap();
+  let g = Arc::new(Mutex::new(gi));
+  let mut ig = g.lock().unwrap();
   for (token, nick) in XXX_PLAYERS_TOKENS {
-    let nu = Player {
+    let np = Player {
       nick : nick.to_string(),
     };
-    let player = ig.gs.players.insert(nu);
-    ig.clients.insert(player, Default::default());
-    let ia = InstanceAccessDetails { i : i.clone(), player };
-    GLOBAL.tokens.write().unwrap().insert(
+    let player = ig.gs.players.insert(np);
+    let ia = InstanceAccessDetails { g : g.clone(), ident : player };
+    GLOBAL.players.write().unwrap().insert(
       RawToken(token.to_string()), ia
     );
   }