athena_rs 0.75.4

WIP Database API gateway
Documentation
use actix_web::{HttpRequest, HttpResponse};
use serde_json::{Value, json};
use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;

use crate::drivers::supabase::supabase;

// crate
use crate::api::headers::{x_company_id, x_user_id};

pub fn log_request(req: HttpRequest) -> Value {
    // Extract all the data synchronously (cheap, no await)
    let user_id: String = x_user_id::get_x_user_id(&req).unwrap_or_else(|| "NOT_FOUND".to_string());
    let company_id: String =
        x_company_id::get_x_company_id(&req).unwrap_or_else(|| "NOT_FOUND".to_string());

    let request_id: String = Uuid::new_v4().to_string();

    let body_json: Value = req
        .match_info()
        .get("body")
        .and_then(|body| serde_json::from_str(body).ok())
        .unwrap_or_else(|| json!({}));

    let query_string: &str = req.query_string();
    let query_string: String = if query_string.is_empty() {
        "NOT_FOUND".to_string()
    } else {
        query_string.to_string()
    };

    let headers: HashMap<String, String> = req
        .headers()
        .iter()
        .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or("").to_string()))
        .collect::<HashMap<_, _>>();

    let method: &str = req.method().as_str();
    let path: &str = req.path();
    let status_http_code: u16 = req
        .app_data::<HttpResponse>()
        .map(|resp| resp.status().as_u16())
        .unwrap_or(0);

    // first look in the headers for x-real-ip
    let x_real_ip: String = headers
        .get("X-Real-IP")
        .unwrap_or(&"NOT_FOUND".to_string())
        .to_string();

    let user_agent: String = req
        .headers()
        .get("User-Agent")
        .and_then(|v| v.to_str().ok())
        .unwrap_or_else(|| "NOT_FOUND")
        .to_string();

    // if user_agent is "Better Stack Better Uptime Bot Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
    // then return empty json
    if user_agent
        == "Better Stack Better Uptime Bot Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"
    {
        return json!({});
    }

    let time: u64 = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_else(|_| std::time::Duration::new(0, 0))
        .as_secs();

    let host: String = req
        .headers()
        .get("Host")
        .and_then(|v| v.to_str().ok())
        .unwrap_or_else(|| "NOT_FOUND")
        .to_string();

    let cache_control: String = req
        .headers()
        .get("Cache-Control")
        .and_then(|v| v.to_str().ok())
        .unwrap_or_else(|| "NOT_FOUND")
        .to_string();

    // if cache_control is "no-cache" then set cached to false
    let cached: bool = if cache_control == "no-cache" {
        false
    } else {
        true
    };

    let request_data: Value = json!({
        "object": "request",
        "request_id": request_id,
        "user_id": user_id,
        "company_id": company_id,
        "body": body_json,
        "query_string": query_string,
        "headers": headers,
        "method": method,
        "path": path,
        "http_code": status_http_code,
        "ipv4": x_real_ip,
        "user_agent": user_agent,
        "time": time,
        "host": host,
        "cached": cached
    });

    // Spawn the logging to the database in the background, non-blocking
    let request_data_clone: Value = request_data.clone();
    actix_web::rt::spawn(async move {
        if let Ok(client) = supabase().await {
            let _ = client
                .insert("event_log_api", request_data_clone.clone())
                .await;
        }
    });

    // Instantly return to the caller
    request_data
}

pub fn log_event(
    directive: Option<String>,
    path: Option<String>,
    content: Option<String>,
    server: Option<String>,
    api_version: Option<String>,
    severity: Option<String>,
    message: Option<String>,
    json: Option<serde_json::Value>,
    user_id: Option<String>,
    company_id: Option<String>,
    status: Option<String>,
) {
    let time: f64 = chrono::Utc::now().timestamp() as f64;
    // Prepare the event log data as a serde_json::Value
    let event_data: Value = serde_json::json!({
        "directive": directive,
        "time": time,
        "path": path,
        "content": content,
        "server": server,
        "api_version": api_version,
        "severity": severity,
        "message": message,
        "json": json,
        "user_id": user_id,
        "company_id": company_id,
        "status": status,
    });

    // Spawn the logging to the database in the background, non-blocking
    let event_data_clone: Value = event_data.clone();
    actix_web::rt::spawn(async move {
        if let Ok(client) = supabase().await {
            let _ = client.insert("event_log", event_data_clone.clone()).await;
        }
    });
}

pub fn log_event_v2(
    directive: Option<String>,
    path: Option<String>,
    severity: Option<String>,
    message: Option<String>,
    json: Option<serde_json::Value>,
    user_id: Option<String>,
    company_id: Option<String>,
    status: Option<String>,
    ref_id: Option<String>,
) {
    let time: f64 = chrono::Utc::now().timestamp() as f64;
    let package_version: String = env!("CARGO_PKG_VERSION").to_string();
    let xbp_server: String = std::env::var("XBP_SERVER_HOST").unwrap_or_default();
    // Prepare the event log data as a serde_json::Value
    let event_data: Value = json!({
        "directive": directive,
        "time": time,
        "path": path,
        "server": xbp_server,
        "api_version": package_version,
        "severity": severity,
        "message": message,
        "json": json,
        "user_id": user_id,
        "company_id": company_id,
        "status": status,
        "ref_id": ref_id,
    });

    // Spawn the logging to the database in the background, non-blocking
    let event_data_clone: Value = event_data.clone();
    actix_web::rt::spawn(async move {
        if let Ok(client) = supabase().await {
            let _ = client.insert("event_log", event_data_clone.clone()).await;
        }
    });
}