From: Ian Jackson Date: Wed, 20 May 2020 21:35:03 +0000 (+0100) Subject: before redo for user based guards etc. X-Git-Tag: otter-0.2.0~1608 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=0cb5c7ee405f65f64d45a32e47ed1604e07ebabe;p=otter.git before redo for user based guards etc. --- diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..61b26b1c --- /dev/null +++ b/src/error.rs @@ -0,0 +1,8 @@ + +#[derive(Error)] +enum Error { + [error("attempt to create instance with same name as existing instance")] + InstanceAlreadyExists, + [error("attempt to create instance with same name as existing instance")] + UnknownInstance, +} diff --git a/src/gamestate.rs b/src/gamestate.rs index 994f25de..761e14fd 100644 --- a/src/gamestate.rs +++ b/src/gamestate.rs @@ -1,53 +1,30 @@ - pub trait Piece { - type Msg : Serialize; - fn msg(&self) -> Msg; + fn svg(&self, pr : &PiecedRecord) -> SvgData; } #[derive(Debug)] pub struct PieceRecord { - x : Coord, - y : Coord, + pos : Pos, p : Box, held : Option, } -const RECENT_BUFFER : usize = 10; #[derive(Debug)] pub struct GameState { - gen : Counter, - data : GameStateData, - recent : VecDeque, - notify : Condvar, -} - -#[derive(Debug)] -pub struct GameStateData { pub pieces : Vec, pub players : Vec, } -impl Deref for GameState { - type Output = GamStateData; - fn deref(&self) -> &GamStateData { &self.data } -} - -impl GameState { - fn as_ref(&self) -> (&usize, &GameStateData) { (&self.gen, &self.data) } - fn gen(&self) -> usize { self.gen } +type MsgPiece = SvgData; - fn update(&mut self, f : F) - where F : FnOnce(&mut GameStateData) -> MsgUpdate { - let msg = f(&mut self.data), - if let MsgNoUpdate = msg { return } - self.gen += 1, - if self.recent.len() >= RECENT_BUFFER { self.pop_front() } - self.recent.push_back(msg); - self.notify.notify_all(); - } +pub struct GameRef (InstanceGuard); +impl Deref for GameRef { + type Output = GamState; + fn deref(&self) -> &GameState { self.0.read() } } + #[derive(Serialize)] enum MsgUpdate { MsgNoUpdate, @@ -56,31 +33,25 @@ enum MsgUpdate { MsgPieceUpdate(usize, MsgPiece), } -struct MsgPiece { - -} - impl PieceRecord { - fn msg(&self) -> MsgPiece { - - } + fn msg(&self) -> MsgPiece { self.p.svg(self) } } -impl GameState { +impl GameRef { fn piece_insert(&mut self, i : usize, p : PieceRecord) { - self.update(|d| { + self.0.update(|d| { d.pieces.insert(i, p); MsgPieceInsert(i, p.msg()) ); } fn piece_delete(&mut self, i : usize) { - self.update(|d| { + self.0.update(|d| { d.pieces.remove(i, p); MsgPieceDelete(i) } } fn piece_update(&mut self, i : usize, p : PieceRecord) { - self.update(|d| { + self.0.update(|d| { d.pieces[i] = p, MsgPieceUpdate(i, p.msg()), } diff --git a/src/global.rs b/src/global.rs new file mode 100644 index 00000000..33f37963 --- /dev/null +++ b/src/global.rs @@ -0,0 +1,37 @@ + +#[derive(Default)] +struct Global { + instances : RwLock>>, + // xxx delete instances at some point! +} + +lazy_static! { + static ref GLOBAL : Global = Default::default(); +} + +fn lookup_instance(name : &str) -> Option> { + GLOBAL.instances().read().get(name) +} + +#[throws(TE)] +fn create_instance(name : &str, i : Rc) { + let w = GLOBAL.instances().write(); + match w.entry(name) { + Occupied(oe) => throw!(TE::InstanceAlreadyExists); + Vacant(ve) => ve.insert(i); + } +} + +impl<'r> FromParam<'r> for InstanceGuard<'r> { + // xxx any additional auth should go here + type Error = AE; + #[throws(E)] + fn from_param(param: &'r RawStr) -> Self { + let g = GLOBAL.instances().read(); + let iname = param.as_str(); + let i = g.get(iname); + let i = i.ok_or(anyhow!("unnown instance"))?; + i.lock(iname) + } +} + diff --git a/src/imports.rs b/src/imports.rs index 7582a078..dc4c222b 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -21,3 +21,8 @@ pub use rocket::response::NamedFile; pub use rocket::response; pub type E = anyhow::Error; + +pub type SvgData = Vec; +pub type Coord = isize; +pub type Pos = [Coord; 2]; +pub type Colour = String; diff --git a/src/instance.rs b/src/instance.rs new file mode 100644 index 00000000..720cb1ce --- /dev/null +++ b/src/instance.rs @@ -0,0 +1,56 @@ + +const RECENT_BUFFER : usize = 10; + +#[derive(Debug)] +pub struct Instance { + g : RwLock, + g_notify : Condvar, +} + +#[derive(Debug)] +struct Game { + gen : Counter, + gs : GameState, + recent : VecDeque, +} + +impl Instance { + fn new(gs : GameState) -> Instance { + Instance { + g_notify : Condvar::new(), + g : RwLock::new(Game { + gen : 0, + gs, + recent : VecDequeue::with_capacity(RECENT_BUFFER), + }), + } + } +} + +pub struct InstanceGuard<'r> { + iname : &'r str; + g : RwLockWriteGuard, + g_notify : &'r Condvar, +} + +impl Instance { + fn lock(&'r self, iname : &'r str) -> InstanceGuard<'r> { + let g = self.g.lock(); + InstanceGuard { g, iname, g_notify : &self.g_notify } + } +} + +impl InstanceGuard { + fn read(&self) -> &GameState { &self.g.deref().gs } + fn iname(&self) -> &str { self.iname } + + fn update(&mut self, f : F) + where F : FnOnce(&mut GameState) -> MsgUpdate { + let msg = f(&mut self.gs.g), + if let MsgNoUpdate = msg { return } + self.gs.gen += 1, + if self.gw.recent.len() >= RECENT_BUFFER { self.pop_front() } + self.g.recent.push_back(msg); + self.g_notify.notify_all(); + } +} diff --git a/src/main.rs b/src/main.rs index d3d3a7dc..5bfbde91 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,8 @@ use imports::*; type RE = E; +pub type InstanceName = String; + #[derive(Serialize,Debug)] struct TestRenderContext { } @@ -53,7 +55,7 @@ impl Read for TestCounterInner { } } -#[get("/updates")] +#[get("/")] fn updates() -> impl response::Responder<'static> { let tc = TestCounterInner { next : 0 }; let tc = BufReader::new(tc); @@ -63,7 +65,7 @@ fn updates() -> impl response::Responder<'static> { response::content::Content(ct,ch) } -#[get("/")] +#[get("/_/")] fn resource(leaf : CheckedResourceLeaf) -> io::Result { let template_dir = "templates"; // xxx NamedFile::open(format!("{}/{}", template_dir, leaf.safe)) diff --git a/src/pieces.rs b/src/pieces.rs index 6454ae1a..0f6fa366 100644 --- a/src/pieces.rs +++ b/src/pieces.rs @@ -5,5 +5,10 @@ struct Disc { } impl Piece for Disc { + fn svg(&self, pr : &PiecedRecord) -> SvgData { + format!( + r#""#, + pr.pos[0], pr.pos[1], swlf.size, self.colour, + ).into_bytes() + } } -