Menu
Public repository / 11cb359c85449c1aa6d5e0f3eb805b47d18c063d
AkurAI-DNS / src/main.rs
Latest change 1f985ee57c4d7762e35f4e0bd2fbbfe716bf42ee - feat(domains): audited domain lifecycle - certificate-ready state, transitions, events, customer-safe status (AKURAI-DNS-4) by agent
mod dns;
mod health;
mod models;
mod routes;
mod schema;
mod server;
mod zone;
use std::net::SocketAddr;
use std::path::Path;
use std::sync::Arc;
use axum::{Router, routing};
use tokio::sync::RwLock;
use tracing::info;
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() {
// Init tracing
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
)
.init();
// Config from env
let zone_dir = std::env::var("DNS_ZONE_DIR").unwrap_or_else(|_| "/etc/akurai-dns/zones".into());
let listen = std::env::var("DNS_LISTEN").unwrap_or_else(|_| "0.0.0.0".into());
let port: u16 = std::env::var("DNS_PORT")
.ok()
.and_then(|p| p.parse().ok())
.unwrap_or(53);
let api_port: u16 = std::env::var("API_PORT")
.ok()
.and_then(|p| p.parse().ok())
.unwrap_or(8080);
let db_path =
std::env::var("DNS_DB_PATH").unwrap_or_else(|_| "/var/lib/akurai-dns/domains.db".into());
info!(zone_dir = %zone_dir, listen = %listen, port = port, api_port = api_port, db_path = %db_path, "AkurAI DNS starting");
// Init database
let db = routes::init_db(&db_path).expect("failed to initialize database");
// Load zones
let zones = match zone::ZoneSet::load_dir(Path::new(&zone_dir)) {
Ok(z) => z,
Err(e) => {
eprintln!("FATAL: Failed to load zones from {zone_dir}: {e}");
std::process::exit(1);
}
};
let zones = Arc::new(RwLock::new(zones));
health::start();
info!("Zones loaded, starting servers");
// Build HTTP API router
let state = routes::AppState { db };
let api = Router::new()
.route("/api/domains", routing::post(routes::create_domain))
.route("/api/domains", routing::get(routes::list_domains))
.route("/api/domains/{id}", routing::delete(routes::delete_domain))
.route(
"/api/domains/{id}/status",
routing::get(routes::get_domain_status),
)
.route(
"/api/domains/{id}/verify",
routing::post(routes::verify_domain),
)
.route(
"/api/domains/{id}/cert-ready",
routing::post(routes::mark_cert_ready),
)
.route(
"/api/domains/{id}/renew",
routing::post(routes::renew_domain),
)
.route("/api/domains/{id}/fail", routing::post(routes::fail_domain))
.route(
"/api/domains/{id}/retry",
routing::post(routes::retry_domain),
)
.with_state(state);
let api_addr: SocketAddr = format!("{listen}:{api_port}")
.parse()
.expect("invalid API address");
let api_server = tokio::spawn(async move {
info!(addr = %api_addr, "HTTP API listening");
let listener = tokio::net::TcpListener::bind(api_addr).await.unwrap();
axum::serve(listener, api).await.unwrap();
});
// Run DNS server (blocks until exit)
server::run(listen, port, zones, zone_dir).await;
api_server.abort();
}