use std::path::PathBuf;
use axum::body::Bytes;
use axum::extract::{Path as AxumPath, Request, State};
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde_json::json;
use tracing::{debug, warn};
use super::map::{Call, map_request};
use super::{ANALYZE_SERVICE, AnalyzeRpcError, CALL_TIMEOUT, MAX_FRAME_BYTES, call, json_response};
use crate::server::AppState;
pub async fn analyze_api_handler(
State(state): State<AppState>,
AxumPath(path): AxumPath<String>,
req: Request,
) -> Response {
let (parts, body) = req.into_parts();
let query = parts.uri.query().map(str::to_owned);
let body_limit = usize::try_from(MAX_FRAME_BYTES).unwrap_or(usize::MAX);
let body_bytes: Bytes = match axum::body::to_bytes(body, body_limit).await {
Ok(b) => b,
Err(e) => {
warn!("analyze_uds: could not read the request body: {e}");
return (
StatusCode::PAYLOAD_TOO_LARGE,
format!("request body exceeds the {MAX_FRAME_BYTES}-byte frame budget"),
)
.into_response();
}
};
let mapped = match map_request(&parts.method, &path, query.as_deref(), &body_bytes) {
Ok(call) => call,
Err(reason) => {
warn!(
"analyze_uds: {} /{path} is not mapped: {reason}",
parts.method
);
return (
StatusCode::NOT_IMPLEMENTED,
axum::Json(json!({ "error": reason, "service": ANALYZE_SERVICE })),
)
.into_response();
}
};
let socket = match state.analyze_socket_path() {
Ok(p) => p,
Err(reason) => return AnalyzeRpcError::Unresolved(reason).into_response(),
};
let Call::Unary { method, params } = mapped;
debug!("analyze_uds: {} /{path} → {method}", parts.method);
match call(&socket, method, params, CALL_TIMEOUT).await {
Ok(result) => json_response(&result),
Err(e) => e.into_response(),
}
}
pub async fn deprecated_analyze_api_handler(
state: State<AppState>,
path: AxumPath<String>,
req: Request,
) -> Response {
tracing::trace!(
"analyze_uds: DEPRECATED /proxy/analyze/… — use /api/analyze/… instead (#1849)"
);
analyze_api_handler(state, path, req).await
}
impl AppState {
pub(crate) fn analyze_socket_path(&self) -> Result<PathBuf, String> {
match &self.analyze_socket {
Some(p) => Ok(p.as_ref().clone()),
None => super::socket_path(),
}
}
#[must_use]
pub fn with_analyze_socket(mut self, socket: PathBuf) -> Self {
self.analyze_socket = Some(std::sync::Arc::new(socket));
self
}
}