feat: add domain-based index file selection and request logging

This commit is contained in:
Andrew 2025-05-05 20:03:16 +07:00
parent 7a69ffb8ba
commit 6164836cfc
3 changed files with 135 additions and 35 deletions

104
Cargo.lock generated
View file

@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[package]] [[package]]
name = "actix-codec" name = "actix-codec"
@ -88,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -204,7 +204,7 @@ dependencies = [
"actix-router", "actix-router",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -434,7 +434,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -534,7 +534,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -546,6 +546,29 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]] [[package]]
name = "equivalent" name = "equivalent"
version = "1.0.1" version = "1.0.1"
@ -809,7 +832,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -846,6 +869,30 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "jiff"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]] [[package]]
name = "jobserver" name = "jobserver"
version = "0.1.31" version = "0.1.31"
@ -902,9 +949,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.21" version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
[[package]] [[package]]
name = "memchr" name = "memchr"
@ -1023,6 +1070,21 @@ version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]] [[package]]
name = "powerfmt" name = "powerfmt"
version = "0.2.0" version = "0.2.0"
@ -1037,18 +1099,18 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.85" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.36" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -1177,7 +1239,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -1210,6 +1272,8 @@ dependencies = [
"actix-files", "actix-files",
"actix-web", "actix-web",
"clap", "clap",
"env_logger",
"log",
] ]
[[package]] [[package]]
@ -1282,9 +1346,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.66" version = "2.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1299,7 +1363,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -1632,7 +1696,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
"synstructure", "synstructure",
] ]
@ -1653,7 +1717,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]
@ -1673,7 +1737,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
"synstructure", "synstructure",
] ]
@ -1696,7 +1760,7 @@ checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.66", "syn 2.0.101",
] ]
[[package]] [[package]]

View file

@ -8,3 +8,5 @@ authors = ["Andrew G. <me@nuark.xyz>"]
actix-web = "4.7.0" actix-web = "4.7.0"
actix-files = "0.6.6" actix-files = "0.6.6"
clap = { version = "4.5.7", features = ["derive"] } clap = { version = "4.5.7", features = ["derive"] }
env_logger = "0.11.8"
log = "0.4.27"

View file

@ -1,11 +1,12 @@
use std::path::Path; use std::path::Path;
use std::collections::HashMap;
use actix_files; use actix_files;
use actix_web::{ use actix_web::{
dev::{ServiceRequest, ServiceResponse}, dev::{ServiceRequest, ServiceResponse}, middleware::Logger, App, HttpServer
App, HttpServer,
}; };
use clap::{arg, command, Parser}; use clap::{arg, command, Parser};
use env_logger::Env;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about, long_about = None)] #[command(version, about, long_about = None)]
@ -24,10 +25,23 @@ struct ServantArgs {
#[arg(long, default_value_t = String::from("index.html"))] #[arg(long, default_value_t = String::from("index.html"))]
index_file: String, index_file: String,
#[arg(long = "rewrite-index", value_parser = parse_rewrite_index)]
rewrite_index: Vec<(String, String)>,
}
fn parse_rewrite_index(s: &str) -> Result<(String, String), String> {
let parts: Vec<&str> = s.splitn(2, '=').collect();
if parts.len() != 2 {
return Err("Expected format: domain=path".to_string());
}
Ok((parts[0].to_string(), parts[1].to_string()))
} }
#[actix_web::main] #[actix_web::main]
async fn main() -> std::io::Result<()> { async fn main() -> std::io::Result<()> {
env_logger::init_from_env(Env::new().default_filter_or("info"));
let args = ServantArgs::parse(); let args = ServantArgs::parse();
let bind_addr = format!("{}:{}", args.host, args.port); let bind_addr = format!("{}:{}", args.host, args.port);
@ -39,20 +53,40 @@ async fn main() -> std::io::Result<()> {
.to_string(); .to_string();
let mount_point = args.mount.clone(); let mount_point = args.mount.clone();
let serve_dir = args.serve_dir.clone();
let default_index = args.index_file.clone();
let index_map: HashMap<String, String> = args
.rewrite_index
.into_iter()
.collect();
HttpServer::new(move || { HttpServer::new(move || {
let index_path = index_path.to_owned(); let index_map = index_map.clone();
let default_index = default_index.clone();
let serve_dir = serve_dir.clone();
App::new().service( App::new()
actix_files::Files::new(&mount_point, args.serve_dir.as_str()) .wrap(Logger::default())
.index_file(args.index_file.as_str()) .service(
actix_files::Files::new(&mount_point, &serve_dir)
.index_file(&default_index)
.default_handler(move |req: ServiceRequest| { .default_handler(move |req: ServiceRequest| {
let (http_req, _payload) = req.into_parts(); let (http_req, _payload) = req.into_parts();
let index_path = index_path.to_owned(); let host = http_req
.headers()
.get("Host")
.and_then(|h| h.to_str().ok())
.unwrap_or_default();
async { // Determine the index file based on the host
let response = let index_file = index_map
actix_files::NamedFile::open(index_path)?.into_response(&http_req); .get(host)
.cloned()
.unwrap_or_else(|| format!("{}/{}", serve_dir, default_index));
async move {
let response = actix_files::NamedFile::open(index_file)?.into_response(&http_req);
Ok(ServiceResponse::new(http_req, response)) Ok(ServiceResponse::new(http_req, response))
} }
}), }),