pub struct PermSet<P: Perm> (u64, PhantomData<&'static P>);
#[derive(Debug,Clone)]
- pub struct EffectiveAcl<'i, P: Perm> {
+ pub struct EffectiveACL<'i, P: Perm> {
pub owner_account: Option<&'i str>,
pub acl: &'i LoadedAcl<P>,
}
ptype: PhantomData<&'static P>,
}
- impl<'e, P:Perm> EffectiveAcl<'e, P> {
+ impl<'e, P:Perm> EffectiveACL<'e, P> {
fn entries(&self) -> impl Iterator<Item=AclEntryRef<'_, P>> {
self.owner_account.iter().map(
|owner|
completed
}
+pub fn ok_id<T,E>(t: T) -> Result<T,E> { Ok(t) }
+
fn main() {
#[derive(Default,Debug)]
struct RawMainArgs {
TP::ChangePieces,
];
-fn setup_table(ma: &MainOpts, chan: &mut ConnForGame,
- spec: &TableSpec, purge_old_players: bool) -> Result<(),AE> {
+#[throws(AE)]
+fn setup_table(ma: &MainOpts, spec: &TableSpec) -> Vec<Insn> {
let TableSpec { players, player_perms, acl } = spec;
let mut player_perms = player_perms.clone()
.unwrap_or(PLAYER_DEFAULT_PERMS.iter().cloned().collect());
let mut insns = vec![];
insns.push(Insn::ClearLog);
insns.push(Insn::SetACL { acl });
+ insns
+}
+
+
/*
}
}
*/
- Ok(())
-}
#[throws(AE)]
fn read_spec<T: DeserializeOwned>(filename: &str, what: &str) -> T {
#[throws(E)]
fn call(_sc: &Subcommand, ma: MainOpts, args: Vec<String>) {
- let args = parse_args::<Args,_>(args, &subargs, None, None);
+ let args = parse_args::<Args,_>(args, &subargs, &ok_id, None);
let spec : TableSpec = read_spec(&args.file, "table spec")?;
let mut chan = connect(&ma)?;
+ let insns = setup_table(&ma, &spec)?;
chan.cmd(&MgmtCommand::CreateGame {
- name: args.name.clone(), insns: vec![]
+ insns,
+ game: InstanceName {
+ game: args.name.clone(),
+ account: ma.account.clone(),
+ },
})?;
- let mut chan = ConnForGame {
- conn: chan,
- name: args.name.clone(),
- how: MgmtGameUpdateMode::Bulk,
- };
-
- setup_table(&ma, &mut chan, &spec)?;
-
if ma.verbose >= 0 {
eprintln!("create-table successful. game still needs setup.");
}
Err(e)
})?;
- setup_table(&ma, &mut chan, &table_spec)?;
- }
+ setup_table(&ma, &table_spec)?;
+ }
let mut insns = vec![];
} => {
let account = &cs.current_account()?.notional_account;
let (_arecord, acctid) = ag.lookup(account)?;
- let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::AddPlayer])?;
+ let (ig, auth) = cs.check_acl(ag, ig, PCH::Instance, &[TP::Play])?;
let nick = nick.ok_or(ME::ParameterMissing)?;
let logentry = LogEntry {
html: Html(format!("{} ({}) joined the game",
Ok(Resp::Pieces(pieces))
})?,
- RemovePlayer { player } => {
- let ig = cs.check_acl_modify_player(ag, ig, player,
- &[TP::RemovePlayer])?.0;
- let (gpl, _ipl) = ig.player_remove(player)?;
- let show = if let Some(gpl) = gpl {
- htmlescape::encode_minimal(&gpl.nick)
- } else {
- "<i>partial data?!</i>".to_string()
- };
- (U{ pcs: vec![],
- log: vec![ LogEntry {
- html: Html(format!("{} removed a player: {}", &who, &show)),
- }],
- raw: None},
- Fine, ig)
- },
-
UpdatePlayer {
player,
details: MgmtPlayerDetails { nick, timezone },
let ag = AccountsGuard::lock();
let (ig, _) = cs.check_acl(&ag, ig, PCH::Instance, &[TP::Super])?;
ig.acl = acl.into();
+ let mut log = vec![ LogEntry {
+ html: Html(format!("{} set the table access control list",
+ &who)),
+ } ];
+
+ let eacl = EffectiveACL {
+ owner_account: &ig.account,
+ acl: &ig.acl,
+ };
+
+ #[throws(InternalError)]
+ fn remove_old_players(ag: &AccountsGuard, ig: &mut InstanceGuard,
+ who: &str, eacl: &EffectiveACL<'_, TP>,
+ log: &mut Vec<LogEntry>) {
+ let mut remove = vec![];
+ for (player, ipr) in ig.players {
+ if_chain! {
+ let acctid = ipr.ipl.acctid;
+ if let Some(record,_) = ag.lookup(acctid);
+ if let Ok(_) = eacl.check(&*record.name, &[TP::Play]);
+ then {
+ /* ok */
+ }
+ else {
+ remove.push(player);
+ }
+ };
+ };
+ for (gpl, _ipl) in ig.players_remove(&remove)? {
+ let show = if let Some(gpl) = gpl {
+ htmlescape::encode_minimal(&gpl.nick)
+ } else {
+ "<i>partial data?!</i>".to_string()
+ };
+ log.push(LogEntry {
+ html: Html(format!("{} removed a player {}", &who, &show)),
+ });
+ }
+ }
+
+ remove_old_players(ag, ig, &who, &eacl, &mut log)?;
+
(U{ pcs: vec![ ],
- log: vec![ LogEntry {
- html: Html(format!("{} set the table access control list",
- &who)),
- } ],
+ log,
raw: None },
Fine, ig)
},
};
let owner_account = owner.to_string();
let owner_account = Some(owner_account.as_str());
- let eacl = EffectiveAcl { owner_account, acl };
+ let eacl = EffectiveACL { owner_account, acl };
eacl.check(subject, p)?
};
auth
self.tokens_deregister_for_id(|id| clients_to_remove.contains(&id));
}
- // #[throws(ServerFailure)]
+ // #[throws(InternalError)]
// https://github.com/withoutboats/fehler/issues/62
- pub fn player_remove(&mut self, oldplayer: PlayerId)
- -> Result<(Option<GPlayerState>, Option<IPlayerState>),
- InternalError> {
+ pub fn players_remove(&mut self, oldplayers: HashSet<PlayerId>)
+ ->
+ Result<Vec<
+ (Option<GPlayerState>, Option<IPlayerState>)
+ >, 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_gpl = players.remove(oldplayer);
+ let old_gpl = players.remove(oldplayers);
// New state
let mut gs = GameState {
// after all the things it will reference
let mut undo : Vec<Box<dyn FnOnce(&mut InstanceGuard)>> = vec![];
+ let held_by_old = |p: PieceState| if_chain! {
+ if let Some(held) = p.held;
+ if oldplayers.contains(held);
+ then { true }
+ else { false }
+ };
+
// Arrange gs.pieces
for (piece,p) in &mut self.c.g.gs.pieces {
- if p.held == Some(oldplayer) {
+ if held_by_old(p) {
p.held = None;
updated_pieces.push(piece);
}
}
undo.push(Box::new(|ig| for &piece in &updated_pieces {
(||Some({
- ig.c.g.gs.pieces.get_mut(piece)?.held = Some(oldplayer);
+ held_by_old(ig.c.g.gs.pieces.get_mut(piece)?);
}))();
}));
}
buf.finish();
- self.remove_clients(oldplayer, ErrorSignaledViaUpdate::PlayerRemoved);
- self.tokens_deregister_for_id(|id:PlayerId| id==oldplayer);
- let iplayer = self.iplayers.remove(oldplayer);
+ self.remove_clients(oldplayers, ErrorSignaledViaUpdate::PlayerRemoved);
+ self.tokens_deregister_for_id(|id:PlayerId| oldplayers.contains(id));
+ let iplayer = self.iplayers.remove(oldplayers);
let ipl = iplayer.map(|iplayer| iplayer.ipl);
self.save_access_now().unwrap_or_else(
|e| warn!(
pub use crate::shapelib;
pub use crate::tz::*;
pub use crate::accounts::*;
-pub use crate::accounts::loaded_acl::{self,LoadedAcl,EffectiveAcl,PermSet};
+pub use crate::accounts::loaded_acl::{self,LoadedAcl,EffectiveACL,PermSet};
pub use zcoord::{self, ZCoord};
pub enum TablePermission {
TestExistence,
ViewPublic,
- AddPlayer,
+ Play,
ChangePieces,
ResetOthersAccess,
RedeliverOthersAccess,
ModifyOtherPlayer,
- RemovePlayer,
Super,
}