use std::sync::Arc;
use actix_web::{HttpRequest, HttpResponse, get, web};
use crate::backend::Backend;
pub mod v1;
pub type BackendData = web::Data<Arc<dyn Backend>>;
#[derive(Debug, Clone, Copy)]
pub struct QueryLimits {
pub max_page_size: u64,
}
impl Default for QueryLimits {
fn default() -> Self {
Self {
max_page_size: 100_000,
}
}
}
pub const ARROW_IPC_MIME: &str = "application/vnd.apache.arrow.stream";
#[get("/health")]
pub async fn health() -> HttpResponse {
HttpResponse::Ok()
.content_type("application/json")
.body(r#"{"status":"ok"}"#)
}
#[get("/healthz")]
pub async fn healthz() -> HttpResponse {
HttpResponse::Ok()
.content_type("application/json")
.body(r#"{"status":"ok"}"#)
}
#[get("/readyz")]
pub async fn readyz(backend: BackendData) -> HttpResponse {
let names = backend.names();
if names.is_empty() {
HttpResponse::ServiceUnavailable()
.content_type("application/json")
.body(r#"{"status":"not ready","reason":"no datasets registered"}"#)
} else {
let body = format!(r#"{{"status":"ready","datasets":{}}}"#, names.len());
HttpResponse::Ok()
.content_type("application/json")
.body(body)
}
}
#[derive(Clone, Debug, serde::Serialize)]
pub struct BuildInfo {
pub name: &'static str,
pub version: &'static str,
pub backend: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub git_sha: Option<&'static str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub build_time: Option<&'static str>,
pub profile: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<&'static str>,
}
impl BuildInfo {
pub fn new(backend: &'static str) -> Self {
Self {
name: env!("CARGO_PKG_NAME"),
version: env!("CARGO_PKG_VERSION"),
backend,
git_sha: option_env!("DATAPRESS_GIT_SHA"),
build_time: option_env!("DATAPRESS_BUILD_TIME"),
profile: if cfg!(debug_assertions) {
"debug"
} else {
"release"
},
target: option_env!("DATAPRESS_TARGET"),
}
}
}
#[get("/version")]
pub async fn version(info: web::Data<BuildInfo>) -> HttpResponse {
HttpResponse::Ok().json(info.get_ref())
}
pub(crate) fn wants_arrow(http: &HttpRequest) -> bool {
let qs = http.query_string();
if !qs.is_empty()
&& qs.split('&').any(|kv| matches!(kv.split_once('='), Some(("format", v)) if v.eq_ignore_ascii_case("arrow")))
{
return true;
}
http.headers()
.get(actix_web::http::header::ACCEPT)
.and_then(|h| h.to_str().ok())
.map(|s| {
s.split(',').any(|part| {
part.split(';')
.next()
.unwrap_or("")
.trim()
.eq_ignore_ascii_case(ARROW_IPC_MIME)
})
})
.unwrap_or(false)
}