use std::ops;
use std::sync::Arc;
#[async_trait::async_trait]
pub trait HttpContextInterface: Send + Sync {
type State;
async fn new(
extensions: &super::Extensions,
state: Self::State,
) -> Option<Self>
where
Self: Sized;
fn shared(self) -> Arc<Self>
where
Self: Sized,
{
Arc::new(self)
}
}
pub struct HttpContext<T> {
pub(crate) context: Arc<T>,
pub request: HttpRequest<T>,
pub response: HttpResponse<T>,
#[cfg(feature = "cookies")]
pub cookies: crate::http::cookies::Cookies,
#[cfg(feature = "cookies")]
pub session: SessionContext,
}
pub struct HttpRequest<T> {
pub(crate) context: Arc<T>,
pub ip: std::net::SocketAddr,
pub method: hyper::Method,
pub uri: hyper::Uri,
pub raw_query: Option<String>,
pub referer: Option<axum::headers::Referer>,
}
pub struct HttpResponse<T> {
pub(crate) context: Arc<T>,
}
#[cfg(feature = "cookies")]
pub struct SessionContext {
pub(crate) handle: axum_sessions::SessionHandle,
}
impl<T> HttpContext<T> {
#[cfg(feature = "auth")]
pub async fn logout_user(&mut self) {
let mut session = self.session.write().await;
session.remove(crate::auth::AUTH_USER_ID_SESSION);
session.remove(crate::auth::AUTH_ADMIN_ID_SESSION);
session.regenerate();
if let Some(mut user_cookie) = self
.cookies
.private()
.get(crate::auth::AUTH_USER_ID_SESSION)
{
let expires_in = time::OffsetDateTime::now_utc()
.checked_sub(time::Duration::days(100));
user_cookie.set_path("/");
user_cookie.set_expires(expires_in);
self.cookies.private().add(user_cookie);
}
if let Some(mut adm_cookie) = self
.cookies
.private()
.get(crate::auth::AUTH_ADMIN_ID_SESSION)
{
let expires_in = time::OffsetDateTime::now_utc()
.checked_sub(time::Duration::days(100));
adm_cookie.set_path("/");
adm_cookie.set_expires(expires_in);
self.cookies.private().add(adm_cookie);
}
}
}
impl<T> HttpResponse<T> {
#[inline]
pub fn html<R>(
&self,
html: impl Into<axum::response::Html<R>>,
) -> axum::response::Html<R>
where
R: Into<axum::body::Full<hyper::body::Bytes>>,
{
html.into()
}
#[inline]
pub fn json<D>(&self, data: D) -> axum::response::Json<D>
where
D: serde::Serialize,
{
data.into()
}
#[inline]
pub fn redirect_to(&self, uri: impl ToString) -> axum::response::Redirect
where
Self: Sized,
{
axum::response::Redirect::to(uri.to_string().as_ref())
}
#[inline]
pub fn redirect_permanent(
&self,
uri: impl ToString,
) -> axum::response::Redirect
where
Self: Sized,
{
axum::response::Redirect::permanent(uri.to_string().as_ref())
}
#[inline]
pub fn redirect_temporary(
&self,
uri: impl ToString,
) -> axum::response::Redirect
where
Self: Sized,
{
axum::response::Redirect::temporary(uri.to_string().as_ref())
}
}
#[cfg(feature = "cookies")]
impl SessionContext {
pub async fn read(
&self,
) -> tokio::sync::RwLockReadGuard<'_, axum_sessions::async_session::Session>
{
self.handle.read().await
}
pub async fn write(
&mut self,
) -> tokio::sync::RwLockWriteGuard<'_, axum_sessions::async_session::Session>
{
self.handle.write().await
}
#[cfg(feature = "auth")]
pub async fn is_logged<User>(&self) -> bool
where
User: serde::de::DeserializeOwned,
{
self.read()
.await
.get::<User>(crate::auth::AUTH_ADMIN_ID_SESSION)
.is_some() || self
.read()
.await
.get::<User>(crate::auth::AUTH_USER_ID_SESSION)
.is_some()
}
#[cfg(feature = "auth")]
pub async fn is_logged_as_admin<User>(&self) -> bool
where
User: serde::de::DeserializeOwned,
{
self.read()
.await
.get::<User>(crate::auth::AUTH_ADMIN_ID_SESSION)
.is_some()
}
#[cfg(feature = "auth")]
pub async fn is_logged_as_user<User>(&self) -> bool
where
User: serde::de::DeserializeOwned,
{
self.read()
.await
.get::<User>(crate::auth::AUTH_USER_ID_SESSION)
.is_some()
}
}
impl<T> ops::Deref for HttpContext<T> {
type Target = Arc<T>;
fn deref(&self) -> &Self::Target {
&self.context
}
}