diff --git a/Cargo.lock b/Cargo.lock index 939d5885..7e305113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1259,6 +1259,7 @@ dependencies = [ "rust-embed", "serde", "serde_json", + "thiserror", "tokio", "toml", "tower-http", diff --git a/Cargo.toml b/Cargo.toml index 26a819e2..da922d02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,4 @@ mime_guess = "2.0.4" rust-embed = { version = "8.0.0", features = ["axum-ex"] } prometheus = "0.13.3" lazy_static = "1.4.0" +thiserror = "1" \ No newline at end of file diff --git a/src/forward/forward_internal.rs b/src/forward/forward_internal.rs index 0399c740..7a118d6a 100644 --- a/src/forward/forward_internal.rs +++ b/src/forward/forward_internal.rs @@ -34,6 +34,7 @@ use webrtc::track::track_remote::TrackRemote; use crate::forward::track_match::{track_match_codec, track_sort}; use crate::media; +use crate::AppError; use super::rtcp::RtcpMessage; use super::track_match; @@ -156,7 +157,7 @@ impl PeerForwardInternal { pub(crate) async fn set_anchor(&self, peer: Arc) -> Result<()> { let mut anchor = self.anchor.write().await; if anchor.is_some() { - return Err(anyhow::anyhow!("anchor is set")); + return Err(AppError::ResourceAlreadyExists("A connection has already been established".to_string()).into()); } info!("[{}] [anchor] set {}", self.id, peer.get_stats_id()); *anchor = Some(peer); diff --git a/src/forward/mod.rs b/src/forward/mod.rs index ffd7f1dd..84ab1b78 100644 --- a/src/forward/mod.rs +++ b/src/forward/mod.rs @@ -14,6 +14,7 @@ use webrtc::sdp::{MediaDescription, SessionDescription}; use crate::forward::forward_internal::{get_peer_key, PeerForwardInternal}; use crate::{media, metrics}; +use crate::AppError; mod forward_internal; mod rtcp; @@ -38,11 +39,11 @@ impl PeerForward { offer: RTCSessionDescription, ) -> Result<(RTCSessionDescription, String)> { if self.internal.anchor_is_some().await { - return Err(anyhow::anyhow!("anchor is set")); + return Err(AppError::ResourceAlreadyExists("A connection has already been established".to_string()).into()); } let _ = self.anchor_lock.lock().await; if self.internal.anchor_is_some().await { - return Err(anyhow::anyhow!("anchor is set")); + return Err(AppError::ResourceAlreadyExists("A connection has already been established".to_string()).into()); } let peer = self .internal diff --git a/src/main.rs b/src/main.rs index 9ac52784..6415fda4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,8 @@ use log::info; use tower_http::services::{ServeDir, ServeFile}; use tower_http::validate_request::ValidateRequestHeaderLayer; use webrtc::peer_connection::sdp::session_description::RTCSessionDescription; +use thiserror::Error; +use http::header::ToStrError; use config::IceServer; use path::manager::Manager; @@ -152,7 +154,7 @@ async fn whip( header: HeaderMap, uri: Uri, body: String, -) -> Result, AppError> { +) -> AppResult> { let content_type = header .get("Content-Type") .ok_or(anyhow::anyhow!("Content-Type is required"))?; @@ -176,7 +178,7 @@ async fn whep( header: HeaderMap, uri: Uri, body: String, -) -> Result, AppError> { +) -> AppResult> { let content_type = header .get("Content-Type") .ok_or(anyhow::anyhow!("Content-Type is required"))?; @@ -199,7 +201,7 @@ async fn add_ice_candidate( Path(id): Path, header: HeaderMap, body: String, -) -> Result, AppError> { +) -> AppResult> { let content_type = header .get("Content-Type") .ok_or(AppError::from(anyhow::anyhow!("Content-Type is required")))?; @@ -221,7 +223,7 @@ async fn remove_path_key( State(state): State, Path(id): Path, header: HeaderMap, -) -> Result, AppError> { +) -> AppResult> { let key = header .get("If-Match") .ok_or(AppError::from(anyhow::anyhow!("If-Match is required")))? @@ -233,7 +235,7 @@ async fn remove_path_key( .body("".to_string())?) } -async fn ice_server_config(State(state): State) -> Result, AppError> { +async fn ice_server_config(State(state): State) -> AppResult> { let mut builder = Response::builder() .status(StatusCode::NO_CONTENT) .header("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PATCH") @@ -276,19 +278,45 @@ fn string_encoder(s: &impl ToString) -> String { s[1..s.len() - 1].to_string() } -struct AppError(anyhow::Error); +pub type AppResult = Result; +#[derive(Debug, Error)] +pub enum AppError { + #[error("resource not found:{0}")] + ResourceNotFound(String), + #[error("resource already exists:{0}")] + ResourceAlreadyExists(String), + #[error("internal server error")] + InternalServerError(anyhow::Error), +} impl IntoResponse for AppError { fn into_response(self) -> Response { - (StatusCode::INTERNAL_SERVER_ERROR, self.0.to_string()).into_response() + match self { + AppError::ResourceNotFound(err) => (StatusCode::NOT_FOUND, err.to_string()).into_response(), + AppError::InternalServerError(err) => (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response(), + AppError::ResourceAlreadyExists(err) => (StatusCode::CONFLICT, err.to_string()).into_response(), + } + } +} +impl From for AppError { + fn from(err: http::Error) -> Self { + AppError::InternalServerError(err.into()) + } +} +impl From for AppError { + fn from(err: ToStrError) -> Self { + AppError::InternalServerError(err.into()) + } +} + +impl From for AppError { + fn from(err: webrtc::Error) -> Self { + AppError::InternalServerError(err.into()) } } -impl From for AppError -where - E: Into, -{ - fn from(err: E) -> Self { - Self(err.into()) +impl From for AppError { + fn from(err: anyhow::Error) -> Self { + AppError::InternalServerError(err) } } diff --git a/src/path/manager.rs b/src/path/manager.rs index 243808cb..1512cd53 100644 --- a/src/path/manager.rs +++ b/src/path/manager.rs @@ -9,6 +9,7 @@ use webrtc::{ }; use crate::forward::PeerForward; +use crate::AppError; #[derive(Clone)] pub struct Manager { @@ -52,7 +53,7 @@ impl Manager { if let Some(forward) = forward { forward.add_subscribe(offer).await } else { - Err(anyhow::anyhow!("resource not exists")) + Err(AppError::ResourceNotFound(("The requested resource not exist,please check the path and try again.").to_string()).into()) } }