use std::time::Duration;
use axum::{
response::IntoResponse,
routing::{get, post},
Json, Router,
};
use serde_json::json;
async fn health() -> impl IntoResponse {
Json(json!({ "status": "ready" }))
}
async fn info() -> impl IntoResponse {
Json(json!({
"name": "fastworker",
"worker_type": "benchmark",
"resources": {
"cpus_total": 64.0, "cpus_available": 64.0,
"memory_total": 64u64 * 1024 * 1024 * 1024,
"memory_available": 64u64 * 1024 * 1024 * 1024,
"gpus_total": 0, "gpus_available": 0
},
"pricing": { "price_per_hour": 0.0, "min_charge": 0.0 },
"tags": []
}))
}
async fn execute() -> impl IntoResponse {
let delay_us: u64 = std::env::var("FW_DELAY_US")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(0);
if delay_us > 0 {
tokio::time::sleep(Duration::from_micros(delay_us)).await;
}
(
[(axum::http::header::CONTENT_TYPE, "application/octet-stream")],
b"ok".to_vec(),
)
}
fn parse_ports(s: &str) -> Vec<u16> {
if let Some((a, b)) = s.split_once('-') {
let a: u16 = a.trim().parse().expect("bad start port");
let b: u16 = b.trim().parse().expect("bad end port");
(a..=b).collect()
} else {
s.split(',').filter_map(|p| p.trim().parse().ok()).collect()
}
}
fn main() {
let ports = parse_ports(&std::env::var("FW_PORTS").unwrap_or_else(|_| "3960-3967".into()));
let threads: usize = std::env::var("FW_THREADS")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(4);
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(threads)
.enable_all()
.build()
.unwrap();
rt.block_on(async move {
let mut handles = Vec::new();
for port in ports.clone() {
let app = Router::new()
.route("/health", get(health))
.route("/info", get(info))
.route("/", post(execute))
.route("/execute", post(execute));
let addr = format!("127.0.0.1:{port}");
let listener = tokio::net::TcpListener::bind(&addr)
.await
.unwrap_or_else(|e| panic!("bind {addr}: {e}"));
handles.push(tokio::spawn(async move {
axum::serve(listener, app).await.unwrap();
}));
}
eprintln!(
"[fastworker] serving {} ports {:?} on {} threads (FW_DELAY_US={})",
ports.len(),
(ports.first(), ports.last()),
threads,
std::env::var("FW_DELAY_US").unwrap_or_else(|_| "0".into())
);
for h in handles {
let _ = h.await;
}
});
}