Compare commits

...

2 commits

Author SHA1 Message Date
8ec6c9aead Merge pull request 'switch warp for axum' (#1) from axum into main
Reviewed-on: #1
2026-04-26 20:29:01 +00:00
0e503a952e switch warp for axum 2026-04-26 15:45:52 -04:00
4 changed files with 176 additions and 190 deletions

272
Cargo.lock generated
View file

@ -33,10 +33,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base64"
version = "0.22.1"
name = "axum"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90"
dependencies = [
"axum-core",
"bytes",
"form_urlencoded",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"itoa",
"matchit",
"memchr",
"mime",
"percent-encoding",
"pin-project-lite",
"serde_core",
"serde_json",
"serde_path_to_error",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tower",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "axum-core"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1"
dependencies = [
"bytes",
"futures-core",
"http",
"http-body",
"http-body-util",
"mime",
"pin-project-lite",
"sync_wrapper",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "bitflags"
@ -190,12 +236,6 @@ dependencies = [
"crypto-common",
]
[[package]]
name = "equivalent"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
@ -212,12 +252,6 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "form_urlencoded"
version = "1.2.2"
@ -261,9 +295,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6"
dependencies = [
"futures-core",
"futures-sink",
"futures-task",
"pin-project-lite",
"slab",
]
[[package]]
@ -311,55 +345,6 @@ dependencies = [
"walkdir",
]
[[package]]
name = "h2"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54"
dependencies = [
"atomic-waker",
"bytes",
"fnv",
"futures-core",
"futures-sink",
"http",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "hashbrown"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "headers"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb"
dependencies = [
"base64",
"bytes",
"headers-core",
"http",
"httpdate",
"mime",
"sha1",
]
[[package]]
name = "headers-core"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
"http",
]
[[package]]
name = "http"
version = "1.4.0"
@ -393,6 +378,12 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "http-range-header"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9171a2ea8a68358193d15dd5d70c1c10a2afc3e7e4c5bc92bc9f025cebd7359c"
[[package]]
name = "httparse"
version = "1.10.1"
@ -424,7 +415,6 @@ dependencies = [
"bytes",
"futures-channel",
"futures-core",
"h2",
"http",
"http-body",
"httparse",
@ -490,16 +480,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "itoa"
version = "1.0.18"
@ -549,6 +529,12 @@ version = "0.4.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "matchit"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "memchr"
version = "2.8.0"
@ -716,26 +702,6 @@ dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517"
dependencies = [
"pin-project-internal",
]
[[package]]
name = "pin-project-internal"
version = "1.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "pin-project-lite"
version = "0.2.17"
@ -858,12 +824,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -912,6 +872,17 @@ dependencies = [
"zmij",
]
[[package]]
name = "serde_path_to_error"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457"
dependencies = [
"itoa",
"serde",
"serde_core",
]
[[package]]
name = "serde_urlencoded"
version = "0.7.1"
@ -924,17 +895,6 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.9"
@ -1011,6 +971,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "sync_wrapper"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
[[package]]
name = "tera"
version = "1.20.1"
@ -1074,6 +1040,54 @@ dependencies = [
"tokio",
]
[[package]]
name = "tower"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4"
dependencies = [
"futures-core",
"futures-util",
"pin-project-lite",
"sync_wrapper",
"tokio",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-http"
version = "0.6.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8"
dependencies = [
"bitflags",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
"http-range-header",
"httpdate",
"mime",
"mime_guess",
"percent-encoding",
"pin-project-lite",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]]
name = "tower-layer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
[[package]]
name = "tower-service"
version = "0.3.3"
@ -1146,35 +1160,6 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "warp"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d06d9202adc1f15d709c4f4a2069be5428aa912cc025d6f268ac441ab066b0"
dependencies = [
"bytes",
"futures-util",
"headers",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"log",
"mime",
"mime_guess",
"percent-encoding",
"pin-project",
"scoped-tls",
"serde",
"serde_json",
"serde_urlencoded",
"tokio",
"tokio-util",
"tower-service",
"tracing",
]
[[package]]
name = "wasi"
version = "0.11.1+wasi-snapshot-preview1"
@ -1230,10 +1215,11 @@ dependencies = [
name = "website"
version = "0.1.0"
dependencies = [
"axum",
"lazy_static",
"tera",
"tokio",
"warp",
"tower-http",
]
[[package]]

View file

@ -4,7 +4,8 @@ version = "0.1.0"
edition = "2021"
[dependencies]
axum = "0.8.9"
lazy_static = "1.5.0"
tera = "1.20.1"
tokio = { version = "1", features = ["full"] }
warp = { version = "0.4", features = ["server"] }
tower-http = { version = "0.6.8", features = ["fs"] }

View file

@ -1,6 +1,19 @@
use std::collections::HashMap;
use tera::{Context, Tera};
use warp::{Filter, filters::path::Tail, Reply, Rejection};
use warp::hyper::StatusCode;
use axum::{
Router,
response::{
Html,
Redirect
},
extract::Path,
routing::get,
http::{
header::{HeaderMap, ACCEPT_LANGUAGE},
StatusCode
}
};
use tower_http::services::{ServeDir, ServeFile};
lazy_static::lazy_static! {
pub static ref TEMPLATES: Tera = Tera::new("templates/**/*").expect("failed to parse templates");
@ -8,51 +21,37 @@ lazy_static::lazy_static! {
#[tokio::main]
async fn main() {
let static_pages = warp::fs::dir("static");
let serve_dir = ServeDir::new("static").not_found_service(ServeFile::new("static/404.html"));
for name in TEMPLATES.get_template_names() {
println!("Loaded template {}", name);
let app = Router::new()
.route("/", get(language_redirect))
.route("/{lang}/", get(render_template))
.route("/{lang}/{*tail}", get(render_template))
.fallback_service(serve_dir);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3030").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
let templates = warp::get()
.and(warp::path::param::<String>())
.and(warp::path::tail())
.and_then(render_template);
let root = warp::path::end()
.and(warp::header::optional::<String>("accept-language"))
.map(|lang: Option<String>| {
let target = match lang {
Some(l) if l.starts_with("fr") => "/fr/",
_ => "/en/",
};
warp::redirect(warp::http::Uri::from_static(target))
});
let routes = root.or(static_pages)
.or(templates)
.recover(handle_rejection);
warp::serve(routes)
.run(([0,0,0,0], 3030))
.await;
}
async fn handle_rejection(err: Rejection) -> Result<impl Reply, std::convert::Infallible> {
let code;
let message;
if err.is_not_found() {
code = StatusCode::NOT_FOUND;
message = std::fs::read_to_string("static/404.html").expect("/static/404.html must exist for 404 redirects");
async fn language_redirect(headers: HeaderMap) -> Redirect {
let lang = headers
.get(ACCEPT_LANGUAGE)
.and_then(|value| value.to_str().ok())
.map(|s| {
if s.to_lowercase().starts_with("fr") {
"fr"
} else {
code = StatusCode::INTERNAL_SERVER_ERROR;
message = String::from("Internal server error");
"en"
}
Ok(warp::reply::with_status(warp::reply::html(message), code))
}).unwrap_or("en");
Redirect::to(&format!("/{}/", lang))
}
async fn render_template(Path(params): Path<HashMap<String,String>>) -> Result<Html<String>, StatusCode> {
let lang = params.get("lang").ok_or(StatusCode::BAD_REQUEST)?;
let tail = params.get("tail").map(|s| s.as_str()).unwrap_or("index.html");
async fn render_template(lang: String, tail: Tail) -> Result<impl Reply, Rejection> {
let mut path = format!("{lang}/{}", tail.as_str());
let mut path = format!("{lang}/{tail}");
if path.is_empty() || path.ends_with('/') {
path.push_str("index.html");
}
@ -61,10 +60,10 @@ async fn render_template(lang: String, tail: Tail) -> Result<impl Reply, Rejecti
context.insert("lang", &lang);
match TEMPLATES.render(&path, &context) {
Ok(html) => Ok(warp::reply::html(html)),
Ok(html) => Ok(Html(html)),
Err(e) => {
eprintln!("Tera error: {}", e);
Err(warp::reject::not_found())
Err(StatusCode::NOT_FOUND)
}
}
}

View file

@ -13,9 +13,9 @@
{% macro nav() %}
<nav>
{% if lang == "fr" %}
<a href="/">Accueil</a>
<a href="/fr/">Accueil</a>
{% else %}
<a href="/">Home</a>
<a href="/en/">Home</a>
{% endif %}
</nav>
{% endmacro %}