2024-02-06 15:51:30 -05:00
|
|
|
use axum::{
|
2024-02-07 10:12:40 -05:00
|
|
|
extract::{Host, OriginalUri, Json},
|
|
|
|
http::{header::HeaderMap, Method},
|
2024-02-06 15:51:30 -05:00
|
|
|
Router,
|
|
|
|
};
|
2023-01-13 09:56:06 -05:00
|
|
|
use clap::Parser;
|
2023-01-12 15:31:03 -05:00
|
|
|
use serde::Serialize;
|
2024-02-07 10:12:40 -05:00
|
|
|
use serde_json::{json, Value};
|
2023-01-13 09:56:06 -05:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
#[command(author, version, about, long_about = None)]
|
|
|
|
struct CliArgs {
|
|
|
|
/// Port to run on.
|
|
|
|
#[arg(short, long, default_value_t = 8080)]
|
|
|
|
port: u16,
|
|
|
|
|
|
|
|
/// Listen to IP mask
|
|
|
|
#[arg(short, long, default_value = "0.0.0.0")]
|
|
|
|
ips: String,
|
|
|
|
}
|
2023-01-12 15:31:03 -05:00
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
struct EchoHeader {
|
|
|
|
name: String,
|
|
|
|
value: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize)]
|
|
|
|
struct EchoResponse {
|
|
|
|
method: String,
|
|
|
|
path: String,
|
|
|
|
host: String,
|
2023-01-13 09:56:06 -05:00
|
|
|
headers: BTreeMap<String, String>,
|
2024-02-07 10:12:40 -05:00
|
|
|
body: Value,
|
2023-01-12 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2024-02-07 10:12:40 -05:00
|
|
|
async fn echo_request(
|
|
|
|
method: Method,
|
|
|
|
original_uri: OriginalUri,
|
|
|
|
host: Host,
|
|
|
|
header_map: HeaderMap,
|
|
|
|
body: Option<Json<Value>>
|
|
|
|
) -> Json<EchoResponse> {
|
|
|
|
let method = method.to_string();
|
|
|
|
let host = host.0;
|
|
|
|
let path = original_uri.path().to_string();
|
|
|
|
let headers = header_map
|
|
|
|
.iter()
|
|
|
|
.map(|(name, value)| (name.to_string(), value.to_str().unwrap_or("").to_string()))
|
|
|
|
.collect();
|
|
|
|
// TODO: Logging the method and path.
|
2023-01-12 15:31:03 -05:00
|
|
|
|
2024-02-07 10:12:40 -05:00
|
|
|
let json_body = match body {
|
|
|
|
None => {
|
|
|
|
// TODO: Adding logging.
|
|
|
|
json!({"error": "Non-JSON request sent."})
|
|
|
|
},
|
|
|
|
Some(Json(value)) => value,
|
|
|
|
};
|
|
|
|
let response = EchoResponse {
|
|
|
|
method,
|
|
|
|
host,
|
|
|
|
path,
|
|
|
|
headers,
|
|
|
|
body: json_body,
|
|
|
|
};
|
|
|
|
Json(response)
|
2023-01-12 15:31:03 -05:00
|
|
|
}
|
|
|
|
|
2024-02-06 15:51:30 -05:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() {
|
2023-01-13 09:56:06 -05:00
|
|
|
let cli_args = CliArgs::parse();
|
|
|
|
let listen_on = (cli_args.ips, cli_args.port);
|
2024-02-06 15:51:30 -05:00
|
|
|
let listen_on = format!("{ip}:{port}", ip = listen_on.0, port = listen_on.1);
|
|
|
|
|
|
|
|
let app = Router::new().fallback(echo_request);
|
|
|
|
let listener = tokio::net::TcpListener::bind(&listen_on)
|
|
|
|
.await
|
2024-02-07 10:12:40 -05:00
|
|
|
.unwrap_or_else(|_| panic!("Attempted binding to {}", listen_on));
|
2024-02-06 15:51:30 -05:00
|
|
|
axum::serve(listener, app)
|
2023-01-12 15:31:03 -05:00
|
|
|
.await
|
2024-02-06 15:51:30 -05:00
|
|
|
.expect("Server should start");
|
2023-01-12 09:41:47 -05:00
|
|
|
}
|