added rust api to control DESI data distribution; updated to utilize bun for renovate
CI / Unit tests (pull_request) Failing after 8m55s

This commit is contained in:
2026-08-31 13:17:05 -06:00
parent 32ab1213fb
commit 5148d7e54f
19 changed files with 978 additions and 16 deletions
+12
View File
@@ -0,0 +1,12 @@
pub struct Config {
pub bind_addr: String,
}
impl Config {
pub fn from_env() -> anyhow::Result<Self> {
let bind_addr =
std::env::var("API_BIND_ADDR").unwrap_or_else(|_| "0.0.0.0:8080".to_string());
Ok(Self { bind_addr })
}
}
+3
View File
@@ -0,0 +1,3 @@
pub mod config;
pub mod models;
pub mod routes;
+30
View File
@@ -0,0 +1,30 @@
use desi_explorer_api::{config, routes};
use tracing_subscriber::EnvFilter;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("desi_explorer_api=info")),
)
.init();
let config = config::Config::from_env()?;
let app = routes::app();
let listener = tokio::net::TcpListener::bind(&config.bind_addr).await?;
tracing::info!("DESI Explorer API listening on {}", config.bind_addr);
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await?;
Ok(())
}
async fn shutdown_signal() {
let _ = tokio::signal::ctrl_c().await;
tracing::info!("shutting down");
}
+22
View File
@@ -0,0 +1,22 @@
use serde::Serialize;
/// Catalog metadata for a DESI data release/survey.
#[derive(Debug, Clone, Serialize)]
pub struct Catalog {
pub name: String,
pub release: String,
pub description: &'static str,
pub object_count: Option<u64>,
}
/// A single catalog object (galaxy / quasar / star) with its survey
/// coordinates. `ra` and `dec` are in degrees; `redshift` is dimensionless.
#[derive(Debug, Serialize)]
pub struct CatalogObject {
pub id: String,
pub catalog: String,
pub object_type: String,
pub ra: f64,
pub dec: f64,
pub redshift: f64,
}
+54
View File
@@ -0,0 +1,54 @@
use axum::{
extract::Query,
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
use serde::Deserialize;
use std::sync::LazyLock;
use crate::models::{Catalog, CatalogObject};
/// Placeholder catalogs until real DESI EDR/DR1 ingestion lands.
static CATALOGS: LazyLock<Vec<Catalog>> = LazyLock::new(|| {
vec![
Catalog {
name: "edr".to_string(),
release: "EDR".to_string(),
description: "DESI Early Data Release",
object_count: None,
},
Catalog {
name: "dr1".to_string(),
release: "DR1".to_string(),
description: "DESI Data Release 1",
object_count: None,
},
]
});
pub async fn list_catalogs() -> Json<Vec<Catalog>> {
Json(CATALOGS.clone())
}
#[derive(Debug, Deserialize)]
pub struct ObjectQuery {
catalog: Option<String>,
#[serde(default)]
limit: Option<usize>,
}
/// Placeholder object query. Real implementation will page through the
/// centralized DESI catalog store rather than return an empty result set.
pub async fn list_objects(Query(query): Query<ObjectQuery>) -> Response {
let limit = query.limit.unwrap_or(100).min(10_000);
tracing::debug!(
%limit,
catalog = query.catalog.as_deref().unwrap_or("all"),
"querying catalog objects (placeholder)"
);
let objects: Vec<CatalogObject> = Vec::new();
(StatusCode::OK, Json(objects)).into_response()
}
+11
View File
@@ -0,0 +1,11 @@
use axum::Json;
use serde::Serialize;
#[derive(Serialize)]
pub struct Health {
pub status: &'static str,
}
pub async fn health() -> Json<Health> {
Json(Health { status: "ok" })
}
+13
View File
@@ -0,0 +1,13 @@
pub mod catalogs;
pub mod health;
use axum::{routing::get, Router};
/// Builds the application router. Kept separate from `main` so tests can
/// construct it without binding a socket.
pub fn app() -> Router {
Router::new()
.route("/health", get(health::health))
.route("/api/v1/catalogs", get(catalogs::list_catalogs))
.route("/api/v1/objects", get(catalogs::list_objects))
}