at main 2.6 kB view raw
1//! Application state and error types. 2 3use std::sync::Arc; 4 5use axum::{ 6 http::StatusCode, 7 response::{IntoResponse, Response}, 8 Json, 9}; 10use tokio::sync::broadcast; 11use tracing::error; 12 13use crate::claude::ClaudeClient; 14use crate::db::LabelDb; 15use crate::labels::{Label, LabelError, LabelSigner}; 16 17/// Shared application state. 18#[derive(Clone)] 19pub struct AppState { 20 pub audd_api_token: String, 21 pub audd_api_url: String, 22 pub db: Option<Arc<LabelDb>>, 23 pub signer: Option<Arc<LabelSigner>>, 24 pub label_tx: Option<broadcast::Sender<(i64, Label)>>, 25 /// Claude client for image moderation (if configured) 26 pub claude: Option<Arc<ClaudeClient>>, 27 /// Minimum AuDD score to flag as potential copyright violation 28 pub copyright_score_threshold: i32, 29} 30 31/// Application error type. 32#[derive(Debug, thiserror::Error)] 33pub enum AppError { 34 #[error("audd error: {0}")] 35 Audd(String), 36 37 #[error("claude error: {0}")] 38 Claude(String), 39 40 #[error("image moderation not configured")] 41 ImageModerationNotConfigured, 42 43 #[error("labeler not configured")] 44 LabelerNotConfigured, 45 46 #[error("bad request: {0}")] 47 BadRequest(String), 48 49 #[error("not found: {0}")] 50 NotFound(String), 51 52 #[error("label error: {0}")] 53 Label(#[from] LabelError), 54 55 #[error("database error: {0}")] 56 Database(#[from] sqlx::Error), 57 58 #[error("io error: {0}")] 59 Io(#[from] std::io::Error), 60} 61 62impl IntoResponse for AppError { 63 fn into_response(self) -> Response { 64 error!(error = %self, "request failed"); 65 let (status, error_type) = match &self { 66 AppError::Audd(_) => (StatusCode::BAD_GATEWAY, "AuddError"), 67 AppError::Claude(_) => (StatusCode::BAD_GATEWAY, "ClaudeError"), 68 AppError::ImageModerationNotConfigured => { 69 (StatusCode::SERVICE_UNAVAILABLE, "ImageModerationNotConfigured") 70 } 71 AppError::LabelerNotConfigured => { 72 (StatusCode::SERVICE_UNAVAILABLE, "LabelerNotConfigured") 73 } 74 AppError::BadRequest(_) => (StatusCode::BAD_REQUEST, "BadRequest"), 75 AppError::NotFound(_) => (StatusCode::NOT_FOUND, "NotFound"), 76 AppError::Label(_) => (StatusCode::INTERNAL_SERVER_ERROR, "LabelError"), 77 AppError::Database(_) => (StatusCode::INTERNAL_SERVER_ERROR, "DatabaseError"), 78 AppError::Io(_) => (StatusCode::INTERNAL_SERVER_ERROR, "IoError"), 79 }; 80 let body = serde_json::json!({ 81 "error": error_type, 82 "message": self.to_string() 83 }); 84 (status, Json(body)).into_response() 85 } 86}