Menu
Public repository / 0150c3705544adc2275b2871151545a61bdb741c
AkurAI-DNS / src/health.rs
Latest change 26c909314920ab20df94cca011f96d1fa6df9138 - Add loopback health listener by agent
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::thread;
use tracing::{error, info, warn};
const DEFAULT_PORT: u16 = 8053;
const BODY: &str = concat!(
r#"{"app":"akurai-dns","version":""#,
env!("CARGO_PKG_VERSION"),
r#"","status":"ok"}"#,
);
fn response() -> String {
format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n{}",
BODY.len(),
BODY
)
}
fn handle(mut stream: TcpStream) {
let mut request = [0_u8; 1024];
if let Err(err) = stream.read(&mut request) {
warn!(error = %err, "Health request read failed");
return;
}
if let Err(err) = stream.write_all(response().as_bytes()) {
warn!(error = %err, "Health response write failed");
}
}
pub fn start() {
let port = std::env::var("MONITOR_HEALTH_PORT")
.ok()
.and_then(|value| value.parse().ok())
.unwrap_or(DEFAULT_PORT);
let address = format!("127.0.0.1:{port}");
let listener = match TcpListener::bind(&address) {
Ok(listener) => listener,
Err(err) => {
error!(address = %address, error = %err, "Health listener failed to bind");
return;
}
};
info!(address = %address, "Health listener started");
thread::spawn(move || {
for connection in listener.incoming() {
match connection {
Ok(stream) => handle(stream),
Err(err) => error!(error = %err, "Health listener accept failed"),
}
}
});
}
#[cfg(test)]
mod tests {
use super::response;
#[test]
fn response_has_monitor_health_shape() {
let response = response();
let (headers, body) = response.split_once("\r\n\r\n").unwrap();
assert!(headers.starts_with("HTTP/1.1 200 OK\r\n"));
assert!(headers.contains("Content-Type: application/json\r\n"));
assert_eq!(body, super::BODY);
assert!(body.contains(r#""app":"akurai-dns""#));
assert!(body.contains(&format!(r#""version":"{}""#, env!("CARGO_PKG_VERSION"))));
assert!(body.contains(r#""status":"ok""#));
}
}