"rocket_cors",
"serde",
"serde_json",
+ "serde_with",
"slotmap",
"thiserror",
"toml 0.5.6",
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"
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 },
#[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 ----------
.as_secs();
Timestamp(now)
}
+
+ pub fn render(&self, tz: &Timezone) -> String {
+ format!("TS{}(@{:?})", self.0, tz)
+ }
}
pub trait ClampTable : Sized {
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}
/// 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
})?;
(||{
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)
}
.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;
}
}
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>() {
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(
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;
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::*;
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)?;
}
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());
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;
pub struct PlayerUpdates {
log : PlayerUpdatesLog,
cv : Arc<Condvar>,
+ pub tz: Timezone,
}
#[derive(Debug)]
ns: &'u PreparedPieceState,
},
SetTableSize(Pos),
- Log (&'u CommittedLogEntry),
+ #[serde(serialize_with="serialize_logentry")]
+ Log (&'u Timezone, &'u CommittedLogEntry),
Error(&'u ErrorSignaledViaUpdate),
}
}
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 }
}
}
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>;
}
},
PUE::Log(logent) => {
- TUE::Log(&logent)
+ TUE::Log(&tz, &logent)
},
&PUE::SetTableSize(size) => {
TUE::SetTableSize(size)
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()
+}
// ----- 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);
}