#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
#![deny(missing_debug_implementations, nonstandard_style)]
#![warn(missing_docs, missing_doc_code_examples, unreachable_pub)]
use async_trait::async_trait;
use std::collections::HashMap;
#[async_trait]
pub trait SessionStore: Send + Sync + 'static + Clone {
type Error;
async fn load_session(&self, jar: &cookie::CookieJar) -> Result<Session, Self::Error>;
async fn store_session(
&mut self,
session: Session,
jar: &mut cookie::CookieJar,
) -> Result<(), Self::Error>;
}
#[derive(Clone, Debug)]
pub struct Session {
inner: HashMap<String, String>,
}
impl Session {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn insert(&mut self, k: String, v: String) -> Option<String> {
self.inner.insert(k, v)
}
pub fn get(&self, k: &str) -> Option<&String> {
self.inner.get(k)
}
}
pub mod mem {
use async_std::io::{Error, ErrorKind};
use async_std::sync::{Arc, RwLock};
use cookie::Cookie;
use std::collections::HashMap;
use async_trait::async_trait;
use uuid::Uuid;
use crate::{Session, SessionStore};
#[derive(Debug)]
pub struct MemoryStore {
inner: Arc<RwLock<HashMap<String, Session>>>,
}
impl MemoryStore {
pub fn new() -> Self {
Self {
inner: Arc::new(RwLock::new(HashMap::new())),
}
}
pub fn create_session(&self) -> Session {
let mut sess = Session::new();
sess.insert("id".to_string(), uuid::Uuid::new_v4().to_string());
sess
}
}
impl Clone for MemoryStore {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
#[async_trait]
impl SessionStore for MemoryStore {
type Error = std::io::Error;
async fn load_session(&self, jar: &cookie::CookieJar) -> Result<Session, Self::Error> {
let id = match jar.get("session") {
Some(cookie) => Uuid::parse_str(cookie.value()),
None => return Err(Error::new(ErrorKind::Other, "No session cookie found")),
};
let id = id
.map_err(|_| Error::new(ErrorKind::Other, "Cookie content was not a valid uuid"))?
.to_string();
let inner = self.inner.read().await;
let sess = inner.get(&id).ok_or(Error::from(ErrorKind::Other))?;
Ok(sess.clone())
}
async fn store_session(
&mut self,
sess: Session,
jar: &mut cookie::CookieJar,
) -> Result<(), Self::Error> {
let mut inner = self.inner.write().await;
let id = sess.get("id").unwrap().to_string();
inner.insert(id.clone(), sess);
jar.add(Cookie::new("session", id));
Ok(())
}
}
}