diff options
| author | WriterV2 <primary-v2@protonmail.com> | 2024-10-27 13:58:51 +0100 |
|---|---|---|
| committer | WriterV2 <primary-v2@protonmail.com> | 2024-10-27 14:00:34 +0100 |
| commit | 04e19765aca471fd85199714699aaf827d04608d (patch) | |
| tree | a2bfa782c1db2a6b783206087309a9eed3c6e9b9 | |
| parent | e074949d96fe29929e99890b3035dc1a5ba57184 (diff) | |
Refactor: Organize modules initially
| -rw-r--r-- | .env | 1 | ||||
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | src/error.rs | 23 | ||||
| -rw-r--r-- | src/handlers/admin.rs | 39 | ||||
| -rw-r--r-- | src/handlers/frontend.rs | 37 | ||||
| -rw-r--r-- | src/handlers/mod.rs | 21 | ||||
| -rw-r--r-- | src/main.rs | 105 |
7 files changed, 124 insertions, 103 deletions
@@ -1 +0,0 @@ -TOKEN=TOKEN @@ -1,3 +1,4 @@ # Added by cargo /target *.db* +.env diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..72378ae --- /dev/null +++ b/src/error.rs @@ -0,0 +1,23 @@ +use axum::http::StatusCode; +use axum::response::IntoResponse; + +pub struct AppError(anyhow::Error); + +impl IntoResponse for AppError { + fn into_response(self) -> axum::response::Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {}", self.0), + ) + .into_response() + } +} + +impl<E> From<E> for AppError +where + E: Into<anyhow::Error>, +{ + fn from(err: E) -> Self { + Self(err.into()) + } +} diff --git a/src/handlers/admin.rs b/src/handlers/admin.rs new file mode 100644 index 0000000..349275b --- /dev/null +++ b/src/handlers/admin.rs @@ -0,0 +1,39 @@ +use std::env; + +use axum::extract::Request; +use axum::http::{HeaderMap, StatusCode}; +use axum::middleware::Next; +use axum::response::Response; +use subtle::ConstantTimeEq; + +pub async fn admin_middleware( + headers: HeaderMap, + request: Request, + next: Next, +) -> Result<Response, StatusCode> { + let expected_token = env::var("TOKEN").map_err(|_| { + eprintln!("Error: TOKEN environment variable is not set"); + StatusCode::INTERNAL_SERVER_ERROR + })?; + + let token = headers + .get("X-Admin-Token") + .and_then(|header| header.to_str().ok()) + .ok_or(StatusCode::UNAUTHORIZED)?; + + if !expected_token + .as_bytes() + .ct_eq(token.as_bytes()) + .unwrap_u8() + == 1 + { + eprintln!("Warning: Unauthorized access attempt with invalid token"); + return Err(StatusCode::UNAUTHORIZED); + } + + Ok(next.run(request).await) +} + +pub async fn admin_handler() -> &'static str { + "Hello World" +} diff --git a/src/handlers/frontend.rs b/src/handlers/frontend.rs new file mode 100644 index 0000000..f4b7c6c --- /dev/null +++ b/src/handlers/frontend.rs @@ -0,0 +1,37 @@ +use axum::response::IntoResponse; +use maud::{html, Markup, DOCTYPE}; + +use crate::error::AppError; + +pub async fn home() -> Result<impl IntoResponse, AppError> { + Ok(html!({ + (head("Home")) + body class="bg-[#eae3d2] text-[#333] dark:bg-[#333] dark:text-[#eae3d2] font-mono text-base tracking-wide" { + (header_with_navbar()) + } + })) +} + +fn header_with_navbar() -> Markup { + html!({ + header { + navbar class="p-3 text-sm flex flex-row flex-wrap content-center justify-around decoration-purple-500 shadow" { + a class="hover:underline" href="/" { "Home" } + a class="hover:underline" href="/" { "Stories" } + a class="hover:underline" href="/" { "Tools" } + a class="hover:underline" href="/" { "Games" } + } + } + }) +} + +fn head(page_title: &str) -> Markup { + html! { + head { + (DOCTYPE) + meta charset="utf-8"; + link rel="stylesheet" type="text/css" href="/static/styles.css"; + title { (page_title) } + } + } +} diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs new file mode 100644 index 0000000..d69f590 --- /dev/null +++ b/src/handlers/mod.rs @@ -0,0 +1,21 @@ +use axum::extract::DefaultBodyLimit; +use axum::middleware::{self}; +use axum::routing::get; +use axum::Router; +use sqlx::SqlitePool; +use tower_http::services::ServeDir; + +use admin::{admin_handler, admin_middleware}; +use frontend::home; + +mod admin; +mod frontend; + +pub async fn router(pool: SqlitePool) -> Router { + Router::new() + .route("/admin", get(admin_handler)) + .layer(middleware::from_fn(admin_middleware)) + .route("/", get(home)) + .nest_service("/static", ServeDir::new("src/static")) + .layer(DefaultBodyLimit::max(10000)) +} diff --git a/src/main.rs b/src/main.rs index feaa6a7..b4d7567 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,39 +1,11 @@ use std::env; -use axum::extract::{DefaultBodyLimit, Request}; -use axum::http::{HeaderMap, StatusCode}; -use axum::middleware::Next; -use axum::response::{IntoResponse, Response}; -use axum::routing::get; -use axum::{middleware, Router}; use dotenvy::dotenv; -use maud::{html, Markup, DOCTYPE}; use sqlx::sqlite::SqlitePoolOptions; -use subtle::ConstantTimeEq; -use tower_http::services::ServeDir; mod db; - -struct AppError(anyhow::Error); - -impl IntoResponse for AppError { - fn into_response(self) -> axum::response::Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Something went wrong: {}", self.0), - ) - .into_response() - } -} - -impl<E> From<E> for AppError -where - E: Into<anyhow::Error>, -{ - fn from(err: E) -> Self { - Self(err.into()) - } -} +mod error; +mod handlers; #[tokio::main] async fn main() { @@ -50,79 +22,8 @@ async fn main() { .await .expect("Failed to run migrations"); - let app = Router::new() - .route("/admin", get(admin_handler)) - .layer(middleware::from_fn(admin_middleware)) - .route("/", get(home)) - .nest_service("/static", ServeDir::new("src/static")) - .layer(DefaultBodyLimit::max(10000)); let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap(); - axum::serve(listener, app.into_make_service()) + axum::serve(listener, handlers::router(pool).await.into_make_service()) .await .unwrap(); } - -async fn admin_middleware( - headers: HeaderMap, - request: Request, - next: Next, -) -> Result<Response, StatusCode> { - let expected_token = env::var("TOKEN").map_err(|_| { - eprintln!("Error: TOKEN environment variable is not set"); - StatusCode::INTERNAL_SERVER_ERROR - })?; - - let token = headers - .get("X-Admin-Token") - .and_then(|header| header.to_str().ok()) - .ok_or(StatusCode::UNAUTHORIZED)?; - - if !expected_token - .as_bytes() - .ct_eq(token.as_bytes()) - .unwrap_u8() - == 1 - { - eprintln!("Warning: Unauthorized access attempt with invalid token"); - return Err(StatusCode::UNAUTHORIZED); - } - - Ok(next.run(request).await) -} - -async fn admin_handler() -> &'static str { - "Hello World" -} - -async fn home() -> Result<impl IntoResponse, AppError> { - Ok(html!({ - (head("Home")) - body class="bg-[#eae3d2] text-[#333] dark:bg-[#333] dark:text-[#eae3d2] font-mono text-base tracking-wide" { - (header_with_navbar()) - } - })) -} - -fn header_with_navbar() -> Markup { - html!({ - header { - navbar class="p-3 text-sm flex flex-row flex-wrap content-center justify-around decoration-purple-500 shadow" { - a class="hover:underline" href="/" { "Home" } - a class="hover:underline" href="/" { "Stories" } - a class="hover:underline" href="/" { "Tools" } - a class="hover:underline" href="/" { "Games" } - } - } - }) -} - -fn head(page_title: &str) -> Markup { - html! { - head { - (DOCTYPE) - meta charset="utf-8"; - link rel="stylesheet" type="text/css" href="/static/styles.css"; - title { (page_title) } - } - } -} |
