Compare commits

...

2 Commits

  1. 32
      Cargo.lock
  2. 2
      Cargo.toml
  3. 18
      src/main.rs
  4. 170
      src/session.rs

32
Cargo.lock generated

@ -142,6 +142,8 @@ name = "cookie"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -796,6 +798,17 @@ name = "regex-syntax"
version = "0.6.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "ring"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rocket"
version = "0.4.2"
@ -829,6 +842,7 @@ dependencies = [
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket_session 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -878,6 +892,16 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rocket_session"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc-demangle"
version = "0.1.16"
@ -1166,6 +1190,11 @@ name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "untrusted"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "url"
version = "1.7.2"
@ -1368,10 +1397,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
"checksum rocket 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "42c1e9deb3ef4fa430d307bfccd4231434b707ca1328fae339c43ad1201cc6f7"
"checksum rocket_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "79aa1366f9b2eccddc05971e17c5de7bb75a5431eb12c2b5c66545fd348647f4"
"checksum rocket_contrib 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e0fa5c1392135adc0f96a02ba150ac4c765e27c58dbfd32aa40678e948f6e56f"
"checksum rocket_http 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b1391457ee4e80b40d4b57fa5765c0f2836b20d73bcbee4e3f35d93cf3b80817"
"checksum rocket_session 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f4d2f62206b13d4d0b2e52bd176e727519ba2326c9eea77978c54c25d48296bf"
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
@ -1410,6 +1441,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
"checksum utf8-ranges 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ae116fef2b7fea257ed6440d3cfcff7f190865f170cdad00bb6465bf18ecba"
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"

@ -16,6 +16,8 @@ json_dotpath = "0.1.2"
titlecase = "0.10.0"
rand = "0.7.2"
rocket_session = "0.1.1"
# special data structure that preserves order
indexmap = { version="1.3.0", features=["serde-1"] }

@ -12,9 +12,12 @@ use serde_json::Value;
use rocket_contrib::serve::StaticFiles;
use rocket_contrib::templates::Template;
mod session;
//mod session;
mod store;
mod session;
use session::Session;
use crate::store::form::{
collect_card_form, render_card_fields, render_empty_fields, MapFromForm, RenderedCard,
RenderedField,
@ -22,11 +25,14 @@ use crate::store::form::{
use crate::store::Store;
use parking_lot::RwLock;
use crate::session::{Session, SessionID, SessionStore};
//use crate::session::Session;
use rocket::request::Form;
use rocket::response::Redirect;
use rocket::{Request, State};
use rocket::State;
use std::env;
use std::time::Duration;
use crate::session::SessionAccess;
//use crate::session::SessionAccess;
#[derive(Serialize, Debug)]
pub struct ListContext<'a> {
@ -61,7 +67,7 @@ fn route_index(store: State<RwLock<Store>>, session: Session, page: Option<usize
count += 1;
session.set("foo.bar.count", count);
println!("{:?}", session);
//println!("{:?}", session);
let mut page = page.unwrap_or_default();
let n_pages = (rg.data.cards.len() as f64 / PER_PAGE as f64).ceil() as usize;
@ -74,7 +80,7 @@ fn route_index(store: State<RwLock<Store>>, session: Session, page: Option<usize
fields: render_empty_fields(&rg),
pages: n_pages,
page,
count,
count: count as usize,
cards: rg
.data
.cards
@ -187,7 +193,7 @@ fn main() {
rocket::ignite()
.attach(Template::fairing())
.attach(Session::fairing())
.attach(Session::fairing(Duration::from_secs(3600)))
.manage(RwLock::new(store))
.mount("/", StaticFiles::from(cwd.join("templates/static/")))
.mount(

@ -1,171 +1,59 @@
use json_dotpath::DotPaths;
use parking_lot::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
use rand::Rng;
use rocket::fairing::{self, Fairing, Info};
use rocket::request::FromRequest;
use rocket::response::ResponseBuilder;
use rocket::{
http::{Cookie, Cookies, Status},
Data, Outcome, Request, Response, Rocket, State,
};
use serde_json::Value;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::borrow::Cow;
use std::collections::HashMap;
use std::ops::{Deref, DerefMut};
use serde::Serialize;
use json_dotpath::DotPaths;
const SESSION_ID: &'static str = "SESSID";
pub type Session<'a> = rocket_session::Session<'a, serde_json::Map<String, Value>>;
type SessionsMap = HashMap<String, SessionInstance>;
pub trait SessionAccess {
fn get<T: DeserializeOwned>(&self, path: &str) -> Option<T>;
#[derive(Debug)]
struct SessionInstance {
data: serde_json::Map<String, Value>,
// TODO expiration
}
fn get_or<T: DeserializeOwned>(&self, path: &str, def: T) -> T;
#[derive(Default, Debug)]
pub struct SessionStore {
inner: RwLock<SessionsMap>,
}
fn get_or_else<T: DeserializeOwned, F: FnOnce() -> T>(&self, path: &str, def: F) -> T;
#[derive(PartialEq, Hash, Clone, Debug)]
pub struct SessionID(String);
impl<'a, 'r> FromRequest<'a, 'r> for &'a SessionID {
type Error = ();
fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
Outcome::Success(request.local_cache(|| {
println!("get id");
if let Some(cookie) = request.cookies().get(SESSION_ID) {
println!("from cookie");
SessionID(cookie.value().to_string()) // FIXME avoid cloning
} else {
println!("new id");
SessionID(
rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(16)
.collect(),
)
}
}))
}
}
fn get_or_default<T: DeserializeOwned + Default>(&self, path: &str) -> T;
#[derive(Debug)]
pub struct Session<'a> {
store: State<'a, SessionStore>,
id: &'a SessionID,
}
fn take<T: DeserializeOwned>(&self, path: &str) -> Option<T>;
impl<'a, 'r> FromRequest<'a, 'r> for Session<'a> {
type Error = ();
fn from_request(request: &'a Request<'r>) -> Outcome<Self, (Status, Self::Error), ()> {
Outcome::Success(Session {
id: request.local_cache(|| {
if let Some(cookie) = request.cookies().get(SESSION_ID) {
SessionID(cookie.value().to_string())
} else {
SessionID(
rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(16)
.collect(),
)
}
}),
store: request.guard().unwrap(),
})
}
}
fn replace<O: DeserializeOwned, N: Serialize>(&self, path: &str, new: N) -> Option<O>;
impl<'a> Session<'a> {
pub fn fairing() -> impl Fairing {
SessionFairing
}
fn set<T: Serialize>(&self, path: &str, value: T);
pub fn get<T: DeserializeOwned>(&self, path: &str) -> Option<T> {
let rg = self.store.inner.read();
if let Some(ses) = rg.get(&self.id.0) {
ses.data.dot_get(path)
} else {
None
}
fn remove(&self, path: &str) -> bool;
}
impl<'a> SessionAccess for Session<'a> {
fn get<T: DeserializeOwned>(&self, path: &str) -> Option<T> {
self.tap(|data| data.dot_get(path))
}
pub fn get_or<T: DeserializeOwned>(&self, path: &str, def: T) -> T {
fn get_or<T: DeserializeOwned>(&self, path: &str, def: T) -> T {
self.get(path).unwrap_or(def)
}
pub fn get_or_else<T: DeserializeOwned, F: FnOnce() -> T>(&self, path: &str, def: F) -> T {
fn get_or_else<T: DeserializeOwned, F: FnOnce() -> T>(&self, path: &str, def: F) -> T {
self.get(path).unwrap_or_else(def)
}
pub fn get_or_default<T: DeserializeOwned + Default>(&self, path: &str) -> T {
fn get_or_default<T: DeserializeOwned + Default>(&self, path: &str) -> T {
self.get(path).unwrap_or_default()
}
pub fn take<T: DeserializeOwned>(&self, path: &str) -> Option<T> {
let mut wg = self.store.inner.write();
if let Some(ses) = wg.get_mut(&self.id.0) {
ses.data.dot_take(path)
} else {
None
}
fn take<T: DeserializeOwned>(&self, path: &str) -> Option<T> {
self.tap(|data| data.dot_take(path))
}
pub fn replace<O: DeserializeOwned, N: Serialize>(&self, path: &str, new: N) -> Option<O> {
let mut wg = self.store.inner.write();
if let Some(ses) = wg.get_mut(&self.id.0) {
ses.data.dot_replace(path, new)
} else {
None
}
fn replace<O: DeserializeOwned, N: Serialize>(&self, path: &str, new: N) -> Option<O> {
self.tap(|data| data.dot_replace(path, new))
}
pub fn set<T: Serialize>(&self, path: &str, value: T) {
let mut wg = self.store.inner.write();
if let Some(ses) = wg.get_mut(&self.id.0) {
ses.data.dot_set(path, value);
} else {
let mut map = Map::new();
map.dot_set(path, value);
wg.insert(self.id.0.clone(), SessionInstance { data: map });
}
fn set<T: Serialize>(&self, path: &str, value: T) {
self.tap(|data| data.dot_set(path, value));
}
pub fn remove(&self, path: &str) {
let mut wg = self.store.inner.write();
if let Some(ses) = wg.get_mut(&self.id.0) {
ses.data.dot_remove(path);
}
fn remove(&self, path: &str) -> bool {
self.tap(|data| data.dot_remove(path))
}
}
/// Fairing struct
struct SessionFairing;
impl Fairing for SessionFairing {
fn info(&self) -> Info {
Info {
name: "Session Fairing",
kind: fairing::Kind::Attach | fairing::Kind::Response,
}
}
fn on_attach(&self, rocket: Rocket) -> Result<Rocket, Rocket> {
Ok(rocket.manage(SessionStore::default()))
}
fn on_response<'r>(&self, request: &'r Request, response: &mut Response) {
let session = request.local_cache(|| SessionID("".to_string()));
if !session.0.is_empty() {
response.adjoin_header(Cookie::build(SESSION_ID, session.0.clone()).finish());
}
}
}

Loading…
Cancel
Save