use std::net::SocketAddr;
use std::time::Instant;
use tachyon_web::http::header::AUTHORIZATION;
use tachyon_web::http::{Request, StatusCode};
use tachyon_web::{
MiddlewarePosition, Next, Router,
response::{Body, IntoResponse},
routing::get,
};
#[derive(Clone)]
struct AppState {
expected_token: String,
}
async fn request_timer(req: Request<Body>, next: Next<AppState>) -> impl IntoResponse {
let start = Instant::now();
let path = req.uri().path().to_owned();
println!("⏱️ [Timer Middleware] Entering for path: {path}");
let response = next.run(req).await;
println!(
"⏱️ [Timer Middleware] Exiting for path: {}: took {:?}",
path,
start.elapsed()
);
response
}
async fn mock_auth(req: Request<Body>, next: Next<AppState>) -> impl IntoResponse {
let path = req.uri().path().to_owned();
println!("🔑 [Auth Middleware] Checking authorization for: {path}");
let state = next.state();
let expected_auth_header = format!("Bearer {}", state.expected_token);
let is_authorized = req
.headers()
.get(AUTHORIZATION)
.and_then(|h| h.to_str().ok())
.is_some_and(|val| val == expected_auth_header);
if is_authorized {
println!("🔑 [Auth Middleware] Authorized successfully!");
next.run(req).await
} else {
println!("🔑 [Auth Middleware] Authorization failed!");
(
StatusCode::UNAUTHORIZED,
"Missing or invalid authorization token",
)
.into_response()
}
}
async fn index() -> &'static str {
"Welcome! This endpoint is public and does not require authentication."
}
async fn secure_data() -> &'static str {
"Top-secret database info accessed successfully!"
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let state = AppState {
expected_token: "secret-token-123".to_string(),
};
let secure_router = Router::new()
.route("/data", get(secure_data))
.hoop_at(MiddlewarePosition::First, mock_auth);
let app = Router::new()
.route("/", get(index))
.nest("/secure", secure_router)
.hoop(request_timer)
.with_state(state);
let addr = SocketAddr::from(([127, 0, 0, 1], 8080));
println!("🚀 Stateful & Ordered Scoped Middleware server running at http://{addr}");
println!(" - Visit public endpoint (bypasses auth, runs only timer): http://{addr}");
println!(
" - Visit secure endpoint (returns 401, runs timer + auth): http://{addr}/secure/data"
);
println!(" - Test with valid token via curl (runs timer + auth):");
println!(" curl -H \"Authorization: Bearer secret-token-123\" http://{addr}/secure/data");
let listener = tokio::net::TcpListener::bind(addr).await?;
tachyon_web::serve(listener, app).await?;
Ok(())
}