author-web 0.1.0

Common code for Author web integrations
Documentation
use crate::session::store::{SessionDataValueStorage, SessionStore};
use crate::session::SessionKey;
use async_trait::async_trait;
use parking_lot::Mutex;
use std::borrow::Borrow;
use std::collections::HashMap;
use std::hash::Hash;
use std::sync::Arc;
use uuid::Uuid;

pub struct InMemorySessionStore<S = InMemorySessionData<String, String>, K = Uuid> {
    sessions: Mutex<HashMap<K, Arc<S>>>,
}

impl<S, K> InMemorySessionStore<S, K> {
    pub fn new() -> Self {
        InMemorySessionStore {
            sessions: Mutex::new(HashMap::new()),
        }
    }
}

#[async_trait]
impl<S, K> SessionStore for InMemorySessionStore<S, K>
where
    S: CreateNew,
    K: SessionKey + Clone + Eq + Hash + Send + Sync,
{
    type Session = Arc<S>;
    type Key = K;

    async fn create_session(&self) -> anyhow::Result<(Self::Key, Self::Session)> {
        let key = K::generate();
        let session = Arc::new(S::new());

        self.sessions.lock().insert(key.clone(), session.clone());

        Ok((key, session))
    }

    async fn load_session(&self, key: &K) -> anyhow::Result<Option<Self::Session>> {
        Ok(self.sessions.lock().get(key).cloned())
    }
}

pub trait CreateNew: Send + Sync {
    fn new() -> Self;
}

impl<S> CreateNew for Arc<S>
where
    S: CreateNew,
{
    fn new() -> Self {
        Arc::new(S::new())
    }
}

pub type InMemorySession<K = String, V = String> = Arc<InMemorySessionData<K, V>>;

pub struct InMemorySessionData<K = String, V = String> {
    values: Mutex<HashMap<K, V>>,
}

impl<K, V> InMemorySessionData<K, V> {
    pub fn new() -> Self {
        InMemorySessionData {
            values: Mutex::new(HashMap::new()),
        }
    }
}

impl<K, V> CreateNew for InMemorySessionData<K, V>
where
    K: Send + Sync,
    V: Send + Sync,
{
    fn new() -> Self {
        InMemorySessionData::new()
    }
}

impl SessionKey for Uuid {
    fn generate() -> Self {
        Uuid::new_v4()
    }
}

#[async_trait]
impl<K, V> SessionDataValueStorage<K, V> for InMemorySessionData<K, V>
where
    K: Clone + Hash + Eq + Send,
    V: Clone + Send,
{
    async fn set_value<KVal, VVal>(&self, key: KVal, val: VVal) -> anyhow::Result<()>
    where
        KVal: Into<K> + Send,
        VVal: Into<V> + Send,
    {
        self.values.lock().insert(key.into(), val.into());
        Ok(())
    }

    async fn unset_value<KVal>(&self, key: KVal) -> anyhow::Result<()>
    where
        KVal: Into<K> + Send,
    {
        self.values.lock().remove(&key.into());
        Ok(())
    }

    async fn get_value<KRef>(&self, key: &KRef) -> anyhow::Result<Option<V>>
    where
        KRef: Hash + Eq + ?Sized + Sync,
        K: Borrow<KRef>,
    {
        Ok(self.values.lock().get(key).cloned())
    }
}