89 lines
2.7 KiB
Rust
89 lines
2.7 KiB
Rust
|
use std::{
|
||
|
env,
|
||
|
process::{exit, Command},
|
||
|
time::Duration,
|
||
|
};
|
||
|
|
||
|
use axum::{
|
||
|
error_handling::HandleErrorLayer, extract::Path, http::StatusCode, response::Html,
|
||
|
routing::get, BoxError, Router,
|
||
|
};
|
||
|
|
||
|
use tower::{buffer::BufferLayer, limit::rate::RateLimitLayer, ServiceBuilder};
|
||
|
|
||
|
#[tokio::main]
|
||
|
async fn main() {
|
||
|
// initialize tracing
|
||
|
tracing_subscriber::fmt::init();
|
||
|
|
||
|
// idk how to have one rate limiting block apply to both of these but this works so it's fine
|
||
|
let app = Router::new()
|
||
|
.route(
|
||
|
"/:name",
|
||
|
get(command).layer(
|
||
|
ServiceBuilder::new()
|
||
|
.layer(HandleErrorLayer::new(|err: BoxError| async move {
|
||
|
(
|
||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||
|
format!("Unhandled error: {err}"),
|
||
|
)
|
||
|
}))
|
||
|
.layer(BufferLayer::new(1024))
|
||
|
.layer(RateLimitLayer::new(5, Duration::from_secs(1))),
|
||
|
),
|
||
|
)
|
||
|
.route(
|
||
|
"/",
|
||
|
get(StatusCode::BAD_REQUEST).layer(
|
||
|
ServiceBuilder::new()
|
||
|
.layer(HandleErrorLayer::new(|err: BoxError| async move {
|
||
|
(
|
||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||
|
format!("Unhandled error: {err}"),
|
||
|
)
|
||
|
}))
|
||
|
.layer(BufferLayer::new(1024))
|
||
|
.layer(RateLimitLayer::new(5, Duration::from_secs(1))),
|
||
|
),
|
||
|
);
|
||
|
|
||
|
let args: Vec<String> = env::args().collect();
|
||
|
if args.len() < 2 {
|
||
|
println!("Provide a port with manserve $PORT");
|
||
|
exit(1);
|
||
|
}
|
||
|
if args[1].parse::<u16>().is_ok() {
|
||
|
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", args[1]))
|
||
|
.await
|
||
|
.unwrap();
|
||
|
println!("Starting server on port {}", args[1]);
|
||
|
axum::serve(listener, app).await.unwrap();
|
||
|
} else {
|
||
|
println!("Could not parse port {}", args[1]);
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async fn command(Path(name): Path<String>) -> Result<Html<String>, StatusCode> {
|
||
|
let mut manpage_loc = String::from_utf8(
|
||
|
Command::new("man")
|
||
|
.args(["-w", name.as_str()])
|
||
|
.output()
|
||
|
.unwrap()
|
||
|
.stdout,
|
||
|
)
|
||
|
.unwrap();
|
||
|
manpage_loc.pop();
|
||
|
let man = Command::new("mandoc")
|
||
|
.arg("-Thtml")
|
||
|
.arg("-O")
|
||
|
.arg("fragment")
|
||
|
.arg(manpage_loc)
|
||
|
.output()
|
||
|
.unwrap();
|
||
|
match man.status.success() {
|
||
|
true => Ok(Html(String::from_utf8(man.stdout).unwrap())),
|
||
|
false => Err(StatusCode::BAD_REQUEST),
|
||
|
}
|
||
|
}
|