chiark / gitweb /
wip untangle
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 30 Dec 2020 11:11:25 +0000 (11:11 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 30 Dec 2020 11:11:25 +0000 (11:11 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
14 files changed:
Cargo.lock.example
Cargo.toml
daemon/api.rs [moved from src/api.rs with 82% similarity]
daemon/cmdlistener.rs [moved from src/cmdlistener.rs with 93% similarity]
daemon/main.rs
daemon/session.rs [moved from src/session.rs with 99% similarity]
src/accounts.rs
src/authproofs.rs [new file with mode: 0644]
src/error.rs
src/global.rs
src/imports.rs
src/lens.rs [new file with mode: 0644]
src/lib.rs
src/ui.rs [new file with mode: 0644]

index deb67a242d0fbdb02d430715d240538d5ac3646b..b9c9a462cad426d33e3e68c421bce48762b3a3d1 100644 (file)
@@ -1551,15 +1551,13 @@ dependencies = [
  "regex",
  "rmp",
  "rmp-serde 0.15.0",
- "rocket",
- "rocket_contrib",
- "rocket_cors",
  "serde",
  "serde_json",
  "serde_with",
  "slotmap",
  "strum",
  "tempfile",
+ "tera",
  "thiserror",
  "toml 0.5.8",
  "typetag",
index af19ac15b9d35402a0bf0c595da23e09679031d7..18f41a943c7b3cd45b4a6a7a66af167c9d00f0e2 100644 (file)
@@ -58,15 +58,8 @@ slotmap = { version = "0.4", features = ['serde'] }
 strum = { version = "0.20", features = ['derive'] }
 thiserror = "1"
 tempfile = "3"
+tera = "0.11"
 toml = "0.5"
 typetag = "0.1.6"
 uds = "0.2"
 vecdeque-stableix = "1"
-
-rocket = { version = "^0.4.6", features=["sse"] }
-rocket_cors = "0.5"
-
-[dependencies.rocket_contrib]
-version = "0.4"
-default-features = false
-features = ["tera_templates","helmet","json","serve"]
similarity index 82%
rename from src/api.rs
rename to daemon/api.rs
index 943edfa74a07ce0078fd13662e7601668125947e..fbaec774b84259372112836390a4b9d46f25c9cf 100644 (file)
@@ -2,46 +2,21 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // There is NO WARRANTY.
 
-use crate::imports::*;
+use super::*;
 
 type WRC = WhatResponseToClientOp;
 
-#[derive(Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize,EnumString)]
-pub enum PresentationLayout {
-  Portrait,
-  Landscape,
-}
-
 type PL = PresentationLayout;
 
-impl<'r> FromParam<'r> for PresentationLayout {
+pub struct AbbrevPresentationLayout(pub PresentationLayout);
+
+impl<'r> FromParam<'r> for AbbrevPresentationLayout {
   type Error = strum::ParseError;
   fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
-    param.as_str().parse()
+    AbbrevPresentationLayout(param.as_str().parse())
   }
 }
 
-impl PresentationLayout {
-  pub fn template(self) -> &'static str {
-    match self {
-      PL::Portrait => "session",
-      PL::Landscape => "landscape",
-    }
-  }
-  pub fn abbreviate_timestamps(self) -> bool {
-    match self {
-      PL::Portrait => false,
-      PL::Landscape => true,
-    }
-  }
-}
-
-impl Default for PresentationLayout {
-  fn default() -> Self { PL::Portrait }
-}
-
-pub struct AbbrevPresentationLayout(pub PresentationLayout);
-
 impl<'r> FromParam<'r> for AbbrevPresentationLayout {
   type Error = ();
   #[throws(Self::Error)]
@@ -54,6 +29,26 @@ impl<'r> FromParam<'r> for AbbrevPresentationLayout {
   }
 }
 
+#[derive(Clone,Debug)]
+pub struct InstanceAccess<'i, Id> {
+  pub raw_token: &'i RawTokenVal,
+  pub i: InstanceAccessDetails<Id>,
+}
+
+impl<'r, Id> FromFormValue<'r> for InstanceAccess<'r, Id>
+  where Id : AccessId, OE : From<Id::Error>
+{
+  type Error = OE;
+  #[throws(OE)]
+  fn from_form_value(param: &'r RawStr) -> Self {
+    let g = Id::global_tokens(PRIVATE_Y).read().unwrap();
+    let token = RawTokenVal::from_str(param.as_str());
+    let i = g.get(token).ok_or(Id::ERROR)?;
+    InstanceAccess { raw_token : token, i : i.clone() }
+  }
+}
+
+
 #[derive(Debug,Serialize,Deserialize)]
 struct ApiPiece<O : ApiPieceOp> {
   ctoken : RawToken,
@@ -83,57 +78,6 @@ trait ApiPieceOp : Debug {
   }
 }
 
-#[derive(Error,Debug)]
-pub enum ApiPieceOpError {
-  ReportViaResponse(#[from] OnlineError),
-  ReportViaUpdate(#[from] PieceOpError),
-  PartiallyProcessed(PieceOpError, Vec<LogEntry>),
-}
-display_as_debug!(ApiPieceOpError);
-
-impl From<PlayerNotFound> for ApiPieceOpError {
-  fn from(x: PlayerNotFound) -> ApiPieceOpError {
-    ApiPieceOpError::ReportViaResponse(x.into())
-  }
-}
-
-pub trait Lens : Debug {
-  fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId;
-  fn log_pri(&self, piece: PieceId, pc: &PieceState)
-             -> PieceRenderInstructions;
-  fn svg_pri(&self, piece: PieceId, pc: &PieceState, player: PlayerId)
-             -> PieceRenderInstructions;
-  fn massage_prep_piecestate(&self, ns : &mut PreparedPieceState);
-  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, player: PlayerId)
-                            -> PieceId;
-}
-#[derive(Debug)]
-pub struct TransparentLens {
-  // when lenses become nontrivial, make this nonconstructable
-  // to find all the places where a TransparentLens was bodged
-}
-impl Lens for TransparentLens {
-  fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId {
-    let kd : slotmap::KeyData = piece.into();
-    VisiblePieceId(kd)
-  }
-  fn log_pri(&self, piece: PieceId, pc: &PieceState)
-             -> PieceRenderInstructions {
-    let id = self.pieceid2visible(piece);
-    PieceRenderInstructions { id, face : pc.face }
-  }
-  fn svg_pri(&self, piece: PieceId, pc: &PieceState, _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) { }
-}
-
 impl From<&OnlineError> for rocket::http::Status {
   fn from(oe: &OnlineError) -> rocket::http::Status {
     use OnlineError::*;
similarity index 93%
rename from src/cmdlistener.rs
rename to daemon/cmdlistener.rs
index 892bc520138794d3f6d1e676326a072a1033289f..bb1ecec7865c1677901692384a618bb9e4ad782d 100644 (file)
@@ -4,7 +4,9 @@
 
 // management API implementation
 
-use crate::imports::*;
+use super::*;
+
+use authproofs::*;
 
 // ---------- newtypes, type aliases, basic definitions ----------
 
@@ -13,9 +15,6 @@ use std::os::unix::io::AsRawFd;
 use std::os::unix::net::UnixListener;
 use uds::UnixStreamExt;
 
-pub use crate::from_instance_lock_error;
-pub use std::os::unix::net::UnixStream;
-
 type SE = SpecError;
 type CSE = anyhow::Error;
 
@@ -23,7 +22,6 @@ use MgmtCommand::*;
 use MgmtResponse::*;
 
 type ME = MgmtError;
-from_instance_lock_error!{MgmtError}
 
 type AS = AccountScope;
 type TP = TablePermission;
@@ -34,8 +32,6 @@ const CREATE_PIECES_MAX: u32 = 300;
 const DEFAULT_POS_START: Pos = PosC([20,20]);
 const DEFAULT_POS_DELTA: Pos = PosC([5,5]);
 
-pub type AuthorisationSuperuser = Authorisation<authproofs::Global>;
-
 pub struct CommandListener {
   listener: UnixListener,
 }
@@ -156,7 +152,7 @@ fn execute(cs: &mut CommandStream, cmd: MgmtCommand) -> MgmtResponse {
       let mut games = games_lock();
       let auth = authorise_by_account(cs, &ag, &game)?;
 
-      let gs = crate::gamestate::GameState {
+      let gs = otter::gamestate::GameState {
         table_colour: Html::lit("green"),
         table_size: DEFAULT_TABLE_SIZE,
         pieces: default(),
@@ -908,6 +904,12 @@ impl CommandListener {
 #[error("connection euid lookup failed (at connection initiation): {0}")]
 pub struct ConnectionEuidDiscoverEerror(String);
 
+impl From<ConnectionEuidDiscoverEerror> for AuthorisationError {
+  fn from(e: ConnectionEuidDiscoverEerror) -> AuthorisationError {
+    AuthorisationError(format!("{}", e))
+  }
+}
+
 impl CommandStream<'_> {
   #[throws(AuthorisationError)]
   fn authorised_uid(&self, wanted: Option<Uid>, xinfo: Option<&str>)
@@ -1172,87 +1174,3 @@ fn do_authorise_scope(cs: &CommandStream, wanted: &AccountScope)
 
   }
 }
-
-use authproofs::*;
-use authproofs::AuthorisationError;
-
-pub use authproofs::Authorisation;
-pub use authproofs::Unauthorised;
-
-mod authproofs {
-  use crate::imports::*;
-
-  #[derive(Copy,Clone,Debug)]
-  pub struct Global;
-
-  #[derive(Debug,Copy,Clone)]
-  pub struct Unauthorised<T,A> (T, PhantomData<A>);
-  impl<T,A> Unauthorised<T,A> {
-    pub fn of(t: T) -> Self { Unauthorised(t, PhantomData) }
-    pub fn by(self, _auth: Authorisation<A>) -> T { self.0 }
-    pub fn by_ref(&self,     _auth: Authorisation<A>) -> &    T { &    self.0 }
-    pub fn by_mut(&mut self, _auth: Authorisation<A>) -> &mut T { &mut self.0 }
-  }
-  impl<T,A> From<T> for Unauthorised<T,A> {
-    fn from(t: T) -> Self { Self::of(t) }
-  }
-
-  #[derive(Error,Debug)]
-  #[error("internal AuthorisationError {0}")]
-  pub struct AuthorisationError(pub String);
-
-  #[derive(Debug)]
-  pub struct Authorisation<A> (PhantomData<*const A>);
-  impl<A> Clone for Authorisation<A> { fn clone(&self) -> Self { *self } }
-  impl<A> Copy for Authorisation<A> { }
-
-  impl<T> Authorisation<T> {
-    pub const fn authorised(_v: &T) -> Authorisation<T> {
-      Authorisation(PhantomData)
-    }
-    pub fn map<U>(self, _f: fn(&T) -> &U) -> Authorisation<U> {
-      self.therefore_ok()
-    }
-    pub fn therefore_ok<U>(self) -> Authorisation<U> {
-      Authorisation(PhantomData)
-    }
-    pub const fn authorise_any() -> Authorisation<T> {
-      Authorisation(PhantomData)
-    }
-  }
-
-  impl<T:Serialize> From<Authorisation<Global>> for Authorisation<T> {
-    // ^ we need a bound not met by Global or we conflict with From<T> for T
-    fn from(global: Authorisation<Global>) -> Self {
-      global.therefore_ok()
-    }
-  }
-
-  impl From<anyhow::Error> for AuthorisationError {
-    fn from(a: anyhow::Error) -> AuthorisationError {
-      AuthorisationError(format!("{}", a))
-    }
-  }
-  impl From<ConnectionEuidDiscoverEerror> for AuthorisationError {
-    fn from(e: ConnectionEuidDiscoverEerror) -> AuthorisationError {
-      AuthorisationError(format!("{}", e))
-    }
-  }
-
-  pub trait AuthorisationCombine: Sized {
-    type Output;
-    fn combine(self) -> Authorisation<Self::Output> {
-      Authorisation(PhantomData)
-    }
-  }
-  impl<A,B> AuthorisationCombine
-    for (Authorisation<A>, Authorisation<B>) {
-    type Output = (A, B);
-  }
-  impl<A,B,C> AuthorisationCombine
-    for (Authorisation<A>, Authorisation<B>, Authorisation<C>) {
-    type Output = (A, B, C);
-  }
-}
-
-
index 7626d799948e893a5108af92c36f2bce07b0447b..23730617624c0818cad965bda24dd2fb6b6807b2 100644 (file)
@@ -4,8 +4,30 @@
 
 #![feature(proc_macro_hygiene, decl_macro)]
 
+pub mod api;
+pub mod cmdlistener;
+pub mod session;
+
+pub use rocket::http::Status;
+pub use rocket::http::{ContentType, RawStr};
+pub use rocket::request::Request;
+pub use rocket::request::{FromFormValue, FromParam, FromRequest, LenientForm};
+pub use rocket::response;
+pub use rocket::response::NamedFile;
+pub use rocket::response::{Responder, Response};
+pub use rocket::{get, post, routes};
+pub use rocket::{Rocket, State};
+pub use rocket_contrib::helmet::*;
+pub use rocket_contrib::json::Json;
+pub use rocket_contrib::templates::tera::{self, Value};
+pub use rocket_contrib::templates::Engines;
+pub use rocket_contrib::templates::Template;
+
+pub use crate::api::{AbbrevPresentationLayout};
+pub use crate::api::{ApiPieceOpError, Lens, TransparentLens};
+pub use crate::cmdlistener::*;
+
 use rocket::fairing;
-use rocket::{get, routes};
 use rocket::response::Content;
 use rocket_contrib::serve::StaticFiles;
 
@@ -295,8 +317,8 @@ fn main() {
     r = r.attach(ReportStartup);
   }
 
-  let r = otter::session::mount(r);
-  let r = otter::api::mount(r);
+  let r = crate::session::mount(r);
+  let r = crate::api::mount(r);
 
   thread::spawn(client_periodic_expiry);
   thread::spawn(logs_periodic_expiry);
similarity index 99%
rename from src/session.rs
rename to daemon/session.rs
index 9ed70cf098960032877077f32b5d250af8b927ba..db515a201d1e62ed5b5a499666500392956137dc 100644 (file)
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 // There is NO WARRANTY.
 
-use crate::imports::*;
+use super::*;
 
 #[derive(Serialize,Debug)]
 struct SessionRenderContext {
index 38fa32aa7f640cea79d8b4d9248f051e37723808..1ede9b9c7b905faefce6f3a61d67c4240a862c60 100644 (file)
@@ -6,6 +6,8 @@ use crate::imports::*;
 
 use parking_lot::{Mutex, const_mutex, MutexGuard};
 
+use authproofs::*;
+
 //---------- simple types ----------
 
 slotmap::new_key_type!{
@@ -433,6 +435,7 @@ pub fn load_accounts() {
 
 pub mod loaded_acl {
   use crate::imports::*;
+  use authproofs::*;
 
   pub trait Perm : FromPrimitive + ToPrimitive +
     Copy + Eq + Hash + Sync + Send + 'static
diff --git a/src/authproofs.rs b/src/authproofs.rs
new file mode 100644 (file)
index 0000000..c472838
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright 2020 Ian Jackson
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use crate::imports::*;
+
+#[derive(Copy,Clone,Debug)]
+pub struct Global;
+
+#[derive(Debug,Copy,Clone)]
+pub struct Unauthorised<T,A> (T, PhantomData<A>);
+impl<T,A> Unauthorised<T,A> {
+  pub fn of(t: T) -> Self { Unauthorised(t, PhantomData) }
+  pub fn by(self, _auth: Authorisation<A>) -> T { self.0 }
+  pub fn by_ref(&self,     _auth: Authorisation<A>) -> &    T { &    self.0 }
+  pub fn by_mut(&mut self, _auth: Authorisation<A>) -> &mut T { &mut self.0 }
+}
+impl<T,A> From<T> for Unauthorised<T,A> {
+  fn from(t: T) -> Self { Self::of(t) }
+}
+
+#[derive(Error,Debug)]
+#[error("internal AuthorisationError {0}")]
+pub struct AuthorisationError(pub String);
+
+#[derive(Debug)]
+pub struct Authorisation<A> (PhantomData<*const A>);
+impl<A> Clone for Authorisation<A> { fn clone(&self) -> Self { *self } }
+impl<A> Copy for Authorisation<A> { }
+
+pub type AuthorisationSuperuser = Authorisation<Global>;
+
+impl<T> Authorisation<T> {
+  pub const fn authorised(_v: &T) -> Authorisation<T> {
+    Authorisation(PhantomData)
+  }
+  pub fn map<U>(self, _f: fn(&T) -> &U) -> Authorisation<U> {
+    self.therefore_ok()
+  }
+  pub fn therefore_ok<U>(self) -> Authorisation<U> {
+    Authorisation(PhantomData)
+  }
+  pub const fn authorise_any() -> Authorisation<T> {
+    Authorisation(PhantomData)
+  }
+}
+
+impl<T:Serialize> From<Authorisation<Global>> for Authorisation<T> {
+  // ^ we need a bound not met by Global or we conflict with From<T> for T
+  fn from(global: Authorisation<Global>) -> Self {
+    global.therefore_ok()
+  }
+}
+
+impl From<anyhow::Error> for AuthorisationError {
+  fn from(a: anyhow::Error) -> AuthorisationError {
+    AuthorisationError(format!("{}", a))
+  }
+}
+
+pub trait AuthorisationCombine: Sized {
+  type Output;
+  fn combine(self) -> Authorisation<Self::Output> {
+    Authorisation(PhantomData)
+  }
+}
+impl<A,B> AuthorisationCombine
+  for (Authorisation<A>, Authorisation<B>) {
+  type Output = (A, B);
+}
+impl<A,B,C> AuthorisationCombine
+  for (Authorisation<A>, Authorisation<B>, Authorisation<C>) {
+  type Output = (A, B, C);
+}
index e0c9306600295e7e235c7b8d03fed92b78b16ec7..3f78620891d49a880c3b5e23f63498535eb9e8ca 100644 (file)
@@ -74,6 +74,21 @@ impl From<InternalError> for SpecError {
     SpecError::InternalError(format!("{:?}", ie))
   }
 }
+
+#[derive(Error,Debug)]
+pub enum ApiPieceOpError {
+  ReportViaResponse(#[from] OnlineError),
+  ReportViaUpdate(#[from] PieceOpError),
+  PartiallyProcessed(PieceOpError, Vec<LogEntry>),
+}
+display_as_debug!(ApiPieceOpError);
+
+impl From<PlayerNotFound> for ApiPieceOpError {
+  fn from(x: PlayerNotFound) -> ApiPieceOpError {
+    ApiPieceOpError::ReportViaResponse(x.into())
+  }
+}
+
 #[derive(Error,Debug,Serialize,Clone)]
 pub enum ErrorSignaledViaUpdate {
   InternalError,
index 2c07faea882b2e46fee3b64323b7d0be89d9f289..df1d1324506014253744228f5feb5d13d45e9ac7 100644 (file)
@@ -168,12 +168,6 @@ pub struct InstanceAccessDetails<Id> {
   pub acctid: AccountId,
 }
 
-#[derive(Clone,Debug)]
-pub struct InstanceAccess<'i, Id> {
-  pub raw_token: &'i RawTokenVal,
-  pub i: InstanceAccessDetails<Id>,
-}
-
 // ========== internal data structures ==========
 
 lazy_static! {
@@ -225,6 +219,7 @@ display_as_debug!{InstanceLockError}
 impl<X> From<PoisonError<X>> for InstanceLockError {
   fn from(_: PoisonError<X>) -> Self { Self::GameCorrupted }
 }
+from_instance_lock_error!{MgmtError}
 
 pub struct PrivateCaller(());
 // outsiders cannot construct this
@@ -1144,19 +1139,6 @@ pub fn lookup_token<Id : AccessId>(s : &RawTokenVal)
     .ok_or(Id::ERROR)
 }
 
-impl<'r, Id> FromFormValue<'r> for InstanceAccess<'r, Id>
-  where Id : AccessId, OE : From<Id::Error>
-{
-  type Error = OE;
-  #[throws(OE)]
-  fn from_form_value(param: &'r RawStr) -> Self {
-    let g = Id::global_tokens(PRIVATE_Y).read().unwrap();
-    let token = RawTokenVal::from_str(param.as_str());
-    let i = g.get(token).ok_or(Id::ERROR)?;
-    InstanceAccess { raw_token : token, i : i.clone() }
-  }
-}
-
 #[throws(OE)]
 pub fn record_token<Id : AccessId> (
   ig: &mut InstanceGuard,
index 6cf4562aba6c43e5a66d7872898692c0e2a98856..394f3659d0f0f930ae05fc96da26485ae9224da9 100644 (file)
@@ -28,6 +28,7 @@ pub use std::num::{TryFromIntError, Wrapping};
 pub use std::ops::{Deref, DerefMut};
 pub use std::os::unix;
 pub use std::os::unix::ffi::OsStrExt;
+pub use std::os::unix::net::UnixStream;
 pub use std::os::unix::process::CommandExt;
 pub use std::path::PathBuf;
 pub use std::process::{exit, Command};
@@ -64,20 +65,6 @@ pub use rand::distributions::Alphanumeric;
 pub use rand::thread_rng;
 pub use rand::Rng;
 pub use regex::Regex;
-pub use rocket::http::Status;
-pub use rocket::http::{ContentType, RawStr};
-pub use rocket::request::Request;
-pub use rocket::request::{FromFormValue, FromParam, FromRequest, LenientForm};
-pub use rocket::response;
-pub use rocket::response::NamedFile;
-pub use rocket::response::{Responder, Response};
-pub use rocket::{get, post, routes};
-pub use rocket::{Rocket, State};
-pub use rocket_contrib::helmet::*;
-pub use rocket_contrib::json::Json;
-pub use rocket_contrib::templates::tera::{self, Value};
-pub use rocket_contrib::templates::Engines;
-pub use rocket_contrib::templates::Template;
 pub use serde::ser::SerializeTuple;
 pub use serde::{de::DeserializeOwned, Deserialize, Serialize};
 pub use serde::{Deserializer, Serializer};
@@ -89,11 +76,12 @@ pub use thiserror::Error;
 pub use vecdeque_stableix::Deque as StableIndexVecDeque;
 pub use zcoord::{self, ZCoord};
 
+pub use crate::from_instance_lock_error;
+
 pub use crate::accounts::loaded_acl::{self, EffectiveACL, LoadedAcl, PermSet};
 pub use crate::accounts::*;
-pub use crate::api::{AbbrevPresentationLayout, PresentationLayout};
-pub use crate::api::{ApiPieceOpError, Lens, TransparentLens};
-pub use crate::cmdlistener::*;
+pub use crate::authproofs::{self, Authorisation, Unauthorised};
+pub use crate::authproofs::AuthorisationSuperuser;
 pub use crate::commands::*;
 pub use crate::config::*;
 pub use crate::debugreader::DebugReader;
@@ -101,6 +89,7 @@ pub use crate::error::*;
 pub use crate::gamestate::*;
 pub use crate::global::*;
 pub use crate::keydata::*;
+pub use crate::lens::*;
 pub use crate::mgmtchannel::*;
 pub use crate::nwtemplates;
 pub use crate::pieces::*;
@@ -112,6 +101,7 @@ pub use crate::toml_de;
 pub use crate::tz::*;
 pub use crate::updates::*;
 pub use crate::utils::*;
+pub use crate::ui::*;
 
 pub type SecondarySlotMap<K,V> = slotmap::secondary::SecondaryMap<K,V>;
 pub type SvgData = Vec<u8>;
diff --git a/src/lens.rs b/src/lens.rs
new file mode 100644 (file)
index 0000000..f5bd2f3
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2020 Ian Jackson
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use crate::imports::*;
+
+pub trait Lens : Debug {
+  fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId;
+  fn log_pri(&self, piece: PieceId, pc: &PieceState)
+             -> PieceRenderInstructions;
+  fn svg_pri(&self, piece: PieceId, pc: &PieceState, player: PlayerId)
+             -> PieceRenderInstructions;
+  fn massage_prep_piecestate(&self, ns : &mut PreparedPieceState);
+  fn decode_visible_pieceid(&self, vpiece: VisiblePieceId, player: PlayerId)
+                            -> PieceId;
+}
+#[derive(Debug)]
+pub struct TransparentLens {
+  // when lenses become nontrivial, make this nonconstructable
+  // to find all the places where a TransparentLens was bodged
+}
+impl Lens for TransparentLens {
+  fn pieceid2visible(&self, piece: PieceId) -> VisiblePieceId {
+    let kd : slotmap::KeyData = piece.into();
+    VisiblePieceId(kd)
+  }
+  fn log_pri(&self, piece: PieceId, pc: &PieceState)
+             -> PieceRenderInstructions {
+    let id = self.pieceid2visible(piece);
+    PieceRenderInstructions { id, face : pc.face }
+  }
+  fn svg_pri(&self, piece: PieceId, pc: &PieceState, _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) { }
+}
+
index f4e29f7c6e407e02429d4a0cd9309cdcce672ed8..3586336a9f60ea90bc9a0d52dce011e7c06f8f3a 100644 (file)
@@ -8,8 +8,7 @@
 #![allow(clippy::redundant_closure_call)]
 
 pub mod accounts;
-pub mod api;
-pub mod cmdlistener;
+pub mod authproofs;
 pub mod commands;
 pub mod config;
 pub mod debugreader;
@@ -18,15 +17,16 @@ pub mod gamestate;
 pub mod global;
 pub mod imports;
 pub mod keydata;
+pub mod lens;
 pub mod mgmtchannel;
 pub mod nwtemplates;
 pub mod pieces;
-pub mod session;
 pub mod shapelib;
 pub mod spec;
 pub mod sse;
 pub mod tz;
 pub mod updates;
+pub mod ui;
 pub mod utils;
 
 #[path = "slotmap-slot-idx.rs"]   pub mod slotmap_slot_idx;
diff --git a/src/ui.rs b/src/ui.rs
new file mode 100644 (file)
index 0000000..237afe6
--- /dev/null
+++ b/src/ui.rs
@@ -0,0 +1,33 @@
+// Copyright 2020 Ian Jackson
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use crate::imports::*;
+
+#[derive(Clone,Copy,Debug,Eq,PartialEq,Serialize,Deserialize,EnumString)]
+pub enum PresentationLayout {
+  Portrait,
+  Landscape,
+}
+
+type PL = PresentationLayout;
+
+impl PresentationLayout {
+  pub fn template(self) -> &'static str {
+    match self {
+      PL::Portrait => "session",
+      PL::Landscape => "landscape",
+    }
+  }
+  pub fn abbreviate_timestamps(self) -> bool {
+    match self {
+      PL::Portrait => false,
+      PL::Landscape => true,
+    }
+  }
+}
+
+impl Default for PresentationLayout {
+  fn default() -> Self { PL::Portrait }
+}
+