use std::{cell::RefCell, collections::HashMap, str::FromStr};
use actix_session::storage::{LoadError, SaveError, SessionKey, SessionStore, UpdateError};
use actix_web::cookie::time::Duration;
use anyhow::Error;
#[derive(Default)]
pub struct MockSessionStore {
data: RefCell<Vec<HashMap<String, String>>>,
}
fn key_to_index(session_key: &SessionKey) -> Result<usize, Error> {
usize::from_str(session_key.as_ref()).map_err(Into::into)
}
impl SessionStore for MockSessionStore {
async fn load(
&self,
session_key: &SessionKey,
) -> Result<Option<HashMap<String, String>>, LoadError> {
key_to_index(session_key)
.map(|i| self.data.borrow().get(i).cloned())
.map_err(LoadError::Deserialization)
}
async fn save(
&self,
session_state: HashMap<String, String>,
_ttl: &Duration,
) -> Result<SessionKey, SaveError> {
let key = SessionKey::try_from(self.data.borrow().len().to_string())
.map_err(Error::from)
.map_err(SaveError::Serialization)?;
self.data.borrow_mut().push(session_state);
Ok(key)
}
async fn update(
&self,
session_key: SessionKey,
session_state: HashMap<String, String>,
_ttl: &Duration,
) -> Result<SessionKey, UpdateError> {
let i = key_to_index(&session_key).map_err(UpdateError::Other)?;
self.data.borrow_mut().get_mut(i).map_or_else(
|| Err(UpdateError::Other(Error::msg("No such key"))),
|data| {
*data = session_state;
Ok(session_key)
},
)
}
async fn update_ttl(&self, _session_key: &SessionKey, _ttl: &Duration) -> Result<(), Error> {
unimplemented!();
}
async fn delete(&self, session_key: &SessionKey) -> Result<(), Error> {
match key_to_index(session_key)? {
i if i < self.data.borrow().len() => {
self.data.borrow_mut().remove(i);
Ok(())
}
_ => Err(Error::msg("No such key")),
}
}
}