}
display_as_debug!(ApiPieceOpError);
+impl From<PlayerNotFound> for ApiPieceOpError {
+ fn from(x: PlayerNotFound) -> ApiPieceOpError {
+ ApiPieceOpError::ReportViaResponse(x.into())
+ }
+}
+
pub trait Lens : Debug {
fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId;
fn log_pri(&self, piece: PieceId, pc: &PieceState)
use OnlineError::*;
let status = match self {
ServerFailure(_) => Status::InternalServerError,
- NoClient | NoPlayer | GameBeingDestroyed
+ NoClient | NoPlayer(_) | GameBeingDestroyed
=> Status::NotFound,
OnlineError::PieceHeld | OnlineError::PieceGone
=> Status::Conflict,
type Resp = MgmtGameResponse;
let who = &cs.who; // todo show player nick when it's a player
+ fn tz_from_str(s: &str) -> Timezone {
+ match Timezone::from_str(s) {
+ Ok(tz) => tz,
+ Err(x) => match x { },
+ }
+ }
+
#[throws(MgmtError)]
fn readonly<'ig,
F: FnOnce(&InstanceGuard) -> Result<MgmtGameResponse,ME>,
};
let timezone = timezone.as_ref().map(String::as_str)
.unwrap_or("");
- let tz = match Timezone::from_str(timezone) {
- Ok(tz) => tz,
- Err(x) => match x { },
- };
+ let tz = tz_from_str(&timezone);
let gpl = GPlayerState {
nick: nick.to_string(),
};
let itemname = pinfo.itemname().to_string();
let bbox = pinfo.bbox_approx();
let lens = TransparentLens { };
+ #[allow(irrefutable_let_patterns)]
+ let visible = if let TransparentLens { } = lens {
+ Some(MgmtGamePieceVisibleInfo {
+ pos, face, desc_html, bbox
+ })
+ } else {
+ None
+ };
Some(MgmtGamePieceInfo {
piece, itemname,
- visible:
- if let TransparentLens { } = lens {
- Some(MgmtGamePieceVisibleInfo {
- pos, face, desc_html, bbox
- })
- } else {
- None
- }
+ visible
})
}).flatten().collect();
Ok(Resp::Pieces(pieces))
Fine, ig)
},
+ UpdatePlayer {
+ player,
+ details: MgmtPlayerDetails { nick, timezone },
+ } => {
+ let ig = cs.check_acl_modify_player(ag, ig, player,
+ &[TP::ModifyOtherPlayer])?.0;
+ let ipr = ig.iplayers.byid_mut(player)?;
+ let gpl = ig.gs.players.byid_mut(player)?;
+ let mut log = vec![];
+ if let Some(new_nick) = nick {
+ ig.check_new_nick(&new_nick)?;
+ log.push(LogEntry {
+ html: Html(format!("{} changed {}'s nick to {}",
+ &who,
+ htmlescape::encode_minimal(&gpl.nick),
+ htmlescape::encode_minimal(&new_nick))),
+ });
+ gpl.nick = new_nick;
+ }
+ if let Some(new_timezone) = timezone {
+ ipr.ipl.tz = tz_from_str(&new_timezone);
+ }
+ (U{ log,
+ pcs: vec![],
+ raw: None},
+ Fine, ig)
+ },
+
Insn::Info => readonly(cs,ag,ig, &[TP::ViewPublic], |ig|{
let players = ig.gs.players.iter().map(
|(player, &gpl)| {
{
let (ipl_unauth, gpl_unauth) = {
let ig = ig.by(Authorisation::authorise_any());
- (ig.iplayers.get(player).ok_or(ME::PlayerNotFound)?,
- ig.gs.players.get(player).ok_or(ME::PlayerNotFound)?)
+ (ig.iplayers.byid(player)?, ig.gs.players.byid(player)?)
};
let how = PCH::InstanceOrOnlyAffectedAccount(ipl_unauth.ipl.acctid);
let (ig, auth) = self.check_acl(ag, ig, how, p)?;
else { None }
}
},
+ PCH::Instance => None,
} {
return auth;
}
GameNotFound,
GameCorrupted,
AccountNotFound(#[from] AccountNotFound),
- PlayerNotFound,
+ PlayerNotFound(#[from] PlayerNotFound),
AuthorisationUninitialised,
PieceNotFound,
LimitExceeded,
#[error("client session not recognised (terminated by server?)")]
NoClient,
#[error("player not part of game (removed?)")]
- NoPlayer,
+ NoPlayer(#[from] PlayerNotFound),
#[error("invalid Z coordinate")]
InvalidZCoord,
#[error("Server operational problems - consult administrator: {0:?}")]
some_slotmap!{SecondarySlotMap}
impl<T> IdForById for T where T : AccessId {
- type Error = OE;
- const ERROR : OE = <Self as AccessId>::ERROR;
+ type Error = T::Error;
+ const ERROR : Self::Error = <Self as AccessId>::ERROR;
}
impl IdForById for PieceId {
logentry: LogEntry) -> (PlayerId, LogEntry) {
// saving is fallible, but we can't attempt to save unless
// we have a thing to serialise with the player in it
- if self.c.g.gs.players.values().any(|old| old.nick == gnew.nick) {
- Err(MgmtError::NickCollision)?;
- }
+ self.check_new_nick(&gnew.nick)?;
if self.c.g.iplayers.values().any(|r| r.ipl.acctid == inew.acctid) {
Err(MgmtError::AlreadyExists)?;
}
(player, logentry)
}
+ #[throws(MgmtError)]
+ pub fn check_new_nick(&mut self, new_nick: &str) {
+ if self.c.g.gs.players.values().any(|old| old.nick == new_nick) {
+ Err(MgmtError::NickCollision)?;
+ }
+ }
+
pub fn remove_clients(&mut self,
player: PlayerId,
signal: ErrorSignaledViaUpdate) {
authorised: Authorisation<AccountName>,
reset: bool)
-> Option<AccessTokenReport> {
- let ipl = self.c.g.iplayers.get(player)
- .ok_or(MgmtError::PlayerNotFound)?
- .ipl;
- let gpl = self.c.g.gs.players.get(player)
- .ok_or(MgmtError::PlayerNotFound)?;
+ let ipl = self.c.g.iplayers.byid(player)?.ipl;
+ let gpl = self.c.g.gs.players.byid(player)?;
let (access, acctid) = accounts.with_entry_mut(
ipl.acctid, authorised, None,
pub type TokenTable<Id> = HashMap<RawToken, InstanceAccessDetails<Id>>;
pub trait AccessId : Copy + Clone + 'static {
+ type Error : Into<OnlineError>;
+ const ERROR : Self::Error;
fn global_tokens(_:PrivateCaller) -> &'static RwLock<TokenTable<Self>>;
fn tokens_registry(ig: &mut Instance, _:PrivateCaller)
-> &mut TokenRegistry<Self>;
- const ERROR : OnlineError;
}
+#[derive(Debug,Copy,Clone,Eq,PartialEq,Ord,PartialOrd)]
+#[derive(Serialize,Deserialize)]
+#[derive(Error)]
+#[error("Player not found")]
+pub struct PlayerNotFound;
+
impl AccessId for PlayerId {
- const ERROR : OnlineError = NoPlayer;
+ type Error = PlayerNotFound;
+ const ERROR : PlayerNotFound = PlayerNotFound;
fn global_tokens(_: PrivateCaller) -> &'static RwLock<TokenTable<Self>> {
&GLOBAL.players
}
}
}
impl AccessId for ClientId {
+ type Error = OnlineError;
const ERROR : OnlineError = NoClient;
fn global_tokens(_: PrivateCaller) -> &'static RwLock<TokenTable<Self>> {
&GLOBAL.clients
}
pub fn lookup_token<Id : AccessId>(s : &RawTokenVal)
- -> Result<InstanceAccessDetails<Id>, OE> {
+ -> Result<InstanceAccessDetails<Id>, Id::Error> {
Id::global_tokens(PRIVATE_Y).read().unwrap().get(s).cloned()
.ok_or(Id::ERROR)
}
impl<'r, Id> FromParam<'r> for InstanceAccess<'r, Id>
- where Id : AccessId
+ where Id : AccessId, OE : From<Id::Error>
{
type Error = OE;
#[throws(OE)]
ChangePieces,
ResetOthersAccess,
RedeliverOthersAccess,
+ ModifyOtherPlayer,
RemovePlayer,
ChangeACL,
}