diff --git a/scripts/watch.sh b/scripts/watch.sh index 0ec22d6..a2ef680 100755 --- a/scripts/watch.sh +++ b/scripts/watch.sh @@ -11,5 +11,5 @@ killall trunk || true # start frontend CARGO_TARGET_DIR=target/frontend trunk serve -w src/frontend/ -w assets/ --proxy-backend http://$IBIS__BIND & # start backend, with separate target folder to avoid rebuilds from arch change - cargo watch -x run + cargo watch --ignore assets/ibis.css --exec run ) diff --git a/src/backend/assets.rs b/src/backend/assets.rs new file mode 100644 index 0000000..4de51a9 --- /dev/null +++ b/src/backend/assets.rs @@ -0,0 +1,87 @@ +use super::error::MyResult; +use anyhow::anyhow; +use axum::{ + body::Body, + extract::Path, + response::{IntoResponse, Response}, + routing::get, + Router, +}; +use axum_macros::debug_handler; +use once_cell::sync::OnceCell; +use reqwest::header::HeaderMap; +use std::fs::read_to_string; + +pub fn asset_routes() -> MyResult> { + Ok(Router::new() + .route("/assets/ibis.css", get(ibis_css)) + .route( + "/assets/simple.css", + get((css_headers(), include_str!("../../assets/simple.css"))), + ) + .route( + "/assets/katex.min.css", + get((css_headers(), include_str!("../../assets/katex.min.css"))), + ) + .route("/assets/fonts/*font", get(get_font)) + .route( + "/assets/index.html", + get(include_str!("../../assets/index.html")), + ) + .route("/pkg/ibis.js", get(serve_js)) + .route("/pkg/ibis_bg.wasm", get(serve_wasm))) +} + +fn css_headers() -> HeaderMap { + static INSTANCE: OnceCell = OnceCell::new(); + INSTANCE + .get_or_init(|| { + let mut css_headers = HeaderMap::new(); + let val = "text/css".parse().expect("valid header value"); + css_headers.insert("Content-Type", val); + css_headers + }) + .clone() +} + +async fn ibis_css() -> MyResult<(HeaderMap, Response)> { + let res = if cfg!(debug_assertions) { + read_to_string("assets/ibis.css")?.into_response() + } else { + include_str!("../../assets/ibis.css").into_response() + }; + Ok((css_headers(), res)) +} + +#[debug_handler] +async fn serve_js() -> MyResult { + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", "application/javascript".parse()?); + let content = include_str!("../../assets/dist/ibis.js"); + Ok((headers, content)) +} + +#[debug_handler] +async fn serve_wasm() -> MyResult { + let mut headers = HeaderMap::new(); + headers.insert("Content-Type", "application/wasm".parse()?); + let content = include_bytes!("../../assets/dist/ibis_bg.wasm"); + Ok((headers, content)) +} + +#[debug_handler] +async fn get_font(Path(font): Path) -> MyResult { + let mut headers = HeaderMap::new(); + let content_type = if font.ends_with(".ttf") { + "font/ttf" + } else if font.ends_with(".woff") { + "font/woff" + } else if font.ends_with(".woff2") { + "font/woff2" + } else { + return Err(anyhow!("invalid font").into()); + }; + headers.insert("Content-type", content_type.parse()?); + let content = std::fs::read("assets/fonts/".to_owned() + &font)?; + Ok((headers, content)) +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs index e75eb20..f119946 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -22,17 +22,16 @@ use activitypub_federation::{ http_signatures::generate_actor_keypair, }; use api::api_routes; +use assets::asset_routes; use axum::{ body::Body, - extract::Path, http::{HeaderValue, Request}, middleware::Next, - response::{IntoResponse, Response}, - routing::get, + response::Response, Router, ServiceExt, }; -use axum_macros::{debug_handler, debug_middleware}; +use axum_macros::debug_middleware; use chrono::Local; use diesel::{ r2d2::{ConnectionManager, Pool}, @@ -42,12 +41,12 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use leptos::leptos_config::get_config_from_str; use leptos_axum::{generate_route_list, LeptosRoutes}; use log::info; -use reqwest::header::HeaderMap; use tokio::net::TcpListener; use tower_http::cors::CorsLayer; use tower_layer::Layer; pub mod api; +mod assets; pub mod config; pub mod database; pub mod error; @@ -110,64 +109,6 @@ pub async fn start(config: IbisConfig) -> MyResult<()> { Ok(()) } -pub fn asset_routes() -> MyResult> { - let mut css_headers = HeaderMap::new(); - css_headers.insert("Content-Type", "text/css".parse()?); - Ok(Router::new() - .route( - "/assets/ibis.css", - get((css_headers.clone(), include_str!("../../assets/ibis.css"))), - ) - .route( - "/assets/simple.css", - get((css_headers.clone(), include_str!("../../assets/simple.css"))), - ) - .route( - "/assets/katex.min.css", - get((css_headers, include_str!("../../assets/katex.min.css"))), - ) - .route("/assets/fonts/*font", get(get_font)) - .route( - "/assets/index.html", - get(include_str!("../../assets/index.html")), - ) - .route("/pkg/ibis.js", get(serve_js)) - .route("/pkg/ibis_bg.wasm", get(serve_wasm))) -} - -#[debug_handler] -async fn serve_js() -> MyResult { - let mut headers = HeaderMap::new(); - headers.insert("Content-Type", "application/javascript".parse()?); - let content = include_str!("../../assets/dist/ibis.js"); - Ok((headers, content)) -} - -#[debug_handler] -async fn serve_wasm() -> MyResult { - let mut headers = HeaderMap::new(); - headers.insert("Content-Type", "application/wasm".parse()?); - let content = include_bytes!("../../assets/dist/ibis_bg.wasm"); - Ok((headers, content)) -} - -#[debug_handler] -async fn get_font(Path(font): Path) -> MyResult { - let mut headers = HeaderMap::new(); - let content_type = if font.ends_with(".ttf") { - "font/ttf" - } else if font.ends_with(".woff") { - "font/woff" - } else if font.ends_with(".woff2") { - "font/woff2" - } else { - "" - }; - headers.insert("Content-type", content_type.parse()?); - let content = std::fs::read("assets/fonts/".to_owned() + &font).expect("Can't open katex font"); - Ok((headers, content)) -} - const MAIN_PAGE_DEFAULT_TEXT: &str = "Welcome to Ibis, the federated Wikipedia alternative! This main page can only be edited by the admin. Use it as an introduction for new users, \