#![allow(dead_code)]
mod admin;
mod cache;
mod cmf_runtime;
mod config;
mod error;
mod import;
mod model;
mod pipeline;
mod promotion;
mod protocols;
mod providers;
mod registry;
mod router_client;
mod routing;
mod secrets;
mod state;
mod stats;
use axum::{routing::get, Router};
use clap::Parser;
use config::Config;
use state::SharedState;
#[derive(Parser)]
#[command(
name = "cortiq-gateway",
version,
about = "Universal LLM gateway with intelligent routing"
)]
struct Args {
#[arg(long, default_value = "config/gateway.toml")]
config: String,
#[arg(long)]
admin_token: Option<String>,
}
fn resolve_admin_token(cfg: &Config, args: &Args) -> (String, bool) {
if let Some(env) = &cfg.admin.token_env {
if let Ok(v) = std::env::var(env) {
if !v.is_empty() {
return (v, false);
}
}
}
if let Some(t) = &args.admin_token {
if !t.is_empty() {
return (t.clone(), false);
}
}
(admin::random_token(24), true)
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args = Args::parse();
let cfg = Config::load(&args.config)?;
tracing_subscriber::fmt()
.with_env_filter(
tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| cfg.log.level.clone().into()),
)
.init();
let listen = cfg.listen.clone();
let admin_enabled = cfg.admin.enabled;
let (admin_token, generated) = resolve_admin_token(&cfg, &args);
let state = SharedState::build(cfg, args.config.clone())?;
{
let cmf_rt = state.cmf.clone();
let cmf_cfg = state.live().cfg.cmf.clone();
tokio::spawn(async move { cmf_runtime::manage(cmf_rt, cmf_cfg).await });
}
let mut app = Router::new()
.route("/healthz", get(|| async { "ok" }))
.route("/readyz", get(|| async { "ready" }))
.route("/metrics", get(admin::metrics))
.merge(protocols::build_router());
if admin_enabled {
app = app
.merge(admin::api_routes(admin_token.clone()))
.fallback(admin::assets::fallback);
}
let app = app.with_state(state);
let listener = tokio::net::TcpListener::bind(&listen).await?;
tracing::info!("cortiq-gateway listening on {listen}");
if admin_enabled {
tracing::info!("admin console: http://{listen}/admin");
if generated {
tracing::warn!(
"admin token (auto-generated, set [admin].token_env to persist): {admin_token}"
);
}
}
axum::serve(listener, app).await?;
Ok(())
}