audio streaming app
plyr.fm
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::db::LabelDb;
14use crate::labels::{Label, LabelError, LabelSigner};
15
16/// Shared application state.
17#[derive(Clone)]
18pub struct AppState {
19 pub audd_api_token: String,
20 pub audd_api_url: String,
21 pub db: Option<Arc<LabelDb>>,
22 pub signer: Option<Arc<LabelSigner>>,
23 pub label_tx: Option<broadcast::Sender<(i64, Label)>>,
24}
25
26/// Application error type.
27#[derive(Debug, thiserror::Error)]
28pub enum AppError {
29 #[error("audd error: {0}")]
30 Audd(String),
31
32 #[error("labeler not configured")]
33 LabelerNotConfigured,
34
35 #[error("label error: {0}")]
36 Label(#[from] LabelError),
37
38 #[error("database error: {0}")]
39 Database(#[from] sqlx::Error),
40
41 #[error("io error: {0}")]
42 Io(#[from] std::io::Error),
43}
44
45impl IntoResponse for AppError {
46 fn into_response(self) -> Response {
47 error!(error = %self, "request failed");
48 let (status, error_type) = match &self {
49 AppError::Audd(_) => (StatusCode::BAD_GATEWAY, "AuddError"),
50 AppError::LabelerNotConfigured => {
51 (StatusCode::SERVICE_UNAVAILABLE, "LabelerNotConfigured")
52 }
53 AppError::Label(_) => (StatusCode::INTERNAL_SERVER_ERROR, "LabelError"),
54 AppError::Database(_) => (StatusCode::INTERNAL_SERVER_ERROR, "DatabaseError"),
55 AppError::Io(_) => (StatusCode::INTERNAL_SERVER_ERROR, "IoError"),
56 };
57 let body = serde_json::json!({
58 "error": error_type,
59 "message": self.to_string()
60 });
61 (status, Json(body)).into_response()
62 }
63}