let piece = lens.decode_visible_pieceid(form.piece, player);
match (||{
- let pc = gs.pieces.byid_mut(piece)?;
+ let pc = gs.pieces.byid_mut(piece)
+ .map_err(|()| OnlineError::PieceGone)?;
let q_gen = form.gen;
let u_gen =
match self {
ReportViaUpdate(poe) => {
let gen = ig.gs.gen;
- ig.updates.get_mut(player)
- .ok_or(OE::NoPlayer)?
- .push(Arc::new(PreparedUpdate {
- gen,
- us : vec![ PreparedUpdateEntry::Error(
- Some(client),
- ErrorSignaledViaUpdate::PieceOpError(
- lens.pieceid2visible(piece),
- poe,
- ),
- )],
- }));
-
- let mut buf = PrepareUpdatesBuffer::new(ig, None, None);
- buf.piece_update(piece, PieceUpdateOp::Modify(()), lens);
+ let pc = ig.gs.pieces.byid_mut(piece).map_err(|()| OE::PieceGone)?;
+ let pri = lens.svg_pri(piece,pc,player);
+ let state = pc.prep_piecestate(&pri)?;
+ let pl_updates = ig.updates.get_mut(player).ok_or(OE::NoPlayer)?;
+ let pue = PreparedUpdateEntry::Error(
+ Some(client),
+ ErrorSignaledViaUpdate::PieceOpError {
+ piece: pri.id,
+ error: poe,
+ state,
+ },
+ );
+ let update = PreparedUpdate { gen, us : vec![ pue ] };
+ pl_updates.push(Arc::new(update));
},
ReportViaResponse(err) => {
NoPlayer,
#[error("invalid Z coordinate")]
InvalidZCoord,
- #[error("improper piece hold status for op (client should have known)")]
- PieceHeld,
#[error("Server operational problems - consult administrator: {0:?}")]
ServerFailure(#[from] InternalError),
#[error("JSON deserialisation error: {0:?}")]
BadJSON(serde_json::Error),
+ #[error("referenced piece is gone (maybe race)")]
+ PieceGone,
+ #[error("improper piece hold status for op (maybe race)")]
+ PieceHeld,
}
from_instance_lock_error!{OnlineError}
}
}
-#[derive(Error,Debug,Serialize,Copy,Clone)]
+#[derive(Error,Debug,Serialize,Clone)]
pub enum ErrorSignaledViaUpdate {
InternalError,
PlayerRemoved,
- PieceOpError(VisiblePieceId, PieceOpError),
+ PieceOpError {
+ piece: VisiblePieceId,
+ error: PieceOpError,
+ state: PreparedPieceState,
+ },
}
display_as_debug!{ErrorSignaledViaUpdate}
#[derive(Error,Debug,Serialize,Copy,Clone)]
pub enum PieceOpError {
- Gone,
Conflict,
PosOffTable,
}
}
impl IdForById for PieceId {
- type Error = PieceOpError;
- const ERROR : PieceOpError = PieceOpError::Gone;
+ type Error = ();
+ const ERROR : () = ();
}
#[macro_export]
use OnlineError::*;
let status = match self {
ServerFailure(_) => Status::InternalServerError,
- NoClient | NoPlayer | GameBeingDestroyed => Status::NotFound,
- InvalidZCoord | BadJSON(_) | OnlineError::PieceHeld
+ NoClient | NoPlayer | GameBeingDestroyed
+ => Status::NotFound,
+ OnlineError::PieceHeld | OnlineError::PieceGone
+ => Status::Conflict,
+ InvalidZCoord | BadJSON(_)
=> Status::BadRequest,
};
let mut resp = Responder::respond_to(msg,req).unwrap();
Error (Option<ClientId> /* none: all */, ErrorSignaledViaUpdate),
}
-#[derive(Debug,Serialize)]
+#[derive(Debug,Clone,Serialize)]
pub struct PreparedPieceState {
pub pos : Pos,
pub svg : String,
},
SetTableSize(Pos),
Log (&'u LogEntry),
- Error(ErrorSignaledViaUpdate),
+ Error(&'u ErrorSignaledViaUpdate),
}
// ========== implementation ==========
(update, pri_for_all.id)
},
- Err(PieceOpError::Gone) => {
+ Err(()) => {
(PieceUpdateOp::Delete(), lens.pieceid2visible(piece))
}
- Err(e) => {
- panic!(format!("unexpected error {:?} from pices.byid_mut", &e));
- }
};
PreparedUpdateEntry::Piece {
&PreparedUpdateEntry::SetTableSize(size) => {
TransmitUpdateEntry::SetTableSize(size)
},
- &PreparedUpdateEntry::Error(c, e) => {
- if let Some(c) = c { if c != dest { continue } }
+ PreparedUpdateEntry::Error(c, e) => {
+ if let Some(c) = c { if *c != dest { continue } }
TransmitUpdateEntry::Error(e)
}
};