From 7a4fbaf74a270a0e158f930e2230602810d73de5 Mon Sep 17 00:00:00 2001 From: clerie Date: Mon, 10 Feb 2025 12:08:31 +0100 Subject: [PATCH] Move web router to separate module --- src/bin/web.rs | 116 ++------------------------------------------ src/lib.rs | 1 + src/web.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 113 deletions(-) create mode 100644 src/web.rs diff --git a/src/bin/web.rs b/src/bin/web.rs index c204990..1d5e0e8 100644 --- a/src/bin/web.rs +++ b/src/bin/web.rs @@ -1,82 +1,15 @@ use anyhow::{ Context, }; -use askama::Template; -use axum::{ - extract::{ - Path, - State, - }, - http::{ - StatusCode, - }, - response::{ - IntoResponse, - Response, - }, - Router, - routing::{ - get, - }, -}; use flake_tracker::{ storage::{ Storage, }, - templates::{ - FlakeListTemplate, - FlakeTemplate, - IndexTemplate, - RevisionTemplate, + web::{ + make_router, }, }; -struct AppError(anyhow::Error); - -impl std::fmt::Display for AppError { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - std::fmt::Display::fmt(&self.0, formatter) - } -} - -impl std::fmt::Debug for AppError { - fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - std::fmt::Debug::fmt(&self.0, formatter) - } -} - -impl IntoResponse for AppError { - fn into_response(self) -> Response { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Internal server error:\n{:?}", self), - ) - .into_response() - } -} - -impl From for AppError where E: Into { - fn from(err: E) -> Self { - Self(err.into()) - } -} - -fn render_template(t: &T) -> anyhow::Result { - let body = t.render() - .context("Failed to render template")?; - - Ok(( - [ - ("Content-Type", T::MIME_TYPE), - ], - body, - ).into_response()) -} - -#[derive(Clone)] -struct AppState { - storage: Storage, -} #[tokio::main] async fn main() -> anyhow::Result<()> { @@ -84,16 +17,8 @@ async fn main() -> anyhow::Result<()> { .await .context("Failed to connect to database")?; - let state = AppState { - storage, - }; - let app = Router::new() - .route("/", get(route_index)) - .route("/flakes", get(route_flakes)) - .route("/f/{uri}", get(route_flake)) - .route("/r/{revision_uri}", get(route_revision)) - .with_state(state); + let app = make_router(storage)?; let listener = tokio::net::TcpListener::bind("[::]:3000") .await @@ -105,38 +30,3 @@ async fn main() -> anyhow::Result<()> { Ok(()) } - -async fn route_index() -> Result { - Ok(render_template(&IndexTemplate {})?) -} - -async fn route_flakes( - State(state): State, -) -> Result { - Ok(render_template(&FlakeListTemplate { - flakes: state.storage.flakes().await?, - })?) -} - -async fn route_flake( - State(state): State, - Path(uri): Path, -) -> Result { - Ok(render_template(&FlakeTemplate { - uri: uri.clone(), - revisions: state.storage.revisions_from_flake(&uri).await?, - current_inputs: state.storage.current_inputs_for_flake(&uri).await?, - })?) -} - -async fn route_revision( - State(state): State, - Path(revision_uri): Path, -) -> Result { - - Ok(render_template(&RevisionTemplate { - revision_uri: revision_uri.clone(), - inputs: state.storage.inputs_for_revision(&revision_uri).await?, - input_of: state.storage.input_of_for_revision(&revision_uri).await?, - })?) -} diff --git a/src/lib.rs b/src/lib.rs index cdf31dd..6dc59b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod flake; pub mod storage; pub mod templates; pub mod utils; +pub mod web; diff --git a/src/web.rs b/src/web.rs new file mode 100644 index 0000000..9217424 --- /dev/null +++ b/src/web.rs @@ -0,0 +1,129 @@ +use anyhow::{ + Context, +}; +use askama::Template; +use axum::{ + extract::{ + Path, + State, + }, + http::{ + StatusCode, + }, + response::{ + IntoResponse, + Response, + }, + Router, + routing::{ + get, + }, +}; +use crate::{ + storage::{ + Storage, + }, + templates::{ + FlakeListTemplate, + FlakeTemplate, + IndexTemplate, + RevisionTemplate, + }, +}; + +struct AppError(anyhow::Error); + +impl std::fmt::Display for AppError { + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Display::fmt(&self.0, formatter) + } +} + +impl std::fmt::Debug for AppError { + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + std::fmt::Debug::fmt(&self.0, formatter) + } +} + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Internal server error:\n{:?}", self), + ) + .into_response() + } +} + +impl From for AppError where E: Into { + fn from(err: E) -> Self { + Self(err.into()) + } +} + +fn render_template(t: &T) -> anyhow::Result { + let body = t.render() + .context("Failed to render template")?; + + Ok(( + [ + ("Content-Type", T::MIME_TYPE), + ], + body, + ).into_response()) +} + +#[derive(Clone)] +struct AppState { + storage: Storage, +} + +pub fn make_router(storage: Storage) -> anyhow::Result { + let state = AppState { + storage, + }; + + let app = Router::new() + .route("/", get(route_index)) + .route("/flakes", get(route_flakes)) + .route("/f/{uri}", get(route_flake)) + .route("/r/{revision_uri}", get(route_revision)) + .with_state(state); + + Ok(app) +} + +async fn route_index() -> Result { + Ok(render_template(&IndexTemplate {})?) +} + +async fn route_flakes( + State(state): State, +) -> Result { + Ok(render_template(&FlakeListTemplate { + flakes: state.storage.flakes().await?, + })?) +} + +async fn route_flake( + State(state): State, + Path(uri): Path, +) -> Result { + Ok(render_template(&FlakeTemplate { + uri: uri.clone(), + revisions: state.storage.revisions_from_flake(&uri).await?, + current_inputs: state.storage.current_inputs_for_flake(&uri).await?, + })?) +} + +async fn route_revision( + State(state): State, + Path(revision_uri): Path, +) -> Result { + + Ok(render_template(&RevisionTemplate { + revision_uri: revision_uri.clone(), + inputs: state.storage.inputs_for_revision(&revision_uri).await?, + input_of: state.storage.input_of_for_revision(&revision_uri).await?, + })?) +}