diff --git a/Cargo.lock b/Cargo.lock index 6aab3d8..53c3141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,61 @@ dependencies = [ "password-hash", ] +[[package]] +name = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", + "humansize", + "num-traits", + "percent-encoding", +] + +[[package]] +name = "askama_axum" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41603f7cdbf5ac4af60760f17253eb6adf6ec5b6f14a7ed830cf687d375f163" +dependencies = [ + "askama", + "axum-core", + "http", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -174,6 +229,15 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + [[package]] name = "bitflags" version = "2.4.2" @@ -408,6 +472,7 @@ dependencies = [ "dotenvy", "frontend", "jsonwebtoken", + "mime_guess", "rand_core", "serde", "serde_json", @@ -444,7 +509,10 @@ dependencies = [ name = "frontend" version = "0.1.0" dependencies = [ + "askama", + "askama_axum", "npm_rs", + "rust-embed", ] [[package]] @@ -592,6 +660,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humansize" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" +dependencies = [ + "libm", +] + [[package]] name = "hyper" version = "1.2.0" @@ -703,6 +780,12 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "log" version = "0.4.21" @@ -757,6 +840,22 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.7.2" @@ -777,6 +876,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "npm_rs" version = "1.0.0" @@ -1022,6 +1131,40 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rust-embed" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -1040,6 +1183,15 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "serde" version = "1.0.197" @@ -1102,6 +1254,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1427,6 +1590,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -1467,6 +1639,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1543,6 +1725,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 21ca6e0..7770e05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ jsonwebtoken = "9.2.0" axum-extra = { version = "0.9.2", features = ["cookie"] } tower-http = { version = "0.5.2", features = ["trace", "cors"] } frontend = { version = "0.1.0", path = "crates/frontend" } +mime_guess = "2.0.4" [workspace] members = ["crates/frontend"] diff --git a/crates/frontend/Cargo.toml b/crates/frontend/Cargo.toml index c327284..f6d73d0 100644 --- a/crates/frontend/Cargo.toml +++ b/crates/frontend/Cargo.toml @@ -5,3 +5,8 @@ edition = "2021" [build-dependencies] npm_rs = "1.0.0" + +[dependencies] +askama = { version = "0.12.1", features = ["with-axum"] } +askama_axum = "0.4.0" +rust-embed = "8.3.0" diff --git a/crates/frontend/askama.toml b/crates/frontend/askama.toml new file mode 100644 index 0000000..0279753 --- /dev/null +++ b/crates/frontend/askama.toml @@ -0,0 +1,2 @@ +[general] +dirs = ["dist"] diff --git a/crates/frontend/build.rs b/crates/frontend/build.rs index 54d3793..12910f1 100644 --- a/crates/frontend/build.rs +++ b/crates/frontend/build.rs @@ -1,11 +1,14 @@ use npm_rs::*; fn main() { - let exit_status = NpmEnv::default() + // TODO: add cargo:rerun-if-changed for important files + + NpmEnv::default() .with_node_env(&NodeEnv::from_cargo_profile().unwrap_or_default()) .with_env("FOO", "bar") .init_env() .install(None) .run("build") - .exec(); + .exec() + .unwrap(); } diff --git a/crates/frontend/src/lib.rs b/crates/frontend/src/lib.rs index e69de29..a6192fd 100644 --- a/crates/frontend/src/lib.rs +++ b/crates/frontend/src/lib.rs @@ -0,0 +1,15 @@ +use askama_axum::Template; +use rust_embed::RustEmbed; + +#[derive(RustEmbed)] +#[folder = "dist/assets/"] +pub struct Assets; + +#[derive(Template)] +#[template(path = "index.html")] +pub struct HomeTemplate; + +#[test] +fn test_render() { + println!("{}", HomeTemplate.render().unwrap()); +} diff --git a/crates/frontend/vite.config.ts b/crates/frontend/vite.config.ts index 8b33c7a..7261a11 100644 --- a/crates/frontend/vite.config.ts +++ b/crates/frontend/vite.config.ts @@ -5,6 +5,8 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' +// TODO:move index.html to src + // https://vitejs.dev/config/ export default defineConfig({ //base: '/', diff --git a/src/main.rs b/src/main.rs index 2aeaeae..4d2ea16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,11 @@ pub mod state; use axum::{ extract::State, http::{ - header::{ACCEPT, AUTHORIZATION, ORIGIN}, - HeaderValue, Method, StatusCode, + header::{ACCEPT, AUTHORIZATION, CONTENT_TYPE, ORIGIN}, + HeaderValue, Method, StatusCode, Uri, }, middleware, - response::Json, + response::{IntoResponse, Json, Response}, routing::{get, post}, Router, }; @@ -70,6 +70,8 @@ async fn main() { //.allow_credentials(true); //"http://localhost:5173".parse::().unwrap()); let app = Router::new() + .route("/", get(home)) + .route("/assets/*file", get(static_handler)) .route("/api/v1/register_user", post(api::v1::register_user)) .route("/api/v1/login_user", post(api::v1::login_user)) .layer(cors) @@ -98,6 +100,10 @@ async fn main() { .unwrap(); } +async fn home() -> impl IntoResponse { + frontend::HomeTemplate +} + async fn users( State(state): State>, ) -> Result>, (StatusCode, Json)> { @@ -114,6 +120,35 @@ async fn users( Ok(Json(result)) } +async fn static_handler(uri: Uri) -> impl IntoResponse { + let mut path = uri.path().trim_start_matches('/').to_string(); + + if path.starts_with("assets/") { + path = path.replace("assets/", ""); + } + + StaticFile(path) +} + +pub struct StaticFile(pub T); + +impl IntoResponse for StaticFile +where + T: Into, +{ + fn into_response(self) -> Response { + let path = self.0.into(); + + match frontend::Assets::get(path.as_str()) { + Some(content) => { + let mime = mime_guess::from_path(path).first_or_octet_stream(); + ([(CONTENT_TYPE, mime.as_ref())], content.data).into_response() + } + None => (StatusCode::NOT_FOUND, "404 Not Found").into_response(), + } + } +} + /* create_user( connection,