From 1f0dbaa95f98ce51cc880b4aa5278ab8e4be9616 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Sun, 18 Oct 2020 14:14:17 +0100 Subject: [PATCH] wip new account etc. Signed-off-by: Ian Jackson --- src/accounts.rs | 31 ++++++++++++++++++++--- src/api.rs | 66 +++++++++++++++++++++++++++++------------------- src/commands.rs | 5 +++- src/error.rs | 4 +++ src/gamestate.rs | 6 ++++- src/global.rs | 66 +++++++++++++++++++++++++++--------------------- src/imports.rs | 1 + src/session.rs | 8 +++--- src/spec.rs | 20 ++++++++++----- src/sse.rs | 7 ++--- src/updates.rs | 6 +++-- 11 files changed, 145 insertions(+), 75 deletions(-) diff --git a/src/accounts.rs b/src/accounts.rs index 8f71b835..e588b82c 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -86,24 +86,47 @@ pub struct AccountRecord { #[derive(Copy,Clone,Debug,Ord,PartialOrd,Eq,PartialEq)] pub struct TokenRevelation { - latest: Timestamp, - earliest: Timestamp, + pub latest: Timestamp, + pub earliest: Timestamp, } static ACCOUNTS : RwLock>> = const_rwlock(None); +// xxx load, incl reveleation expiry +// xxx periodic token reveleation expiry + +pub fn save_accounts_now() -> Result<(), InternalError> { + panic!("xxx") +} + impl AccountRecord { - fn lookup(account: AccountName) + pub fn lookup(account: &AccountName) -> Option> { ACCOUNTS.read().map( |accounts| accounts?.get(account) ) } - fn lookup_mut(account: AccountName) + pub fn lookup_mut_caller_must_save(account: &AccountName) -> Option> { ACCOUNTS.write().map( |accounts| accounts?.get(account) ) } + pub fn with_entry_mut(account: &AccountName, f: F) + -> Result + where F: FnOnce(Option<&mut AccountRecord>) -> T + { + let entry = AccountRecord::lookup_mut_caller_must_save(account); + let output = f(*entry); + let ok = if entry.is_some() { save_accounts_now() } else { Ok(()) }; + match ok { + Ok(()) => Ok(output), + Err(e) => Err((e, output)) + } + } + + pub fn expire_tokens_revealed(&mut self) { + panic!("xxx") + } } diff --git a/src/api.rs b/src/api.rs index 8d8a5360..72edb05f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -15,12 +15,19 @@ struct ApiPiece { op : O, } +struct ApiPieceOpArgs<'a> { + gs: &'a mut GameState, + player: PlayerId, + pst: &'a PlayerState, + piece: PieceId, + p: &'a dyn Piece, + iplayers: &'a SecondarySlotMap, + lens: &'a dyn Lens /* used for LogEntry and PieceId but not Pos */ +} + trait ApiPieceOp : Debug { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, - lens: &dyn Lens /* used for LogEntry and PieceId but not Pos */) - -> PieceUpdateFromOp; + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp; #[throws(OnlineError)] fn check_held(&self, pc: &PieceState, player: PlayerId) { @@ -111,6 +118,8 @@ fn api_piece_op(form : Json>) let player = cl.player; let gs = &mut g.gs; let ipieces = &g.ipieces; + let iplayers = &g.iplayers; + let pst = &iplayers.byid(player)?.pst; let _ = gs.players.byid(player)?; let lens = TransparentLens { }; let piece = lens.decode_visible_pieceid(form.piece, player); @@ -127,7 +136,12 @@ fn api_piece_op(form : Json>) if u_gen > q_gen { throw!(PieceOpError::Conflict) } form.op.check_held(pc,player)?; - let (wrc, update, logents) = form.op.op(gs,player,piece,p.as_ref(),&lens)?; + let (wrc, update, logents) = + form.op.op(ApiPieceOpArgs { + gs, player, pst, piece, iplayers, + p: p.as_ref(), + lens: &lens, + })?; Ok::<_,ApiPieceOpError>((wrc, update, logents)) })() { Err(ReportViaUpdate(poe)) => { @@ -171,8 +185,8 @@ fn api_grab(form : Json>) } impl ApiPieceOp for ApiPieceGrab { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; let pl = gs.players.byid(player)?; let pc = gs.pieces.byid_mut(piece)?; @@ -183,7 +197,7 @@ impl ApiPieceOp for ApiPieceGrab { let logent = LogEntry { html : Html(format!("{} grasped {}", - &htmlescape::encode_minimal(&pl.nick), + &htmlescape::encode_minimal(&pst.nick), p.describe_pri(&lens.log_pri(piece, pc)).0)), }; @@ -207,23 +221,23 @@ impl ApiPieceOp for ApiPieceWrest { fn check_held(&self, _pc: &PieceState, _player: PlayerId) { } #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens,iplayers, .. } = a; let pl = gs.players.byid(player)?; let pc = gs.pieces.byid_mut(piece)?; let pcs = p.describe_pri(&lens.log_pri(piece, pc)).0; let was = pc.held; pc.held = Some(player); - let was = was.and_then(|p| gs.players.get(p)); + let was = was.and_then(|p| iplayers.get(p)); let update = PieceUpdateOp::Modify(()); - let pls = &htmlescape::encode_minimal(&pl.nick); + let pls = &htmlescape::encode_minimal(&pst.nick); let logent = LogEntry { html : Html(match was { Some(was) => format!("{} wrested {} from {}", pls, pcs, - &htmlescape::encode_minimal(&was.nick)), + &htmlescape::encode_minimal(&was.pst.nick)), None => format!("{} wrested {}", pls, pcs), })}; @@ -243,8 +257,8 @@ fn api_ungrab(form : Json>) } impl ApiPieceOp for ApiPieceUngrab { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; let pl = gs.players.byid(player).unwrap(); let pc = gs.pieces.byid_mut(piece).unwrap(); @@ -255,7 +269,7 @@ impl ApiPieceOp for ApiPieceUngrab { let logent = LogEntry { html : Html(format!("{} released {}", - &htmlescape::encode_minimal(&pl.nick), + &htmlescape::encode_minimal(&pst.nick), p.describe_pri(&lens.log_pri(piece, pc)).0)), }; @@ -276,8 +290,8 @@ fn api_raise(form : Json>) } impl ApiPieceOp for ApiPieceRaise { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId, - _p: &dyn Piece, _: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; let pc = gs.pieces.byid_mut(piece).unwrap(); pc.zlevel = ZLevel { z : self.z.clone(), zg : gs.gen }; let update = PieceUpdateOp::SetZLevel(()); @@ -295,8 +309,8 @@ fn api_move(form : Json>) -> impl response::Responder<'st } impl ApiPieceOp for ApiPieceMove { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId, - _p: &dyn Piece, _lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; let pc = gs.pieces.byid_mut(piece).unwrap(); let (pos, clamped) = self.0.clamped(gs.table_size); let logents = vec![]; @@ -322,15 +336,15 @@ fn api_pin(form : Json>) -> impl response::Responder<'stat } impl ApiPieceOp for ApiPiecePin { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; let pc = gs.pieces.byid_mut(piece).unwrap(); let pl = gs.players.byid(player).unwrap(); pc.pinned = self.0; let update = PieceUpdateOp::Modify(()); let logents = vec![ LogEntry { html: Html(format!( "{} {} {}", - &htmlescape::encode_minimal(&pl.nick), + &htmlescape::encode_minimal(&pst.nick), if pc.pinned { "pinned" } else { "unpinned" }, p.describe_pri(&lens.log_pri(piece, pc)).0 ))}]; @@ -350,8 +364,8 @@ fn api_uo(form : Json>) -> impl response::Responder<'static } impl ApiPieceOp for ApiPieceUo { #[throws(ApiPieceOpError)] - fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId, - p: &dyn Piece, lens: &dyn Lens) -> PieceUpdateFromOp { + fn op(&self, a: ApiPieceOpArgs) -> PieceUpdateFromOp { + let ApiPieceOpArgs { gs,player,pst,piece,p,lens, .. } = a; '_normal_global_ops__not_loop: loop { let pc = gs.pieces.byid_mut(piece)?; let pl = gs.players.byid(player)?; @@ -365,7 +379,7 @@ impl ApiPieceOp for ApiPieceUo { PieceUpdateOp::Modify(()), vec![ LogEntry { html: Html(format!( "{} flipped {}", - &htmlescape::encode_minimal(&pl.nick), + &htmlescape::encode_minimal(&pst.nick), p.describe_pri(&lens.log_pri(piece, pc)).0 )) }]) }, diff --git a/src/commands.rs b/src/commands.rs index fff1f6c2..f32a174b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -100,7 +100,7 @@ pub enum MgmtGameResponse { PlayerAccessToken(Option), } -#[derive(Debug,Serialize,Deserialize)] +#[derive(Debug,Clone,Serialize,Deserialize)] pub struct AccessTokenReport { pub url: String, } @@ -151,6 +151,7 @@ pub enum MgmtError { ZCoordinateOverflow(#[from] zcoord::Overflow), BadGlob { pat: String, msg: String }, BadSpec(#[from] SpecError), + TokenDeliveryFailed(#[from] TokenDeliveryError), } impl Display for MgmtError { #[throws(fmt::Error)] @@ -158,6 +159,8 @@ impl Display for MgmtError { use MgmtError::*; match self { ServerFailure(s) => write!(f, "ServerFailure: {}", &s)?, + TokenDeliveryFailed(tde) => + write!(f, "access token delivery failed: {}", &tde)?, _ => ::fmt(self,f)?, } } diff --git a/src/error.rs b/src/error.rs index 1312d124..f50fd63f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -47,6 +47,10 @@ pub enum InternalError { Anyhow(#[from] anyhow::Error), } +#[derive(Error,Debug)] +pub enum TokenDeliveryError { +} + impl From for SpecError { fn from(ie: InternalError) -> SpecError { SpecError::InternalError(format!("{:?}",ie)) diff --git a/src/gamestate.rs b/src/gamestate.rs index 5d800998..9c3c6682 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -19,7 +19,7 @@ pub struct Generation (pub u64); visible_slotmap_key!{ VisiblePieceId('.') } -#[derive(Clone,Serialize,Deserialize,Eq,Ord,PartialEq,PartialOrd)] +#[derive(Clone,Serialize,Deserialize,Hash,Eq,Ord,PartialEq,PartialOrd)] #[serde(transparent)] pub struct Html (pub String); @@ -198,7 +198,11 @@ impl ClampTable for Pos { } impl Html { + // todo convert to display_as but I need to write display_as::typed::Is pub fn lit(s: &str) -> Self { Html(s.to_owned()) } + pub fn from_txt(s: &str) -> Self { + Html(htmlescape::encode_minimal(&s)) + } } impl Debug for Html { diff --git a/src/global.rs b/src/global.rs index ef0fea8a..77ff8349 100644 --- a/src/global.rs +++ b/src/global.rs @@ -45,7 +45,7 @@ pub struct PlayerRecord { pub pst: PlayerState, } -#[derive(Debug,Serialize,Deserialize)] +#[derive(Debug,Clone,Serialize,Deserialize)] pub struct PlayerState { pub account: AccountName, pub nick: String, @@ -193,7 +193,7 @@ pub struct InstanceContainer { #[derive(Debug,Default,Serialize,Deserialize)] struct InstanceSaveAccesses { - pieces: PiecesLoadedRef, + ipieces: PiecesLoadedRef, tokens_players: Vec<(RawTokenStr, PlayerId)>, aplayers: SecondarySlotMap, } @@ -380,7 +380,7 @@ impl InstanceGuard<'_> { (||{ self.save_game_now()?; self.save_access_now()?; - Ok(()) + Ok::<_,InternalError>(()) })().map_err(|e|{ self.c.g.iplayers.remove(player); self.c.g.gs.players.remove(player); @@ -397,14 +397,15 @@ impl InstanceGuard<'_> { // #[throws(ServerFailure)] // https://github.com/withoutboats/fehler/issues/62 pub fn player_remove(&mut self, oldplayer: PlayerId) - -> Result,InternalError> { + -> Result<(Option, Option), + InternalError> { // We have to filter this player out of everything // Then save // Then send updates // We make a copy so if the save fails, we can put everything back let mut players = self.c.g.gs.players.clone(); - let old_data = players.remove(oldplayer); + let old_account = players.remove(oldplayer); // New state let mut gs = GameState { @@ -457,7 +458,7 @@ impl InstanceGuard<'_> { // point of no return mem::drop(undo); - (||{ + let old_pst = (||{ for &piece in &updated_pieces { (||Some({ self.c.g.gs.pieces.get_mut(piece)?.gen = self.c.g.gs.gen; @@ -478,8 +479,9 @@ impl InstanceGuard<'_> { if remove { clients_to_remove.insert(k); } !remove }); - if let Some(PlayerRecord { u: mut updates, .. }) - = self.iplayers.remove(oldplayer) { + let pst = if let Some(PlayerRecord { u: mut updates, pst }) + = self.iplayers.remove(oldplayer) + { updates.push(PreparedUpdate { gen: self.c.g.gs.gen, when: Instant::now(), @@ -488,7 +490,10 @@ impl InstanceGuard<'_> { ErrorSignaledViaUpdate::PlayerRemoved )], }); - } + Some(pst) + } else { + None + }; self.tokens_deregister_for_id(|id:PlayerId| id==oldplayer); self.tokens_deregister_for_id(|id| clients_to_remove.contains(&id)); self.save_access_now().unwrap_or_else( @@ -496,9 +501,10 @@ impl InstanceGuard<'_> { "trouble garbage collecting accesses for deleted player: {:?}", &e) ); + pst })(); // <- No ?, ensures that IEFE is infallible (barring panics) - Ok(old_data) + Ok((old_account, old_pst)) } #[throws(MgmtError)] @@ -506,8 +512,7 @@ impl InstanceGuard<'_> { player: PlayerId, token: RawToken, _safe: Authorised ) { - // xxx call this function when access changes - + // xxx get rid of this or something ? self.tokens_deregister_for_id(|id:PlayerId| id==player); let iad = InstanceAccessDetails { gref : self.gref.clone(), @@ -520,28 +525,31 @@ impl InstanceGuard<'_> { #[throws(MgmtError)] pub fn player_access_reset(&mut self, player: PlayerId) -> Option { - let pst = self.c.g.players.get(player) + // xxx call this function when access changes + + let pst = self.c.g.iplayers.get(player) .ok_or(MgmtError::PlayerNotFound)? .pst; self.save_access_now()?; - let access = { - let acct = AccountRecord::lookup_mut(&pst.account)? - .ok_or(MgmtError::AccountNotFound)?; + let access = AccountRecord::with_entry_mut(&pst.account, |acct|{ + let acct = acct.ok_or(MgmtError::AccountNotFound)?; let access = acct.access; let desc = access.describe_html(); let now = Timestamp::now(); - access.entry(desc) + acct.tokens_revealed.entry(desc) .or_insert(TokenRevelation { latest: now, earliest: now, }) .latest = now; - access.clone() - }; + acct.expire_tokens_revealed(); + Ok::<_,MgmtError>(access.clone()) + }).map_err(|(e,_)|e)??; let token = access .override_token() + .cloned() .unwrap_or_else(||{ RawToken::new_random() // xxx disconnect everyone else @@ -554,10 +562,10 @@ impl InstanceGuard<'_> { self.token_register(token.clone(), iad); let report = AccessTokenReport { - url: format!("http://localhost:8000/{}", token.url), // xxx + url: format!("http://localhost:8000/{}", token.0), // xxx }; let report = access - .server_deliver(&pst, &report); + .server_deliver(&pst, &report)?; report.cloned() } @@ -712,7 +720,7 @@ impl InstanceGuard<'_> { #[throws(InternalError)] fn save_access_now(&mut self) { self.save_something("a-", |s,w| { - let pieces = &s.c.g.pieces; + let ipieces = &s.c.g.ipieces; let tokens_players : Vec<(&str, PlayerId)> = { let global_players = GLOBAL.players.read().unwrap(); s.c.g.tokens_players.tr @@ -725,9 +733,9 @@ impl InstanceGuard<'_> { }; let aplayers = s.c.g.iplayers.iter().map( |(player, PlayerRecord { pst, .. })| - (player, pst) + (player, pst.clone()) ).collect(); - let isa = InstanceSaveAccesses { pieces, tokens_players, aplayers }; + let isa = InstanceSaveAccesses { ipieces, tokens_players, aplayers }; rmp_serde::encode::write_named(w, &isa) })?; self.c.access_dirty = false; @@ -746,7 +754,7 @@ impl InstanceGuard<'_> { } #[throws(StartupError)] - fn load(name: InstanceName) -> InstanceRef { + fn load_game(name: InstanceName) -> InstanceRef { { let mut st = GLOBAL.save_area_lock.lock().unwrap(); let st = &mut *st; @@ -791,15 +799,15 @@ impl InstanceGuard<'_> { let iplayers = { let a = aplayers; a.drain() - }.map(|pst| { + }.map(|(player, pst)| { let u = pu_bc.new(); - PlayerRecord { u, pst } + (player, PlayerRecord { u, pst }) }).collect(); for mut p in gs.pieces.values_mut() { p.lastclient = Default::default(); if let Some(held) = p.held { - if !gs.players.has_key(held) { p.held = None } + if !gs.players.contains_key(held) { p.held = None } } } @@ -867,7 +875,7 @@ pub fn load_games() { ); }, GameFile { access_leaf, name } => { - InstanceGuard::load(name)?; + InstanceGuard::load_game(name)?; a_leaves.insert(access_leaf, Used); }, } diff --git a/src/imports.rs b/src/imports.rs index 3c8a9213..b8821566 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -12,6 +12,7 @@ pub use std::thread::{self,sleep}; pub use std::time::Duration; pub use std::sync::{Arc,Mutex,MutexGuard,RwLock,RwLockReadGuard,Condvar}; pub use std::collections::{HashMap,hash_map,HashSet}; +pub use std::hash::Hash; pub use std::borrow::Borrow; pub use std::convert::{TryFrom,TryInto}; pub use std::str; diff --git a/src/session.rs b/src/session.rs index 915692f1..188f210b 100644 --- a/src/session.rs +++ b/src/session.rs @@ -94,7 +94,8 @@ fn session(form : Json) -> Result { } let pl = ig.gs.players.byid_mut(player)?; - let tz = &ig.updates.byid(player)?.tz; + let ipl = ig.iplayers.byid(player)?; + let tz = &ipl.pst.tz; let mut pieces : Vec<_> = ig.gs.pieces.iter().collect(); pieces.sort_by_key(|(_,pr)| &pr.zlevel); @@ -104,7 +105,7 @@ fn session(form : Json) -> Result { id : make_pieceid_visible(gpid), face : pr.face, }; - let p = if let Some(p) = ig.pieces.get(gpid) { p } + let p = if let Some(p) = ig.ipieces.get(gpid) { p } else { continue /* was deleted */ }; let defs = p.make_defs(&pri)?; alldefs.push((pri.id, defs)); @@ -137,10 +138,11 @@ fn session(form : Json) -> Result { player, defs : alldefs, uses, - nick : pl.nick.clone(), + nick : ipl.pst.nick.clone(), load : serde_json::to_string(&DataLoad { players : load_players, }).map_err(|e| InternalError::JSONEncode(e))?, + // xxx show account accesses }; trace!("SessionRenderContext {:?}", &src); (src, client) diff --git a/src/spec.rs b/src/spec.rs index 568b53de..ab520b59 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -13,6 +13,7 @@ use std::collections::hash_set::HashSet; use thiserror::Error; use crate::error::display_as_debug; use crate::accounts::AccountName; +use std::hash::Hash; pub use implementation::PlayerAccessSpec; @@ -65,13 +66,14 @@ pub struct TableSpec { pub type Acl = Vec>; #[derive(Debug,Clone,Serialize,Deserialize)] -pub struct AclEntry { +pub struct AclEntry { pub account_glob: String, pub allow: HashSet, pub deny: HashSet, } #[derive(Debug,Clone,Copy,Serialize,Deserialize)] +#[derive(Hash,Eq,PartialEq,Ord,PartialOrd)] enum TablePermission { AddPlayer, ChangePieces, @@ -221,6 +223,8 @@ pub mod implementation { use crate::imports::*; type Insn = crate::commands::MgmtGameInstruction; + type TDE = TokenDeliveryError; + pub fn raw_token_debug_as_str(s: &str, f: &mut fmt::Formatter) -> fmt::Result { let len = min(5, s.len() / 2); @@ -243,13 +247,17 @@ pub mod implementation { None } fn server_deliver(&self, pst: &PlayerState, token: &AccessTokenReport) - -> Result, AE> { + -> Result, TDE> { Ok(None) } fn client_deliver(&self, pst: &PlayerState, token: &AccessTokenReport) - -> Result<(),AE> { + -> Result<(), TDE> { panic!() } + fn describe_html(&self) -> Html { + let inner = Html::from_txt(&format!("{:?}", self)); + Html(format!("{}", inner.0)) + } } #[typetag::serde] @@ -259,7 +267,7 @@ pub mod implementation { #[typetag::serde] impl PlayerAccessSpec for FixedToken { fn override_token(&self) -> Option<&RawToken> { - Some(self.token) + Some(&self.token) } fn client_mgi(&self, player: PlayerId) -> Option { Some(Insn::SetFixedPlayerAccess { @@ -274,12 +282,12 @@ pub mod implementation { fn client_mgi(&self, player: PlayerId) -> Option { Some(Insn::ReportPlayerAccesses(player)) } - #[throws(AE)] + #[throws(TDE)] fn server_deliver(&self, ps: &PlayerState, token: &AccessTokenReport) -> Option<&AccessTokenReport> { Some(token) } - #[throws(AE)] + #[throws(TDE)] fn client_deliver(&self, ps: &PlayerState, token: &AccessTokenReport) { println!("access account={} nick={:?} url:\n{}", &ps.account, &ps.nick, token.url); diff --git a/src/sse.rs b/src/sse.rs index 1db533ef..e99e7195 100644 --- a/src/sse.rs +++ b/src/sse.rs @@ -86,8 +86,9 @@ impl Read for UpdateReader { self.player, self.client, ig.gs.gen, self.to_send)?; } - let pu = &mut ig.updates.get_mut(self.player) + let iplayer = &mut ig.iplayers.get_mut(self.player) .ok_or_else(|| self.trouble("player gonee",()))?; + let pu = &mut iplayer.u; loop { if let Some(ref mut overflow) = self.overflow { @@ -124,7 +125,7 @@ impl Read for UpdateReader { } self.overflow = { let mut overflow = Vec::with_capacity(next_len); - self.wn.write_next(&mut overflow, &pu.tz, &next) + self.wn.write_next(&mut overflow, &iplayer.pst.tz, &next) .map_err(|e| self.wn.trouble("overflow.write_next",&e))?; debug!("overflow {} {}, len={}", &self.wn.player, &self.wn.client, &overflow.len()); @@ -133,7 +134,7 @@ impl Read for UpdateReader { continue; } - self.wn.write_next(&mut buf, &pu.tz, &next) + self.wn.write_next(&mut buf, &iplayer.pst.tz, &next) .map_err(|e| self.wn.trouble("UpdateReader.write_next",&e))?; let before = next.when - UPDATE_EXPIRE; diff --git a/src/updates.rs b/src/updates.rs index da095aaf..c6ee500b 100644 --- a/src/updates.rs +++ b/src/updates.rs @@ -346,7 +346,7 @@ impl<'r> PrepareUpdatesBuffer<'r> { let (update, piece) = match ( gs.pieces.byid_mut(piece), - self.g.pieces.get(piece), + self.g.ipieces.get(piece), ) { (Ok(pc), Some(p)) => { gs.max_z.update_max(&pc.zlevel.z); @@ -435,7 +435,9 @@ impl<'r> Drop for PrepareUpdatesBuffer<'r> { let update = Arc::new(update); trace!("PrepareUpdatesBuffer update {:?}", &update); - for (_tplayer, tplupdates) in &mut self.g.updates { + for (_tplayer, PlayerRecord { u: tplupdates, .. }) + in &mut self.g.iplayers + { tplupdates.push(update.clone()); } } -- 2.30.2