chiark / gitweb /
wip format timestamps
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 14 Oct 2020 22:12:49 +0000 (23:12 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 14 Oct 2020 22:12:49 +0000 (23:12 +0100)
Before try into

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Cargo.lock.example
Cargo.toml
src/cmdlistener.rs
src/gamestate.rs
src/global.rs
src/imports.rs
src/sse.rs
src/updates.rs
templates/script.ts

index 7d8c4cfabebe95ac71145549b673fd913c57f517..28229ab7b3865ec40cb4ef71183328104c63ebf9 100644 (file)
@@ -1057,6 +1057,7 @@ dependencies = [
  "rocket_cors",
  "serde",
  "serde_json",
+ "serde_with",
  "slotmap",
  "thiserror",
  "toml 0.5.6",
index 99dd5c51977b6f7432ee604c1ce62de29adb42a7..7a45ae70788dd8cdb65289131e7b05cdb8206649 100644 (file)
@@ -46,6 +46,7 @@ rmp-serde = "0.14"
 rocket_cors = "0.5"
 serde = { version = "1", features = ["derive","rc"] }
 serde_json = "1"
+serde_with = "1"
 slotmap = { version = "0.4", features = ['serde'] }
 thiserror = "1"
 toml = "0.5"
index 47a7d69864bb89f9e23cddb48679434a0bf88e5b..6bad6eaeb1651d96ebb7955f3cb9d68bcacbb74d 100644 (file)
@@ -166,7 +166,7 @@ fn execute_game_insn(cs: &CommandStream,
         html: Html(format!("{} added a player: {}", &who,
                       htmlescape::encode_minimal(&pl.nick))),
       };
-      let (player, logentry) = ig.player_new(pl, logentry)?;
+      let (player, logentry) = ig.player_new(pl, Timezone{}, logentry)?;
       (U{ pcs: vec![],
           log: vec![ logentry ],
           raw: None },
index 340aac71dd8c3098f7bcfb4bbda73de4edca7396..db536c7c5091b812261637861c6e9339c4e20318 100644 (file)
@@ -27,6 +27,9 @@ pub struct Html (pub String);
 #[serde(transparent)]
 pub struct Timestamp(pub u64); /* time_t */
 
+#[derive(Clone,Debug,Default,Serialize,Deserialize)]
+pub struct Timezone { } // todo
+
 pub const DEFAULT_TABLE_SIZE : Pos = PosC([ 400, 200 ]);
 
 // ---------- general data types ----------
@@ -169,6 +172,10 @@ impl Timestamp {
       .as_secs();
     Timestamp(now)
   }
+
+  pub fn render(&self, tz: &Timezone) -> String {
+    format!("TS{}(@{:?})", self.0, tz)
+  }
 }
 
 pub trait ClampTable : Sized {
index 3bb351418ee1b3d80f4c31d052de112a005f185d..ba335682b4ecfbc1b516c5fee943e55225b6ed86 100644 (file)
@@ -193,6 +193,12 @@ pub struct InstanceContainer {
 struct InstanceSaveAccesses<RawTokenStr, PiecesLoadedRef> {
   pieces: PiecesLoadedRef,
   tokens_players: Vec<(RawTokenStr, PlayerId)>,
+  aplayers: SecondarySlotMap<PlayerId, PlayerSaveAccess>,
+}
+
+#[derive(Debug,Default,Serialize,Deserialize)]
+struct PlayerSaveAccess {
+  tz: Timezone,
 }
 
 display_as_debug!{InstanceLockError}
@@ -352,7 +358,7 @@ impl InstanceGuard<'_> {
   /// caller is responsible for logging; threading it through
   /// proves the caller has a log entry.
   #[throws(MgmtError)]
-  pub fn player_new(&mut self, newplayer: PlayerState,
+  pub fn player_new(&mut self, newplayer: PlayerState, tz: Timezone,
                     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
@@ -366,7 +372,7 @@ impl InstanceGuard<'_> {
     })?;
     (||{
       let pu_bc = PlayerUpdates::new_begin(&self.c.g.gs);
-      self.c.g.updates.insert(player, pu_bc.new());
+      self.c.g.updates.insert(player, pu_bc.new(tz));
     })(); // <- No ?, ensures that IEFE is infallible (barring panics)
     (player, logentry)
   }
@@ -685,7 +691,11 @@ impl InstanceGuard<'_> {
           .flatten()
           .collect()
       };
-      let isa = InstanceSaveAccesses { pieces, tokens_players };
+      let aplayers = s.c.g.updates.iter().map(
+        |(player, PlayerUpdates { tz, .. })|
+        (player, PlayerSaveAccess { tz: tz.clone() })
+      ).collect();
+      let isa = InstanceSaveAccesses { pieces, tokens_players, aplayers };
       rmp_serde::encode::write_named(w, &isa)
     })?;
     self.c.access_dirty = false;
@@ -718,7 +728,8 @@ impl InstanceGuard<'_> {
       }
     }
     let InstanceSaveAccesses::<String,ActualPiecesLoaded>
-    { mut tokens_players, mut pieces } = Self::load_something(&name, "a-")
+    { mut tokens_players, mut pieces, mut aplayers }
+    = Self::load_something(&name, "a-")
       .or_else(|e| {
         if let InternalError::Anyhow(ae) = &e {
           if let Some(ioe) = ae.downcast_ref::<io::Error>() {
@@ -744,7 +755,8 @@ impl InstanceGuard<'_> {
     let mut updates : SecondarySlotMap<_,_> = Default::default();
     let pu_bc = PlayerUpdates::new_begin(&gs);
     for player in gs.players.keys() {
-      updates.insert(player, pu_bc.new());
+      let aplayer = aplayers.remove(player).unwrap_or_default();
+      updates.insert(player, pu_bc.new(aplayer.tz));
     }
     let name = Arc::new(name);
     tokens_players.retain(
index 155adc52c959ccbf1db2d5f1ab59f9d25f5c79fa..e86d19897040a6c607521676d09087345576befc 100644 (file)
@@ -41,6 +41,7 @@ pub use fehler::{throws,throw};
 
 pub use serde::{Serialize,Deserialize,de::DeserializeOwned};
 pub use serde::{Serializer,Deserializer};
+pub use serde::ser::SerializeTuple;
 
 pub use rocket_contrib::helmet::*;
 pub use rocket_contrib::templates::Template;
@@ -93,6 +94,9 @@ pub use itertools::Itertools;
 pub use rental::RentalError;
 pub use rental::common::RentRef;
 
+pub use serde_with;
+pub use serde_with::serde_as;
+
 pub use ordered_float::OrderedFloat;
 
 pub use crate::global::*;
index 8af08b0af7e5cbcfde332056496bfe6ee173bd2a..4910ff900e413044ef6c3782306b29e8be1c40e7 100644 (file)
@@ -48,9 +48,10 @@ struct FlushWouldBlockError{}
 
 impl UpdateReaderWN {
   #[throws(io::Error)]
-  fn write_next<U>(&mut self, mut buf: &mut U, next: &PreparedUpdate)
+  fn write_next<U>(&mut self, mut buf: &mut U, tz: &Timezone,
+                   next: &PreparedUpdate)
                    where U : Write {
-    let tu = next.for_transmit(self.client);
+    let tu = next.for_transmit(tz, self.client);
 
     write!(buf, "data: ")?;
     serde_json::to_writer(&mut buf, &tu)?;
@@ -123,7 +124,7 @@ impl Read for UpdateReader {
         }
         self.overflow = {
           let mut overflow = Vec::with_capacity(next_len);
-          self.wn.write_next(&mut overflow, &next)
+          self.wn.write_next(&mut overflow, &pu.tz, &next)
             .map_err(|e| self.wn.trouble("overflow.write_next",&e))?;
           debug!("overflow {} {}, len={}",
                  &self.wn.player, &self.wn.client, &overflow.len());
@@ -132,7 +133,7 @@ impl Read for UpdateReader {
         continue;
       }
 
-      self.wn.write_next(&mut buf, &next)
+      self.wn.write_next(&mut buf, &pu.tz, &next)
         .map_err(|e| self.wn.trouble("UpdateReader.write_next",&e))?;
 
       let before = next.when - UPDATE_EXPIRE;
index 11df724f77dc26f9620c462f462f863d37173ddf..e5e5c4919789f43373929d5e17942bfd800b4317 100644 (file)
@@ -30,6 +30,7 @@ pub type PlayerUpdatesLog =
 pub struct PlayerUpdates {
   log : PlayerUpdatesLog,
   cv : Arc<Condvar>,
+  pub tz: Timezone,
 }
 
 #[derive(Debug)]
@@ -103,7 +104,8 @@ enum TransmitUpdateEntry<'u> {
     ns: &'u PreparedPieceState,
   },
   SetTableSize(Pos),
-  Log (&'u CommittedLogEntry),
+  #[serde(serialize_with="serialize_logentry")]
+  Log (&'u Timezone, &'u CommittedLogEntry),
   Error(&'u ErrorSignaledViaUpdate),
 }
 
@@ -117,11 +119,11 @@ pub struct PlayerUpdatesBuildContext {
 }
 
 impl PlayerUpdatesBuildContext {
-  pub fn new(&self) -> PlayerUpdates {
+  pub fn new(&self, tz: Timezone) -> PlayerUpdates {
     let mut log = StableIndexVecDeque::with_capacity(50);
     log.push_back(self.u1.clone());
     let cv = Default::default();
-    PlayerUpdates { log, cv }
+    PlayerUpdates { log, tz, cv }
   }
 }
 
@@ -438,7 +440,8 @@ impl<'r> Drop for PrepareUpdatesBuffer<'r> {
 type WRC = WhatResponseToClientOp;
 
 impl PreparedUpdate {
-  pub fn for_transmit(&self, dest : ClientId) -> TransmitUpdate {
+  pub fn for_transmit<'u>(&'u self, tz: &'u Timezone, dest : ClientId)
+                      -> TransmitUpdate<'u> {
     type ESVU = ErrorSignaledViaUpdate;
     type PUE = PreparedUpdateEntry;
     type TUE<'u> = TransmitUpdateEntry<'u>;
@@ -477,7 +480,7 @@ impl PreparedUpdate {
           }
         },
         PUE::Log(logent) => {
-          TUE::Log(&logent)
+          TUE::Log(&tz, &logent)
         },
         &PUE::SetTableSize(size) => {
           TUE::SetTableSize(size)
@@ -498,3 +501,12 @@ impl PreparedUpdate {
     TransmitUpdate(self.gen, ents)
   }
 }
+
+fn serialize_logentry<S:Serializer>(tz: &Timezone, logent: &CommittedLogEntry,
+                                    s:S) -> Result<S::Ok, S::Error> {
+  let mut tup = s.serialize_tuple(2)?;
+  let ts = logent.when.render(&tz);
+  tup.serialize_element(&ts)?;
+  tup.serialize_element(&logent.logent)?;
+  tup.end()
+}
index 9f38f0a4c52002456ad2d1cb6e6124e9fa4b6ca3..b3efaeb62ac497c575089ae3118a20dcad8b2fe3 100644 (file)
@@ -778,7 +778,7 @@ function drag_cancel() {
 // ----- logs -----
 
 messages.Log = <MessageHandler>function
-(j: { when: Timestamp, logent: { html: string } }) {
+(j: { when: string, logent: { html: string } }) {
   add_log_message(j.when + '|' + j.logent.html);
 }