From: Ian Jackson Date: Sun, 28 Jun 2020 22:30:31 +0000 (+0100) Subject: wip reorg idents etc. X-Git-Tag: otter-0.2.0~1501 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=4e16f7b398ad0cb9ae49f7289342933a4fd7f466;p=otter.git wip reorg idents etc. --- diff --git a/src/bin/server.rs b/src/bin/server.rs index 83b322b3..c085931f 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -45,7 +45,7 @@ struct LoadingRenderContext<'r> { } #[get("/")] -fn loading(token : InstanceAccess) -> Result { +fn loading(token : InstanceAccess) -> Result { let c = LoadingRenderContext { token : token.raw_token }; Ok(Template::render("loading",&c)) } @@ -66,12 +66,13 @@ struct SessionForm { fn session(form : Json) -> Result { // 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) -> Result { 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) -> 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) -> 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) -> 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//")] +#[get("/_/updates/")] #[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) + -> 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); diff --git a/src/global.rs b/src/global.rs index 357eb2ec..b8180d3f 100644 --- a/src/global.rs +++ b/src/global.rs @@ -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 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>, + pub clients : DenseSlotMap, } #[derive(Clone)] -pub struct InstanceAccessDetails { - pub i : Arc>, - pub player : PlayerId, +pub struct InstanceAccessDetails { + pub g : Arc>, + 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, } +pub type TokenTable = HashMap>; + #[derive(Default)] struct Global { // lock hierarchy: this is the innermost lock - tokens : RwLock>, + players : RwLock>, + clients : RwLock>, // 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 { - GLOBAL.tokens.read().unwrap().get(s).cloned() +pub trait AccessId : Copy + Clone + 'static { + fn global_tokens() -> &'static RwLock>; +} + +impl AccessId for PlayerId { + fn global_tokens() -> &'static RwLock> { &GLOBAL.players } +} +impl AccessId for ClientId { + fn global_tokens() -> &'static RwLock> { &GLOBAL.clients } +} + +pub fn lookup_token(s : &str) + -> Option> { + 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 ); }