fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, player: PlayerId)
-> PieceId;
}
-struct TransparentLens { }
+pub struct TransparentLens {
+ // when lenses become nontrivial, make this nonconstructable
+ // to find all the places where a TransparentLens was bodged
+}
impl Lens for TransparentLens {
fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId {
let kd : slotmap::KeyData = piece.into();
eprintln!("API {:?} => {:?}", &form, &err);
},
Ok((update, logents)) => {
- let mut buf = PrepareUpdatesBuffer::new(g, client, form.cseq,
- 1 + logents.len());
+ let mut buf = PrepareUpdatesBuffer::new(g, Some((client, form.cseq)),
+ Some(1 + logents.len()));
buf.piece_update(piece, update, &lens)?;
buf.log_updates(logents)?;
#[throws(CSE)]
fn decode_and_process(cs: &mut CommandStream, s: &str) {
let resp = self::decode_process_inner(cs, s)
- .unwrap_or_else(|e| MgmtResponse::Error(format!("{}", e)));
+ .unwrap_or_else(|e| MgmtResponse::Error(
+ MgmtError::ParseFailed(format!("{}", e))));
serde_lexpr::to_writer(&mut cs.write, &resp)?;
}
Fine { }
},
- CreateGame(name) => {
+ CreateGame(name, subcommands) => {
let gs = GameState {
pieces : Default::default(),
players : Default::default(),
scoped_name : name,
};
- cs.amu = Some(Instance::new(name, gs)?);
+ let ami = Instance::new(name, gs)?;
+ let g = ami.lock();
+
+ execute_for_game(cs, &ami, subcommands, MgmtGameUpdateMode::Bulk)
+ .map_err(|e|{
+ Instance::destroy(ami);
+ e
+ })?;
Fine { }
},
+
+
/*
AddPiece(game, { pos,count,name,info }) => {
let game = cs.lookup_game(&game)?;
}
}
+struct UpdateHandlerBulk {
+ pieces : SecondarySlotMap<PieceId, PieceUpdateOp<()>>,
+}
+
+enum UpdateHandler {
+ Bulk(UpdateHandlerBulk),
+ Online,
+}
+
+impl UpdateHandler {
+ #[throws(SVGProcessingError)]
+ fn accumulate(&mut self, g: &mut Instance,
+ upieces: Vec<(PieceId,PieceUpdateOp<()>)>,
+ ulogs: Vec<LogEntry>) {
+ use UpdateHandler::*;
+ match self {
+ Bulk(bulk) => {
+ for (upiece, uuop) in upieces {
+ use PieceUpdateOp::*;
+ let ne = match (bulk.pieces.get(upiece), uuop) {
+ ( None , e ) => e,
+ ( Some( Insert(()) ) , Some( Delete(()) ) ) => None,
+ ( Some( Insert(()) ) , _ ) => Some( Insert(()) ),
+ ( Some( Delete(()) ) , _ ) => Some( Modify(()) ),
+ ( _ , _ ) => Some( Modify(()) ),
+ };
+ match ne {
+ Some(ne) => bulk.pieces[upiece] = ne,
+ None => bulk.pieces.remove(upiece),
+ };
+ }
+ let _logs = ulogs;
+ },
+ Online => {
+ let estimate = upieces.len() + ulogs.len();
+ let buf = PrepareUpdatesBuffer::new(g, None, Some(estimate));
+ for (upiece, uuop) in upieces {
+ let lens = TransparentLens { };
+ buf.piece_update(upiece, uuop, &lens)?;
+ }
+ buf.log_updates(ulogs)?;
+ },
+ }
+ }
+
+ #[throws(SVGProcessingError)]
+ fn complete(&mut self, g: &mut Instance) {
+ use UpdateHandler::*;
+ match self {
+ Bulk(bulk) => {
+ let buf = PrepareUpdatesBuffer::new(g, None, None);
+ for (upiece, uuop) in self.pieces {
+ let lens = TransparentLens { };
+ buf.piece_update(upiece, uuop, &lens)?;
+ }
+
+ buf.log_updates(LogEntry {
+ html: "The facilitator (re)configured the game".to_owned(),
+ })?;
+ },
+ Online => { },
+ }
+ }
+}
+
+#[throws(ME)]
+fn execute_for_game(cs: &CommandStream, amu: &InstanceRef,
+ subcommands: Vec<MgmtGameUpdate>,
+ how: MgmtGameUpdateMode) {
+ let g = amu.lock()?;
+ let mut subcommands = subcommands.drain.zip(0..);
+ let mut uh = UpdateHandler::from_how(how);
+ let response = 'subcommands: loop {
+
+ let (subcommand, index) = match subcommands.next() {
+ None => break 'subcommands Fine { },
+ Some(r) => r,
+ };
+
+ let (upieces, ulogs) = match execute_game_update(&mut g.gs, subcommand) {
+ Err(e) => break 'subcommands ErrorAfter(index, e),
+ Ok(r) => r,
+ };
+
+ uh.accumulate(upieces, ulogs)?;
+
+ };
+
+ uh.complete()?;
+}
+
+#[throws(ME)]
+fn execute_game_update(gs: &mut GameState, update: MgmtGameUpdate)
+ -> (Vec<(PieceId,PieceUpdateOp<()>)>, Vec<LogEntry>) {
+ match update {
+ }
+}
+
+
impl CommandListener {
#[throws(StartupError)]
pub fn new() -> Self {
#[derive(Debug)]
pub struct Instance {
+ pub live : bool,
pub name : Arc<InstanceName>,
pub gs : GameState,
pub clients : DenseSlotMap<ClientId,Client>,
let name = Arc::new(name);
let inst = Instance {
+ live : true,
name : name.clone(),
gs,
clients : Default::default(),
#[throws(OE)]
pub fn lock<'g>(amu : &'g Arc<Mutex<Instance>>) -> InstanceGuard<'g> {
let ig = amu.lock()?;
+ if !ig.live { throw!(OnlineError::GameBeingDestroyed) }
InstanceGuard { ig, amu: amu.clone() }
}
+
+ pub fn destroy(g: InstanceGuard) {
+ g.live = false;
+ // remove the files
+ GLOBAL.games.write().unwrap().remove(&g.name);
+ InstanceGuard::forget_all_tokens(&mut g.tokens_players);
+ InstanceGuard::forget_all_tokens(&mut g.tokens_clients);
+ }
}
impl Deref for InstanceGuard<'_> {
Id::global_tokens(PRIVATE_Y).write().unwrap().insert(token, iad);
}
- pub fn game_destroy(mut self) {
- Self::forget_all_tokens(&mut self.ig.tokens_players);
- Self::forget_all_tokens(&mut self.ig.tokens_clients);
- }
fn forget_all_tokens<Id:AccessId>(tokens: &mut TokenRegistry<Id>) {
let global : &RwLock<TokenTable<Id>> = AccessId::global_tokens(PRIVATE_Y);
let mut global = global.write().unwrap();
let name = Arc::new(name);
let inst = Instance {
+ live: true,
name, gs, updates,
clients : Default::default(),
tokens_clients : Default::default(),