use axum::{response::{IntoResponse, Response}, http::{StatusCode, Request, HeaderValue}, body::Body, headers::HeaderName}; use tower::ServiceExt; use tower_http::services::ServeFile; use tracing::instrument; #[derive(Debug)] pub enum ResponseCode { Success, Created, BadRequest, Unauthorized, Forbidden, NotFound, ImATeapot, InternalServerError } impl ResponseCode { const fn code(self) -> StatusCode { match self { Self::Success => StatusCode::OK, Self::Created => StatusCode::CREATED, Self::BadRequest => StatusCode::BAD_REQUEST, Self::Unauthorized => StatusCode::UNAUTHORIZED, Self::Forbidden => StatusCode::FORBIDDEN, Self::NotFound => StatusCode::NOT_FOUND, Self::ImATeapot => StatusCode::IM_A_TEAPOT, Self::InternalServerError => StatusCode::INTERNAL_SERVER_ERROR } } #[instrument()] pub fn text(self, msg: &str) -> Response { (self.code(), msg.to_owned()).into_response() } #[instrument()] pub fn json(self, json: &str) -> Response { let mut res = (self.code(), json.to_owned()).into_response(); res.headers_mut().insert( HeaderName::from_static("content-type"), HeaderValue::from_static("application/json"), ); res } #[instrument()] pub fn html(self, json: &str) -> Response { let mut res = (self.code(), json.to_owned()).into_response(); res.headers_mut().insert( HeaderName::from_static("content-type"), HeaderValue::from_static("text/html"), ); res } #[instrument()] pub async fn file(self, path: &str) -> Response { if !path.chars().any(|c| c == '.' ) { return Self::BadRequest.text("Folders cannot be served"); } let path = format!("public{path}"); let svc = ServeFile::new(path); let Ok(mut res) = svc.oneshot(Request::new(Body::empty())).await else { tracing::error!("Error while fetching file"); return Self::InternalServerError.text("Error while fetching file"); }; if res.status() != StatusCode::OK { return Self::NotFound.text("File not found"); } *res.status_mut() = self.code(); res.into_response() } } pub type Result = std::result::Result;