use crate::app::AppState;
use crate::service::{self, CacheStatus, ProcessRequest};
use axum::extract::{Path, State};
use axum::http::{header, HeaderValue, StatusCode};
use axum::response::{IntoResponse, Json};
use axum_extra::headers::{authorization::Bearer, Authorization};
use axum_extra::TypedHeader;
use serde_json::json;
use std::sync::Arc;
use tracing::error;
pub async fn status_handler() -> impl IntoResponse {
(StatusCode::OK, Json(json!({"status": "ok"})))
}
pub async fn info_handler(
State(state): State<Arc<AppState>>,
Path(path): Path<String>,
auth_header: Option<TypedHeader<Authorization<Bearer>>>,
) -> impl IntoResponse {
let bearer = auth_header.map(|TypedHeader(auth)| auth.token().to_string());
match service::image_info(
state.clone(),
ProcessRequest {
path: &path,
bearer_token: bearer.as_deref(),
},
)
.await
{
Ok(info) => {
let response = json!({
"width": info.width,
"height": info.height,
"format": info.format,
"content_type": info.content_type,
"size_bytes": info.size_bytes,
"channels": info.channels,
"has_alpha": info.has_alpha,
"orientation": info.orientation,
});
(StatusCode::OK, Json(response)).into_response()
}
Err(err) => {
error!(path, error = ?err, "Info handler error");
(err.status(), err.message().into_owned()).into_response()
}
}
}
pub async fn image_forge_handler(
State(state): State<Arc<AppState>>,
Path(path): Path<String>,
auth_header: Option<TypedHeader<Authorization<Bearer>>>,
) -> impl IntoResponse {
let bearer = auth_header.map(|TypedHeader(auth)| auth.token().to_string());
match service::process_path(
state,
ProcessRequest {
path: &path,
bearer_token: bearer.as_deref(),
},
)
.await
{
Ok(result) => {
let mut headers = header::HeaderMap::new();
headers.insert(header::CONTENT_TYPE, HeaderValue::from_static(result.content_type));
if result.cache_status == CacheStatus::Hit {
headers.insert(
header::CACHE_STATUS,
HeaderValue::from_static(CacheStatus::Hit.as_header_value()),
);
}
if let Some(content_disposition) = result.content_disposition {
match HeaderValue::from_str(&content_disposition) {
Ok(value) => {
headers.insert(header::CONTENT_DISPOSITION, value);
}
Err(err) => {
error!("Invalid Content-Disposition header value: {}", err);
}
}
}
(StatusCode::OK, headers, result.bytes).into_response()
}
Err(err) => {
error!(path, error = ?err, "Image handler error");
(err.status(), err.message().into_owned()).into_response()
}
}
}