use std::{error::Error, fmt}; use crate::VECTOR_ENGINE_PROVIDER; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum AudioStatusHint { BadRequest, ServiceUnavailable, BadGateway, GatewayTimeout, } #[derive(Clone, Debug)] pub enum AudioError { InvalidConfig { provider: &'static str, message: String, }, InvalidRequest { provider: &'static str, message: String, }, Request { provider: &'static str, message: String, endpoint: Option, timeout: bool, connect: bool, request: bool, body: bool, status_code: Option, source: Option, }, Upstream { provider: &'static str, message: String, upstream_status: u16, raw_excerpt: String, }, ResponseParse { provider: &'static str, message: String, raw_excerpt: String, }, MissingAudio { provider: &'static str, message: String, reason_code: Option<&'static str>, }, } impl AudioError { pub fn provider(&self) -> &'static str { match self { Self::InvalidConfig { provider, .. } | Self::InvalidRequest { provider, .. } | Self::Request { provider, .. } | Self::Upstream { provider, .. } | Self::ResponseParse { provider, .. } | Self::MissingAudio { provider, .. } => provider, } } pub fn message(&self) -> &str { match self { Self::InvalidConfig { message, .. } | Self::InvalidRequest { message, .. } | Self::Request { message, .. } | Self::Upstream { message, .. } | Self::ResponseParse { message, .. } | Self::MissingAudio { message, .. } => message, } } /// 可安全写入任务记录和指标的稳定失败分类;不会携带 provider 正文或凭据。 pub fn reason_code(&self) -> Option<&'static str> { match self { Self::MissingAudio { reason_code, .. } => *reason_code, _ => None, } } pub fn status_hint(&self) -> AudioStatusHint { match self { Self::InvalidConfig { .. } => AudioStatusHint::ServiceUnavailable, Self::InvalidRequest { .. } => AudioStatusHint::BadRequest, Self::Request { timeout, status_code, .. } if *timeout => AudioStatusHint::GatewayTimeout, Self::Request { status_code, .. } if status_code.is_some_and(|status| status >= 500) => { AudioStatusHint::BadGateway } Self::Upstream { .. } | Self::ResponseParse { .. } | Self::MissingAudio { .. } => { AudioStatusHint::BadGateway } Self::Request { .. } => AudioStatusHint::BadGateway, } } pub fn invalid_config(message: impl Into) -> Self { Self::invalid_config_for(VECTOR_ENGINE_PROVIDER, message) } pub fn invalid_config_for(provider: &'static str, message: impl Into) -> Self { Self::InvalidConfig { provider, message: message.into(), } } pub fn invalid_request(message: impl Into) -> Self { Self::invalid_request_for(VECTOR_ENGINE_PROVIDER, message) } pub fn invalid_request_for(provider: &'static str, message: impl Into) -> Self { Self::InvalidRequest { provider, message: message.into(), } } pub fn request( message: impl Into, endpoint: Option, timeout: bool, connect: bool, request: bool, body: bool, status_code: Option, source: Option, ) -> Self { Self::request_for( VECTOR_ENGINE_PROVIDER, message, endpoint, timeout, connect, request, body, status_code, source, ) } #[allow(clippy::too_many_arguments)] pub fn request_for( provider: &'static str, message: impl Into, endpoint: Option, timeout: bool, connect: bool, request: bool, body: bool, status_code: Option, source: Option, ) -> Self { Self::Request { provider, message: message.into(), endpoint, timeout, connect, request, body, status_code, source, } } pub fn upstream( message: impl Into, upstream_status: u16, raw_excerpt: impl Into, ) -> Self { Self::upstream_for( VECTOR_ENGINE_PROVIDER, message, upstream_status, raw_excerpt, ) } pub fn upstream_for( provider: &'static str, message: impl Into, upstream_status: u16, raw_excerpt: impl Into, ) -> Self { Self::Upstream { provider, message: message.into(), upstream_status, raw_excerpt: raw_excerpt.into(), } } pub fn response_parse(message: impl Into, raw_excerpt: impl Into) -> Self { Self::response_parse_for(VECTOR_ENGINE_PROVIDER, message, raw_excerpt) } pub fn response_parse_for( provider: &'static str, message: impl Into, raw_excerpt: impl Into, ) -> Self { Self::ResponseParse { provider, message: message.into(), raw_excerpt: raw_excerpt.into(), } } pub fn missing_audio(message: impl Into) -> Self { Self::missing_audio_for(VECTOR_ENGINE_PROVIDER, message) } pub fn missing_audio_for(provider: &'static str, message: impl Into) -> Self { Self::MissingAudio { provider, message: message.into(), reason_code: None, } } pub fn missing_audio_with_reason_for( provider: &'static str, reason_code: &'static str, message: impl Into, ) -> Self { Self::MissingAudio { provider, message: message.into(), reason_code: Some(reason_code), } } } impl fmt::Display for AudioError { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str(self.message()) } } impl Error for AudioError {}