chiark / gitweb /
much code motion etc.
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 11 Jul 2020 22:30:51 +0000 (23:30 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 11 Jul 2020 22:30:51 +0000 (23:30 +0100)
src/api.rs [new file with mode: 0644]
src/bin/server.rs
src/gamestate.rs
src/global.rs
src/http.rs
src/imports.rs
src/lib.rs
src/session.rs [new file with mode: 0644]
src/sse.rs
src/updates.rs

diff --git a/src/api.rs b/src/api.rs
new file mode 100644 (file)
index 0000000..530ee58
--- /dev/null
@@ -0,0 +1,247 @@
+
+use crate::imports::*;
+use crate::http::*;
+
+#[derive(Debug,Serialize,Deserialize)]
+struct ApiPiece<O : ApiPieceOp> {
+  ctoken : String,
+  piece : VisiblePieceId,
+  gen : Generation,
+  cseq : ClientSequence,
+  op : O,
+}
+trait ApiPieceOp : Debug {
+  #[throws(GameError)]
+  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
+        lens: &dyn Lens /* used for LogEntry and PieceId but not Pos */)
+        -> (PieceUpdateOp<()>, Vec<LogEntry>);
+}
+
+trait Lens {
+  fn log_pri(&self, piece: PieceId, pc: &PieceRecord)
+             -> PieceRenderInstructions;
+  fn svg_pri(&self, piece: PieceId, pc: &PieceRecord, player: PlayerId)
+             -> PieceRenderInstructions;
+  fn massage_prep_piecestate(&self, ns : &mut PreparedPieceState);
+  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, player: PlayerId)
+                            -> PieceId;
+}
+struct TransparentLens { }
+impl Lens for TransparentLens {
+  fn log_pri(&self, piece: PieceId, pc: &PieceRecord)
+             -> PieceRenderInstructions {
+    let kd : slotmap::KeyData = piece.into();
+    let id = VisiblePieceId(kd);
+    PieceRenderInstructions { id, face : pc.face }
+  }
+  fn svg_pri(&self, piece: PieceId, pc: &PieceRecord, _player: PlayerId)
+             -> PieceRenderInstructions {
+    self.log_pri(piece, pc)
+  }
+  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, _player: PlayerId)
+                            -> PieceId {
+    let kd : slotmap::KeyData = vpiece.into();
+    PieceId::from(kd)
+  }
+  fn massage_prep_piecestate(&self, _ns : &mut PreparedPieceState) { }
+}
+
+#[throws(OE)]
+fn api_piece_op<O: ApiPieceOp>(form : Json<ApiPiece<O>>)
+                   -> impl response::Responder<'static> {
+//  thread::sleep(Duration::from_millis(2000));
+  let iad = lookup_token(&form.ctoken)?;
+  let client = iad.ident;
+  let mut g = iad.g.lock()?;
+  let g = &mut *g;
+  let cl = &g.clients.byid(client)?;
+  // ^ can only fail if we raced
+  let player = cl.player;
+  let gs = &mut g.gs;
+  let _ = gs.players.byid(player)?;
+  let lens = TransparentLens { };
+  let piece = lens.decode_visible_pieceid(form.piece, player);
+
+  match (||{
+    let pc = gs.pieces.byid_mut(piece)?;
+
+    let q_gen = form.gen;
+    let u_gen =
+      if client == pc.lastclient { pc.gen_before_lastclient }
+      else { pc.gen };
+
+    eprintln!("Q_GEN={:?} U_GEN={:?}", u_gen, q_gen);
+
+    if u_gen > q_gen { Err(GameError::Conflict)? }
+    if pc.held != None && pc.held != Some(player) {
+      Err(GameError::PieceHeld)?
+    };
+    let (update, logents) = form.op.op(gs,player,piece,&lens)?;
+    Ok((update, logents))
+  })() {
+    Err(err) => {
+      let err : GameError = err;
+      eprintln!("API {:?} => {:?}", &form, &err);
+    },
+    Ok((update, logents)) => {
+      let pc = gs.pieces.byid_mut(piece).expect("piece deleted by op!");
+
+      gs.gen.increment();
+      let gen = gs.gen;
+      if client != pc.lastclient {
+        pc.gen_before_lastclient = pc.gen;
+        pc.lastclient = client;
+      }
+      pc.gen = gen;
+      eprintln!("PC GEN_LC={:?} LC={:?}", pc.gen, pc.lastclient);
+
+      let pri_for_all = lens.svg_pri(piece,pc,Default::default());
+
+      let update = update.map_new_state(|_|{
+        let mut ns = pc.prep_piecestate(&pri_for_all);
+        lens.massage_prep_piecestate(&mut ns);
+        ns
+      });
+
+      let mut us = Vec::with_capacity(1 + logents.len());
+
+      us.push(PreparedUpdateEntry::Piece {
+        client,
+        sameclient_cseq : form.cseq,
+        piece : pri_for_all.id,
+        op : update,
+      });
+
+      for logentry in logents {
+        let logentry = Arc::new(logentry);
+        gs.log.push((gen, logentry.clone()));
+        us.push(PreparedUpdateEntry::Log(logentry));
+      }
+
+      let update = PreparedUpdate { gen, us, };
+      let update = Arc::new(update);
+      eprintln!("UPDATE {:?}", &update);
+
+      for (_tplayer, tplupdates) in &mut g.updates {
+        tplupdates.log.push_back(update.clone());
+        tplupdates.cv.notify_all();
+      }
+      eprintln!("API {:?} OK", &form);
+    }
+  }
+  ""
+}
+
+#[derive(Debug,Serialize,Deserialize)]
+struct ApiPieceGrab {
+}
+#[post("/_/api/grab", format="json", data="<form>")]
+#[throws(OE)]
+fn api_grab(form : Json<ApiPiece<ApiPieceGrab>>)
+            -> impl response::Responder<'static> {
+  api_piece_op(form)
+}
+impl ApiPieceOp for ApiPieceGrab {
+  #[throws(GameError)]
+  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
+        lens: &dyn Lens)
+        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+    let pl = gs.players.byid(player).unwrap();
+    let pc = gs.pieces.byid_mut(piece).unwrap();
+
+    if pc.held.is_some() { Err(GameError::PieceHeld)? }
+    pc.held = Some(player);
+    
+    let update = PieceUpdateOp::Modify(());
+
+    let logent = LogEntry {
+      html : format!("{} grasped {}",
+                     &htmlescape::encode_minimal(&pl.nick),
+                     pc.describe_html(&lens.log_pri(piece, pc))),
+    };
+
+    (update, vec![logent])
+  }
+}
+
+#[derive(Debug,Serialize,Deserialize)]
+struct ApiPieceUngrab {
+}
+#[post("/_/api/ungrab", format="json", data="<form>")]
+#[throws(OE)]
+fn api_ungrab(form : Json<ApiPiece<ApiPieceUngrab>>)
+              -> impl response::Responder<'static> {
+  api_piece_op(form)
+}
+impl ApiPieceOp for ApiPieceUngrab {
+  #[throws(GameError)]
+  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
+        lens: &dyn Lens)
+        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+    let pl = gs.players.byid(player).unwrap();
+    let pc = gs.pieces.byid_mut(piece).unwrap();
+
+    if pc.held != Some(player) { Err(GameError::PieceHeld)? }
+    pc.held = None;
+    
+    let update = PieceUpdateOp::Modify(());
+
+    let logent = LogEntry {
+      html : format!("{} released {}",
+                     &htmlescape::encode_minimal(&pl.nick),
+                     pc.describe_html(&lens.log_pri(piece, pc))),
+    };
+
+    (update, vec![logent])
+  }
+}
+
+#[derive(Debug,Serialize,Deserialize)]
+struct ApiPieceRaise {
+  z : ZCoord,
+}
+#[post("/_/api/setz", format="json", data="<form>")]
+#[throws(OE)]
+fn api_raise(form : Json<ApiPiece<ApiPieceRaise>>)
+            -> impl response::Responder<'static> {
+  api_piece_op(form)
+}
+impl ApiPieceOp for ApiPieceRaise {
+  #[throws(GameError)]
+  fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
+        _: &dyn Lens)
+        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+    let pc = gs.pieces.byid_mut(piece).unwrap();
+    pc.zlevel = ZLevel { z : self.z, zg : gs.gen };
+    let update = PieceUpdateOp::SetZLevel(pc.zlevel);
+    (update, vec![])
+  }
+}
+
+#[derive(Debug,Serialize,Deserialize)]
+struct ApiPieceMove (Pos);
+#[post("/_/api/m", format="json", data="<form>")]
+#[throws(OE)]
+fn api_move(form : Json<ApiPiece<ApiPieceMove>>) -> impl response::Responder<'static> {
+  api_piece_op(form)
+}
+impl ApiPieceOp for ApiPieceMove {
+  #[throws(GameError)]
+  fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
+        _lens: &dyn Lens)
+        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
+    let pc = gs.pieces.byid_mut(piece).unwrap();
+
+    pc.pos = self.0;
+    let update = PieceUpdateOp::Move(self.0);
+    (update, vec![])
+  }
+}
+
+/*
+      api_grab,
+      api_ungrab,
+      api_raise,
+      api_move,
+xxx
+*/
index 95459c55913e1ed66fff0a76f5ee40cda512cc78..e0fb29677c1556ac7906be9a118859a3555f48b2 100644 (file)
@@ -5,9 +5,7 @@
 
 #![feature(proc_macro_hygiene, decl_macro)]
 
-use rocket::{get,post,routes};
-use rocket_contrib::json::Json;
-//use rocket::{post};
+use rocket::{get,routes};
 
 use game::imports::*;
 
@@ -50,331 +48,6 @@ fn loading(ptoken : InstanceAccess<PlayerId>) -> Template {
   Template::render("loading",&c)
 }
 
-#[derive(Serialize,Debug)]
-struct SessionRenderContext {
-  ctoken : String,
-  player : PlayerId,
-  gen : Generation,
-  uses : Vec<SessionPieceContext>,
-  defs : Vec<(VisiblePieceId,String)>,
-  nick : String,
-}
-
-#[derive(Serialize,Debug)]
-struct SessionPieceContext {
-  id: VisiblePieceId,
-  pos: Pos,
-  info: String,
-}
-
-#[derive(Serialize,Debug)]
-struct SessionPieceLoadJson<'r> {
-  held : &'r Option<PlayerId>,
-  z : ZCoord,
-  zg : Generation,
-}
-
-#[derive(Deserialize)]
-struct SessionForm {
-  ptoken : String,
-}
-#[post("/_/session", format="json", data="<form>")]
-fn session(form : Json<SessionForm>) -> Result<Template,OE> {
-  // make session in this game, log a message to other players
-  let iad = lookup_token(&form.ptoken)?;
-  let player = iad.ident;
-  let c = {
-    let mut ig = iad.g.lock()?;
-    let ig = &mut *ig;
-    let pl = ig.gs.players.byid_mut(player)?;
-    let cl = Client { player };
-    let client = ig.clients.insert(cl);
-
-    let ciad = InstanceAccessDetails {
-      g : iad.g.clone(),
-      ident : client,
-    };
-    let ctoken = record_token(ciad);
-
-    let mut uses = vec![];
-    let mut alldefs = vec![];
-
-    let mut pieces : Vec<_> = ig.gs.pieces.iter().collect();
-
-    pieces.sort_by_key(|(_,pr)| &pr.zlevel);
-
-    for (gpid, pr) in pieces {
-      let pri = PieceRenderInstructions {
-        id : make_pieceid_visible(gpid),
-        face : pr.face,
-      };
-      let defs = pr.make_defs(&pri);
-      alldefs.push((pri.id, defs));
-
-      let for_info = SessionPieceLoadJson {
-        held : &pr.held,
-        z  : pr.zlevel.z,
-        zg : pr.zlevel.zg,
-      };
-
-      let for_piece = SessionPieceContext {
-        id: pri.id,
-        pos : pr.pos,
-        info : serde_json::to_string(&for_info)?,
-      };
-      uses.push(for_piece);
-    }
-
-    let src = SessionRenderContext {
-      ctoken : ctoken.0,
-      gen : ig.gs.gen,
-      player,
-      defs : alldefs,
-      uses,
-      nick : pl.nick.clone(),
-    };
-    eprintln!("SRC {:?}", &src);
-    src
-  };
-  Ok(Template::render("session",&c))
-}
-
-#[derive(Debug,Serialize,Deserialize)]
-struct ApiPiece<O : ApiPieceOp> {
-  ctoken : String,
-  piece : VisiblePieceId,
-  gen : Generation,
-  cseq : ClientSequence,
-  op : O,
-}
-trait ApiPieceOp : Debug {
-  #[throws(GameError)]
-  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
-        lens: &dyn Lens /* used for LogEntry and PieceId but not Pos */)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>);
-}
-
-trait Lens {
-  fn log_pri(&self, piece: PieceId, pc: &PieceRecord)
-             -> PieceRenderInstructions;
-  fn svg_pri(&self, piece: PieceId, pc: &PieceRecord, player: PlayerId)
-             -> PieceRenderInstructions;
-  fn massage_prep_piecestate(&self, ns : &mut PreparedPieceState);
-  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, player: PlayerId)
-                            -> PieceId;
-}
-struct TransparentLens { }
-impl Lens for TransparentLens {
-  fn log_pri(&self, piece: PieceId, pc: &PieceRecord)
-             -> PieceRenderInstructions {
-    let kd : slotmap::KeyData = piece.into();
-    let id = VisiblePieceId(kd);
-    PieceRenderInstructions { id, face : pc.face }
-  }
-  fn svg_pri(&self, piece: PieceId, pc: &PieceRecord, _player: PlayerId)
-             -> PieceRenderInstructions {
-    self.log_pri(piece, pc)
-  }
-  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, _player: PlayerId)
-                            -> PieceId {
-    let kd : slotmap::KeyData = vpiece.into();
-    PieceId::from(kd)
-  }
-  fn massage_prep_piecestate(&self, _ns : &mut PreparedPieceState) { }
-}
-
-#[throws(OE)]
-fn api_piece_op<O: ApiPieceOp>(form : Json<ApiPiece<O>>)
-                   -> impl response::Responder<'static> {
-//  thread::sleep(Duration::from_millis(2000));
-  let iad = lookup_token(&form.ctoken)?;
-  let client = iad.ident;
-  let mut g = iad.g.lock()?;
-  let g = &mut *g;
-  let cl = &g.clients.byid(client)?;
-  // ^ can only fail if we raced
-  let player = cl.player;
-  let gs = &mut g.gs;
-  let _ = gs.players.byid(player)?;
-  let lens = TransparentLens { };
-  let piece = lens.decode_visible_pieceid(form.piece, player);
-
-  match (||{
-    let pc = gs.pieces.byid_mut(piece)?;
-
-    let q_gen = form.gen;
-    let u_gen =
-      if client == pc.lastclient { pc.gen_before_lastclient }
-      else { pc.gen };
-
-    eprintln!("Q_GEN={:?} U_GEN={:?}", u_gen, q_gen);
-
-    if u_gen > q_gen { Err(GameError::Conflict)? }
-    if pc.held != None && pc.held != Some(player) {
-      Err(GameError::PieceHeld)?
-    };
-    let (update, logents) = form.op.op(gs,player,piece,&lens)?;
-    Ok((update, logents))
-  })() {
-    Err(err) => {
-      let err : GameError = err;
-      eprintln!("API {:?} => {:?}", &form, &err);
-    },
-    Ok((update, logents)) => {
-      let pc = gs.pieces.byid_mut(piece).expect("piece deleted by op!");
-
-      gs.gen.increment();
-      let gen = gs.gen;
-      if client != pc.lastclient {
-        pc.gen_before_lastclient = pc.gen;
-        pc.lastclient = client;
-      }
-      pc.gen = gen;
-      eprintln!("PC GEN_LC={:?} LC={:?}", pc.gen, pc.lastclient);
-
-      let pri_for_all = lens.svg_pri(piece,pc,Default::default());
-
-      let update = update.map_new_state(|_|{
-        let mut ns = pc.prep_piecestate(&pri_for_all);
-        lens.massage_prep_piecestate(&mut ns);
-        ns
-      });
-
-      let mut us = Vec::with_capacity(1 + logents.len());
-
-      us.push(PreparedUpdateEntry::Piece {
-        client,
-        sameclient_cseq : form.cseq,
-        piece : pri_for_all.id,
-        op : update,
-      });
-
-      for logentry in logents {
-        let logentry = Arc::new(logentry);
-        gs.log.push((gen, logentry.clone()));
-        us.push(PreparedUpdateEntry::Log(logentry));
-      }
-
-      let update = PreparedUpdate { gen, us, };
-      let update = Arc::new(update);
-      eprintln!("UPDATE {:?}", &update);
-
-      for (_tplayer, tplupdates) in &mut g.updates {
-        tplupdates.log.push_back(update.clone());
-        tplupdates.cv.notify_all();
-      }
-      eprintln!("API {:?} OK", &form);
-    }
-  }
-  ""
-}
-
-#[derive(Debug,Serialize,Deserialize)]
-struct ApiPieceGrab {
-}
-#[post("/_/api/grab", format="json", data="<form>")]
-#[throws(OE)]
-fn api_grab(form : Json<ApiPiece<ApiPieceGrab>>)
-            -> impl response::Responder<'static> {
-  api_piece_op(form)
-}
-impl ApiPieceOp for ApiPieceGrab {
-  #[throws(GameError)]
-  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
-        lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
-    let pl = gs.players.byid(player).unwrap();
-    let pc = gs.pieces.byid_mut(piece).unwrap();
-
-    if pc.held.is_some() { Err(GameError::PieceHeld)? }
-    pc.held = Some(player);
-    
-    let update = PieceUpdateOp::Modify(());
-
-    let logent = LogEntry {
-      html : format!("{} grasped {}",
-                     &htmlescape::encode_minimal(&pl.nick),
-                     pc.describe_html(&lens.log_pri(piece, pc))),
-    };
-
-    (update, vec![logent])
-  }
-}
-
-#[derive(Debug,Serialize,Deserialize)]
-struct ApiPieceUngrab {
-}
-#[post("/_/api/ungrab", format="json", data="<form>")]
-#[throws(OE)]
-fn api_ungrab(form : Json<ApiPiece<ApiPieceUngrab>>)
-              -> impl response::Responder<'static> {
-  api_piece_op(form)
-}
-impl ApiPieceOp for ApiPieceUngrab {
-  #[throws(GameError)]
-  fn op(&self, gs: &mut GameState, player: PlayerId, piece: PieceId,
-        lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
-    let pl = gs.players.byid(player).unwrap();
-    let pc = gs.pieces.byid_mut(piece).unwrap();
-
-    if pc.held != Some(player) { Err(GameError::PieceHeld)? }
-    pc.held = None;
-    
-    let update = PieceUpdateOp::Modify(());
-
-    let logent = LogEntry {
-      html : format!("{} released {}",
-                     &htmlescape::encode_minimal(&pl.nick),
-                     pc.describe_html(&lens.log_pri(piece, pc))),
-    };
-
-    (update, vec![logent])
-  }
-}
-
-#[derive(Debug,Serialize,Deserialize)]
-struct ApiPieceRaise {
-  z : ZCoord,
-}
-#[post("/_/api/setz", format="json", data="<form>")]
-#[throws(OE)]
-fn api_raise(form : Json<ApiPiece<ApiPieceRaise>>)
-            -> impl response::Responder<'static> {
-  api_piece_op(form)
-}
-impl ApiPieceOp for ApiPieceRaise {
-  #[throws(GameError)]
-  fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
-        _: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
-    let pc = gs.pieces.byid_mut(piece).unwrap();
-    pc.zlevel = ZLevel { z : self.z, zg : gs.gen };
-    let update = PieceUpdateOp::SetZLevel(pc.zlevel);
-    (update, vec![])
-  }
-}
-
-#[derive(Debug,Serialize,Deserialize)]
-struct ApiPieceMove (Pos);
-#[post("/_/api/m", format="json", data="<form>")]
-#[throws(OE)]
-fn api_move(form : Json<ApiPiece<ApiPieceMove>>) -> impl response::Responder<'static> {
-  api_piece_op(form)
-}
-impl ApiPieceOp for ApiPieceMove {
-  #[throws(GameError)]
-  fn op(&self, gs: &mut GameState, _: PlayerId, piece: PieceId,
-        _lens: &dyn Lens)
-        -> (PieceUpdateOp<()>, Vec<LogEntry>) {
-    let pc = gs.pieces.byid_mut(piece).unwrap();
-
-    pc.pos = self.0;
-    let update = PieceUpdateOp::Move(self.0);
-    (update, vec![])
-  }
-}
-
 #[get("/_/updates/<ctoken>/<gen>")]
 #[throws(OE)]
 fn updates(ctoken : InstanceAccess<ClientId>, gen: u64)
@@ -403,19 +76,15 @@ fn main() {
     .enable(Frame::Deny)
     .enable(Referrer::NoReferrer);
 
-  rocket::ignite()
+  let mut r = rocket::ignite()
     .attach(helmet)
     .attach(Template::fairing())
     .mount("/", routes![
       index,
       loading,
-      session,
       resource,
       updates,
-      api_grab,
-      api_ungrab,
-      api_raise,
-      api_move,
-    ])
-    .launch();
+    ]);
+  game::session::mount(&mut r);
+  r.launch();
 }
index 29c85bdf3f4819f6e8f071b92d2444c78ebdc051..3478217c6dafe74fe328c79e27bda765465702bb 100644 (file)
@@ -98,15 +98,6 @@ pub struct PieceRecord {
   pub gen_before_lastclient : Generation,
 }
 
-#[derive(Debug,Serialize)]
-pub struct PreparedPieceState {
-  pub pos : Pos,
-  pub svg : String,
-  pub held : Option<PlayerId>,
-  pub z : ZCoord,
-  pub zg : Generation,
-}
-
 impl PieceRecord {
   pub fn make_defs(&self, pri : &PieceRenderInstructions) -> String {
     let pr = self;
index 39c45871143e1fcdd6199eeb25d0466b4f69f964..123d313c7d49dc342b7ad3d4311d9b2ffa852d68 100644 (file)
@@ -18,98 +18,6 @@ pub struct Client {
   pub player : PlayerId,
 }
 
-#[derive(Debug)]
-pub struct PreparedUpdate {
-  pub gen : Generation,
-  pub us : Vec<PreparedUpdateEntry>,
-}
-#[derive(Debug)]
-pub enum PreparedUpdateEntry {
-  Piece {
-    client : ClientId,
-    sameclient_cseq : ClientSequence,
-    piece : VisiblePieceId,
-    op : PieceUpdateOp<PreparedPieceState>,
-  },
-  Log (Arc<LogEntry>),
-}
-impl PreparedUpdateEntry {
-  pub fn json_len(&self) -> usize {
-    use PreparedUpdateEntry::*;
-    match self {
-      Piece { ref op, .. } => {
-        50 +
-        op.new_state().map(|x| x.svg.len()).unwrap_or(0)
-      },
-      Log(logent) => {
-        logent.html.as_bytes().len() * 3
-      }
-    }
-  }
-}
-impl PreparedUpdate {
-  pub fn json_len(&self) -> usize {
-    self.us.iter().map(|u| 20 + u.json_len()).sum()
-  }
-}
-
-#[derive(Debug,Serialize)]
-pub enum PieceUpdateOp<NS> {
-  Delete(),
-  Insert(NS),
-  Modify(NS),
-  Move(Pos),
-  SetZLevel(ZLevel),
-}
-impl<NS> PieceUpdateOp<NS> {
-  pub fn new_state(&self) -> Option<&NS> {
-    use PieceUpdateOp::*;
-    match self {
-      Delete() => None,
-      Insert(ns) => Some(ns),
-      Modify(ns) => Some(ns),
-      Move(_) => None,
-      SetZLevel(_) => None,
-    }
-  }
-  pub fn map_new_state<NS2,F: FnOnce(NS) -> NS2>(self, f:F)
-                            -> PieceUpdateOp<NS2> {
-    use PieceUpdateOp::*;
-    match self {
-      Delete() => Delete(),
-      Insert(ns) => Insert(f(ns)),
-      Modify(ns) => Modify(f(ns)),
-      Move(pos) => Move(pos),
-      SetZLevel(zl) => SetZLevel(zl),
-    }
-  }
-  pub fn new_z_generation(&self) -> Option<Generation> {
-    use PieceUpdateOp::*;
-    match self {
-      Delete() => None,
-      Insert(_) => None,
-      Modify(_) => None,
-      Move(_) => None,
-      SetZLevel(ZLevel{zg,..}) => Some(*zg),
-    }
-  }
-}
-
-#[derive(Debug)]
-pub struct PlayerUpdates {
-  pub log : StableIndexVecDeque<Arc<PreparedUpdate>,sse::UpdateId>,
-  pub cv : Arc<Condvar>,
-}
-
-const RECENT_BUFFER : usize = 50;
-
-impl Default for PlayerUpdates {
-  fn default() -> PlayerUpdates { PlayerUpdates {
-    log : StableIndexVecDeque::with_capacity(RECENT_BUFFER),
-    cv : Default::default(),
-  } }
-}
-
 #[derive(Debug)]
 pub struct Instance {
   pub gs : GameState,
index 50f4b5c3854dee1a1284536925b7f3d2dc64df9c..ec31f2a2258a862fc12c3944e0427d4f27d3cc71 100644 (file)
@@ -1,6 +1,9 @@
 
-use rocket::request::Request;
-use rocket::response::{Response,Responder};
+pub use rocket::request::Request;
+pub use rocket::response::{Response,Responder};
+pub use rocket::post;
+pub use rocket_contrib::json::Json;
+pub use rocket::http::Status;
 
 use crate::imports::*;
 
index 8089436545eab22a45c0b108101a4c0bddf74618..a1fd14abc28aa75ee0ca7d7ce7fb0e5e3effcded 100644 (file)
@@ -28,8 +28,8 @@ pub use serde::Serializer;
 pub use rocket_contrib::helmet::*;
 pub use rocket_contrib::templates::Template;
 
-pub use rocket::State;
-pub use rocket::http::{Status,RawStr,ContentType};
+pub use rocket::{State,Rocket};
+pub use rocket::http::{RawStr,ContentType};
 pub use rocket::request::{FromParam,FromRequest,FromFormValue,LenientForm};
 pub use rocket::response::NamedFile;
 pub use rocket::response;
index 3c365e958426ea02c06eeeb951a019115b707b60..130102392820a2c9352c10b3f897f323c1c494b8 100644 (file)
@@ -1,4 +1,6 @@
 
+#![feature(proc_macro_hygiene, decl_macro)]
+
 pub mod imports;
 pub mod global;
 pub mod pieces;
@@ -8,3 +10,5 @@ pub mod updates;
 pub mod sse;
 pub mod error;
 pub mod http;
+pub mod session;
+pub mod api;
diff --git a/src/session.rs b/src/session.rs
new file mode 100644 (file)
index 0000000..7b37d38
--- /dev/null
@@ -0,0 +1,96 @@
+
+use crate::imports::*;
+use crate::http::*;
+
+#[derive(Serialize,Debug)]
+struct SessionRenderContext {
+  ctoken : String,
+  player : PlayerId,
+  gen : Generation,
+  uses : Vec<SessionPieceContext>,
+  defs : Vec<(VisiblePieceId,String)>,
+  nick : String,
+}
+
+#[derive(Serialize,Debug)]
+struct SessionPieceContext {
+  id: VisiblePieceId,
+  pos: Pos,
+  info: String,
+}
+
+#[derive(Serialize,Debug)]
+struct SessionPieceLoadJson<'r> {
+  held : &'r Option<PlayerId>,
+  z : ZCoord,
+  zg : Generation,
+}
+
+#[derive(Deserialize)]
+struct SessionForm {
+  ptoken : String,
+}
+#[post("/_/session", format="json", data="<form>")]
+fn session(form : Json<SessionForm>) -> Result<Template,OE> {
+  // make session in this game, log a message to other players
+  let iad = lookup_token(&form.ptoken)?;
+  let player = iad.ident;
+  let c = {
+    let mut ig = iad.g.lock()?;
+    let ig = &mut *ig;
+    let pl = ig.gs.players.byid_mut(player)?;
+    let cl = Client { player };
+    let client = ig.clients.insert(cl);
+
+    let ciad = InstanceAccessDetails {
+      g : iad.g.clone(),
+      ident : client,
+    };
+    let ctoken = record_token(ciad);
+
+    let mut uses = vec![];
+    let mut alldefs = vec![];
+
+    let mut pieces : Vec<_> = ig.gs.pieces.iter().collect();
+
+    pieces.sort_by_key(|(_,pr)| &pr.zlevel);
+
+    for (gpid, pr) in pieces {
+      let pri = PieceRenderInstructions {
+        id : make_pieceid_visible(gpid),
+        face : pr.face,
+      };
+      let defs = pr.make_defs(&pri);
+      alldefs.push((pri.id, defs));
+
+      let for_info = SessionPieceLoadJson {
+        held : &pr.held,
+        z  : pr.zlevel.z,
+        zg : pr.zlevel.zg,
+      };
+
+      let for_piece = SessionPieceContext {
+        id: pri.id,
+        pos : pr.pos,
+        info : serde_json::to_string(&for_info)?,
+      };
+      uses.push(for_piece);
+    }
+
+    let src = SessionRenderContext {
+      ctoken : ctoken.0,
+      gen : ig.gs.gen,
+      player,
+      defs : alldefs,
+      uses,
+      nick : pl.nick.clone(),
+    };
+    eprintln!("SRC {:?}", &src);
+    src
+  };
+  Ok(Template::render("session",&c))
+}
+
+pub fn mount(_rocket_instance: &mut Rocket) {
+  //rocket_instance.mount(&session);  xxx
+}
index fe2b43b3a80a2943e47316bb1ade39943a9049b1..0b566389ca56138a5dab48b55263a11d330b8489 100644 (file)
@@ -148,72 +148,6 @@ impl Read for UpdateReader {
   }
 }
 
-    /*
-    loop {
-                    e
-      let send_from = (||{
-        let l = self.updates.len();
-        let last_probe = match updates.last() {
-          None => return None,
-          Some(&now) if self.last_sent > now.gen => return l+1,
-          _ => l,
-        };
-        let (lo, hi /* half-open */) = loop {
-          let depth = l - last_probe;
-          depth *= 2;
-          if depth > l { break (0, last_probe) }
-          let probe = l - depth;
-          let here = updates[probe];
-          if here.gen < l 
-
-        if let Some(&now) =  {
-          if  { return None }
-        }
-        let probe = inst.updates.len() - 1;
-        let (lo, hi) = loop {
-          if search == 0 { break }
-          search -= 1;
-          tu = inst.updates[search];
-          if 
-
-        let lo = 0;
-        
-      };
-    loop {
-         implement this! 
-    }
-    for (tclient, tcl) in &mut g.clients {
-      if tclient == client {
-        tcl.transmit_update(&Update {
-          gen,
-          u : UpdatePayload::ClientSequence(piece, form.s),
-        });
-      } else {
-        tcl.transmit_update(&update);
-      }          
-    }
-     */
-/*
-
-    thread::sleep(Duration::from_millis(500));
-    let message = XUpdate::TestCounter { value : self.next };
-    let data = serde_json::to_string(&message)?;
-    let data = format!("data: {}\n\n", &data);
-    // eprintln!("want to return into &[;{}] {:?}", buf.len(), &data);
-    self.next += 1;
-    buf[0..data.len()].copy_from_slice(data.as_bytes());
-    Ok(buf.len())
-  }
-}*/
-
-/*
-#[derive(Deserialize)]
-struct APIForm {
-  t : String,
-  c : ClientId,
-}
- */
-
 #[derive(Debug)]
 pub struct DebugReader<T : Read>(pub T);
 
index 0d1b6d8a49197268db101862c59046e78317c0ff..20a94a2b6fba47d2c35edf5bebf99b122183642b 100644 (file)
 
+// update messages from server to client
+
 use crate::imports::*;
 
 #[derive(Debug,Copy,Clone,Eq,PartialEq,Deserialize,Serialize)]
 #[serde(transparent)]
 pub struct ClientSequence(u64);
-/*
-#[derive(Debug,Serialize)]
-pub struct Update {
+
+#[derive(Debug)]
+pub struct PreparedUpdate {
   pub gen : Generation,
-  pub u : UpdatePayload,
+  pub us : Vec<PreparedUpdateEntry>,
+}
+#[derive(Debug)]
+pub enum PreparedUpdateEntry {
+  Piece {
+    client : ClientId,
+    sameclient_cseq : ClientSequence,
+    piece : VisiblePieceId,
+    op : PieceUpdateOp<PreparedPieceState>,
+  },
+  Log (Arc<LogEntry>),
+}
+impl PreparedUpdateEntry {
+  pub fn json_len(&self) -> usize {
+    use PreparedUpdateEntry::*;
+    match self {
+      Piece { ref op, .. } => {
+        50 +
+        op.new_state().map(|x| x.svg.len()).unwrap_or(0)
+      },
+      Log(logent) => {
+        logent.html.as_bytes().len() * 3
+      }
+    }
+  }
+}
+impl PreparedUpdate {
+  pub fn json_len(&self) -> usize {
+    self.us.iter().map(|u| 20 + u.json_len()).sum()
+  }
+}
+
+#[derive(Debug,Serialize)]
+pub enum PieceUpdateOp<NS> {
+  Delete(),
+  Insert(NS),
+  Modify(NS),
+  Move(Pos),
+  SetZLevel(ZLevel),
+}
+impl<NS> PieceUpdateOp<NS> {
+  pub fn new_state(&self) -> Option<&NS> {
+    use PieceUpdateOp::*;
+    match self {
+      Delete() => None,
+      Insert(ns) => Some(ns),
+      Modify(ns) => Some(ns),
+      Move(_) => None,
+      SetZLevel(_) => None,
+    }
+  }
+  pub fn map_new_state<NS2,F: FnOnce(NS) -> NS2>(self, f:F)
+                            -> PieceUpdateOp<NS2> {
+    use PieceUpdateOp::*;
+    match self {
+      Delete() => Delete(),
+      Insert(ns) => Insert(f(ns)),
+      Modify(ns) => Modify(f(ns)),
+      Move(pos) => Move(pos),
+      SetZLevel(zl) => SetZLevel(zl),
+    }
+  }
+  pub fn new_z_generation(&self) -> Option<Generation> {
+    use PieceUpdateOp::*;
+    match self {
+      Delete() => None,
+      Insert(_) => None,
+      Modify(_) => None,
+      Move(_) => None,
+      SetZLevel(ZLevel{zg,..}) => Some(*zg),
+    }
+  }
+}
+
+#[derive(Debug)]
+pub struct PlayerUpdates {
+  pub log : StableIndexVecDeque<Arc<PreparedUpdate>,sse::UpdateId>,
+  pub cv : Arc<Condvar>,
+}
+
+const RECENT_BUFFER : usize = 50;
+
+impl Default for PlayerUpdates {
+  fn default() -> PlayerUpdates { PlayerUpdates {
+    log : StableIndexVecDeque::with_capacity(RECENT_BUFFER),
+    cv : Default::default(),
+  } }
 }
 
 #[derive(Debug,Serialize)]
-pub enum PieceUpdate {
+pub struct PreparedPieceState {
+  pub pos : Pos,
+  pub svg : String,
+  pub held : Option<PlayerId>,
+  pub z : ZCoord,
+  pub zg : Generation,
 }
-*/