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)]
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
// xxx delete instances at some point!
}
+#[derive(Debug,Default)]
+pub struct TokenRegistry<Id: AccessId> {
+ tr : HashSet<RawToken>,
+ id : PhantomData<Id>,
+}
+
// ---------- API ----------
#[derive(Clone,Debug)]
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;
}
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)
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
}
("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)?;
}
}
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;
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};