lexa-framework 0.2.8

Framework web backend personnel par dessus Axum.
Documentation
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ Copyright: (c) 2023, Mike 'PhiSyX' S. (https://github.com/PhiSyX)         ┃
// ┃ SPDX-License-Identifier: MPL-2.0                                          ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃                                                                           ┃
// ┃  This Source Code Form is subject to the terms of the Mozilla Public      ┃
// ┃  License, v. 2.0. If a copy of the MPL was not distributed with this      ┃
// ┃  file, You can obtain one at https://mozilla.org/MPL/2.0/.                ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

use axum::http;

use crate::http::{HttpContext, HttpContextInterface};
use crate::state::State;

// ----------- //
// Énumération //
// ----------- //

#[derive(Debug)]
#[derive(thiserror::Error)]
#[error("\n\t{}: {0}", std::any::type_name::<Self>())]
pub enum HttpContextError {
	Extension(#[from] axum::extract::rejection::ExtensionRejection),
	Infaillible(#[from] std::convert::Infallible),
	MissingExtension,
}

// -------------- //
// Implémentation // -> Interface
// -------------- //

#[axum::async_trait]
impl<C, S> axum::extract::FromRequestParts<State<S>> for HttpContext<C>
where
	C: 'static,
	C: HttpContextInterface,
	S: 'static,
	S: Send + Sync,
	<C as HttpContextInterface>::State: Send + Sync,
	<C as HttpContextInterface>::State: axum::extract::FromRef<State<S>>,
{
	type Rejection = HttpContextError;

	async fn from_request_parts(
		parts: &mut axum::http::request::Parts,
		state: &State<S>,
	) -> Result<Self, Self::Rejection> {
		// Context
		let axum::extract::State(extracts) = axum::extract::State::<
			<C as HttpContextInterface>::State,
		>::from_request_parts(parts, state)
		.await?;

		let context = C::new(&parts.extensions, extracts)
			.await
			.ok_or(HttpContextError::MissingExtension)?
			.shared();

		// Request
		let axum::extract::ConnectInfo(ip) =
			axum::extract::ConnectInfo::from_request_parts(parts, state)
				.await?;
		let method = parts.method.clone();
		let axum::extract::OriginalUri(uri) =
			axum::extract::OriginalUri::from_request_parts(parts, state)
				.await?;
		let axum::extract::RawQuery(raw_query) =
			axum::extract::RawQuery::from_request_parts(parts, state).await?;
		let referer =
			axum::TypedHeader::<axum::headers::Referer>::from_request_parts(
				parts, state,
			)
			.await
			.map(|ext| ext.0)
			.ok();
		let request = crate::http::HttpRequest {
			context: context.clone(),
			ip,
			method,
			uri,
			raw_query,
			referer,
		};

		// Response
		let response = crate::http::HttpResponse {
			context: context.clone(),
		};

		// Cookies
		#[cfg(feature = "cookies")]
		{
			let cookie_key = state.cookie_key.as_ref().unwrap().clone();
			let cookies_manager =
				tower_cookies::Cookies::from_request_parts(parts, state)
					.await
					.expect("Cookies Manager");
			let cookies =
				crate::http::cookies::Cookies::new(cookies_manager, cookie_key);

			let session = parts
				.extensions
				.get::<axum_sessions::SessionHandle>()
				.cloned()
				.map(|session_handle| {
					crate::http::session::Session {
						handle: session_handle,
					}
				})
				.expect("Impossible d'extraire la session");

			Ok(Self {
				context,
				request,
				response,
				cookies,
				session,
			})
		}

		#[cfg(not(feature = "cookies"))]
		{
			Ok(Self {
				context,
				request,
				response,
			})
		}
	}
}

impl axum::response::IntoResponse for HttpContextError {
	fn into_response(self) -> axum::response::Response {
		let err_status = http::StatusCode::INTERNAL_SERVER_ERROR;
		let err_body = self.to_string();
		(err_status, err_body).into_response()
	}
}