use std::env::var;
use std::process::ExitCode;
use std::time::Duration;
use tokio::net::TcpListener;
use tracing::{error, info};
use tracing_subscriber::EnvFilter;
use tracing_subscriber::fmt;
use ironflow_auth_proxy::{AuthProxyConfig, AuthProxyState, MIN_ADMIN_KEY_LEN, serve, spawn_purge};
use ironflow_core::auth_proxy::{ADMIN_KEY_ENV, DEFAULT_UPSTREAM};
const LISTEN_ENV: &str = "IRONFLOW_AUTH_PROXY_LISTEN";
const DEFAULT_LISTEN: &str = "0.0.0.0:8080";
const PURGE_INTERVAL: Duration = Duration::from_secs(60);
#[tokio::main]
async fn main() -> ExitCode {
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
fmt().json().with_env_filter(filter).init();
let listen = var(LISTEN_ENV)
.ok()
.filter(|value| !value.is_empty())
.unwrap_or_else(|| DEFAULT_LISTEN.to_string());
let admin_key = var(ADMIN_KEY_ENV)
.map(|key| key.trim().to_string())
.unwrap_or_default();
if admin_key.len() < MIN_ADMIN_KEY_LEN {
error!("{ADMIN_KEY_ENV} must be set to at least {MIN_ADMIN_KEY_LEN} characters");
return ExitCode::FAILURE;
}
let state = match AuthProxyState::new(AuthProxyConfig::new(&admin_key)) {
Ok(state) => state,
Err(e) => {
error!(error = %e, "cannot build the upstream HTTP client");
return ExitCode::FAILURE;
}
};
let listener = match TcpListener::bind(&listen).await {
Ok(listener) => listener,
Err(e) => {
error!(listen = %listen, error = %e, "cannot bind the listen address");
return ExitCode::FAILURE;
}
};
info!(listen = %listen, upstream = DEFAULT_UPSTREAM, "ironflow-auth-proxy listening");
let purge = spawn_purge(state.registry().clone(), PURGE_INTERVAL);
let result = serve(listener, state).await;
purge.abort();
match result {
Ok(()) => ExitCode::SUCCESS,
Err(e) => {
error!(error = %e, "server stopped");
ExitCode::FAILURE
}
}
}