pub mod managers;
use std::future::Future;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Mutex;
use uuid::Uuid;
use crate::core::headers::Headers;
use super::cookie;
pub type SessionResult<T> = Box<dyn Future<Output = T> + Send + Unpin>;
pub trait AbstractSessionManager: Sync + Send {
fn set(
&self,
session_id: &String,
name: &str,
value: &str,
) -> SessionResult<std::io::Result<()>>;
fn get(&self, session_id: &String, name: &str) -> SessionResult<Option<String>>;
fn remove(&self, session_id: &String, name: &str) -> SessionResult<std::io::Result<()>>;
fn destroy(&self, session_id: &String) -> SessionResult<std::io::Result<()>>;
}
pub type SessionManager = Box<dyn AbstractSessionManager>;
pub struct Session {
session_manager: Arc<SessionManager>,
session_id: Arc<Mutex<Option<String>>>,
response_headers: Arc<Mutex<Headers>>,
}
impl Clone for Session {
fn clone(&self) -> Self {
Self {
session_manager: self.session_manager.clone(),
session_id: self.session_id.clone(),
response_headers: self.response_headers.clone(),
}
}
}
impl Session {
pub fn from(
session_manager: Arc<SessionManager>,
session_id: Option<&String>,
response_headers: Arc<Mutex<Headers>>,
) -> Self {
let session_id_value;
if let Some(session_id) = session_id {
session_id_value = Some(session_id.to_owned());
} else {
session_id_value = None;
}
Self {
session_manager,
session_id: Arc::new(Mutex::new(session_id_value)),
response_headers: response_headers.clone(),
}
}
pub async fn session_id(&self) -> Option<String> {
let session_id_lock = self.session_id.lock().await;
if let Some(session_id) = &*session_id_lock {
return Some(session_id.to_owned());
}
None
}
pub async fn set<S: AsRef<str>>(&self, name: S, value: S) -> std::io::Result<()> {
let mut session_id_lock = self.session_id.lock().await;
let session_id;
if !session_id_lock.is_some() {
session_id = Uuid::new_v4().to_string();
let mut response_headers = self.response_headers.lock().await;
cookie::set_cookie(
&mut response_headers,
"sessionid",
&session_id,
Duration::from_secs(7 * 86400),
);
*session_id_lock = Some(session_id);
}
if let Some(session_id) = &*session_id_lock {
match self
.session_manager
.set(session_id, name.as_ref(), value.as_ref())
.await
{
Ok(()) => return Ok(()),
Err(error) => {
return Err(std::io::Error::other(error));
}
};
}
Ok(())
}
pub async fn get<S: AsRef<str>>(&self, name: S) -> Option<String> {
let session_id_lock = self.session_id.lock().await;
if let Some(session_id) = &*session_id_lock {
return self.session_manager.get(session_id, name.as_ref()).await;
}
None
}
pub async fn remove<S: AsRef<str>>(&self, name: S) -> std::io::Result<()> {
let session_id_lock = self.session_id.lock().await;
if let Some(session_id) = &*session_id_lock {
return self.session_manager.remove(session_id, name.as_ref()).await;
}
Ok(())
}
pub async fn destroy(&self) -> std::io::Result<()> {
let response_headers_ref = self.response_headers.clone();
let mut response_headers = response_headers_ref.lock().await;
let expire_header_value = format!(
"{}=;Expires=Sun, 06 Nov 1994 08:49:37 GMT; Path=/",
"sessionid"
);
response_headers.insert(
"Set-Cookie".to_string(),
vec![expire_header_value.as_bytes().to_vec()],
);
let session_lock = self.session_id.lock().await;
if let Some(session_id) = &*session_lock {
return self.session_manager.destroy(session_id).await;
}
Ok(())
}
}