1use std::sync::Arc;
2
3#[derive(Debug, Clone, thiserror::Error)]
9#[non_exhaustive]
10pub enum Error {
11 #[error(transparent)]
13 Io(Arc<std::io::Error>),
14
15 #[error(transparent)]
17 MoqNet(#[from] moq_net::Error),
18
19 #[error("invalid log directive")]
21 Directive(#[source] Arc<tracing_subscriber::filter::ParseError>),
22
23 #[error("failed to set global tracing subscriber")]
25 SetSubscriber(#[source] Arc<tracing_subscriber::util::TryInitError>),
26
27 #[error("failed to initialize Android logcat layer")]
29 Logcat(#[source] Arc<std::io::Error>),
30
31 #[error("{0}")]
33 NoBackend(&'static str),
34
35 #[error("failed to connect to server")]
37 ConnectFailed,
38
39 #[error(transparent)]
41 Connect(#[from] crate::ConnectError),
42
43 #[cfg(feature = "websocket")]
45 #[error("failed to connect to server: QUIC failed: {quic}; WebSocket failed: {websocket}")]
46 TransportRace {
47 quic: Arc<Error>,
49 websocket: Arc<Error>,
51 },
52
53 #[cfg(feature = "iroh")]
55 #[error("Iroh support is not enabled")]
56 IrohDisabled,
57
58 #[error("tls.root (mTLS) is not supported by the selected QUIC backend")]
60 MtlsUnsupported,
61
62 #[error("invalid status code")]
64 InvalidStatusCode,
65
66 #[error("{0}")]
68 Reconnect(String),
69
70 #[error(transparent)]
72 Tls(Arc<crate::tls::Error>),
73
74 #[cfg(feature = "quinn")]
76 #[error(transparent)]
77 Quinn(Arc<crate::quinn::Error>),
78
79 #[cfg(feature = "noq")]
81 #[error(transparent)]
82 Noq(Arc<crate::noq::Error>),
83
84 #[cfg(feature = "quiche")]
86 #[error(transparent)]
87 Quiche(Arc<crate::quiche::Error>),
88
89 #[cfg(feature = "iroh")]
91 #[error(transparent)]
92 Iroh(Arc<crate::iroh::Error>),
93
94 #[cfg(feature = "websocket")]
96 #[error(transparent)]
97 WebSocket(Arc<crate::websocket::Error>),
98
99 #[cfg(feature = "tcp")]
101 #[error(transparent)]
102 Tcp(Arc<crate::tcp::Error>),
103
104 #[cfg(all(feature = "uds", unix))]
106 #[error(transparent)]
107 Unix(Arc<crate::unix::Error>),
108}
109
110impl Error {
111 pub fn connect_error(&self) -> Option<crate::ConnectError> {
113 match self {
114 Self::Connect(err) => Some(*err),
115 Self::MoqNet(moq_net::Error::Unauthorized) => Some(crate::ConnectError::Unauthorized),
116 #[cfg(feature = "quinn")]
117 Self::Quinn(err) => err.connect_error(),
118 #[cfg(feature = "noq")]
119 Self::Noq(err) => err.connect_error(),
120 #[cfg(feature = "quiche")]
121 Self::Quiche(err) => err.connect_error(),
122 #[cfg(feature = "websocket")]
123 Self::TransportRace { quic, websocket } => quic.connect_error().or_else(|| websocket.connect_error()),
124 #[cfg(feature = "websocket")]
125 Self::WebSocket(err) => err.connect_error(),
126 _ => None,
127 }
128 }
129
130 pub fn is_auth(&self) -> bool {
132 self.connect_error().is_some_and(|err| err.is_auth())
133 }
134}
135
136impl From<std::io::Error> for Error {
139 fn from(err: std::io::Error) -> Self {
140 Self::Io(Arc::new(err))
141 }
142}
143
144impl From<tracing_subscriber::filter::ParseError> for Error {
145 fn from(err: tracing_subscriber::filter::ParseError) -> Self {
146 Self::Directive(Arc::new(err))
147 }
148}
149
150impl From<crate::tls::Error> for Error {
151 fn from(err: crate::tls::Error) -> Self {
152 Self::Tls(Arc::new(err))
153 }
154}
155
156#[cfg(feature = "quinn")]
157impl From<crate::quinn::Error> for Error {
158 fn from(err: crate::quinn::Error) -> Self {
159 if let Some(err) = err.connect_error() {
160 return Self::Connect(err);
161 }
162
163 Self::Quinn(Arc::new(err))
164 }
165}
166
167#[cfg(feature = "noq")]
168impl From<crate::noq::Error> for Error {
169 fn from(err: crate::noq::Error) -> Self {
170 if let Some(err) = err.connect_error() {
171 return Self::Connect(err);
172 }
173
174 Self::Noq(Arc::new(err))
175 }
176}
177
178#[cfg(feature = "quiche")]
179impl From<crate::quiche::Error> for Error {
180 fn from(err: crate::quiche::Error) -> Self {
181 if let Some(err) = err.connect_error() {
182 return Self::Connect(err);
183 }
184
185 Self::Quiche(Arc::new(err))
186 }
187}
188
189#[cfg(feature = "iroh")]
190impl From<crate::iroh::Error> for Error {
191 fn from(err: crate::iroh::Error) -> Self {
192 Self::Iroh(Arc::new(err))
193 }
194}
195
196#[cfg(feature = "websocket")]
197impl From<crate::websocket::Error> for Error {
198 fn from(err: crate::websocket::Error) -> Self {
199 if let Some(err) = err.connect_error() {
200 return Self::Connect(err);
201 }
202
203 Self::WebSocket(Arc::new(err))
204 }
205}
206
207#[cfg(feature = "tcp")]
208impl From<crate::tcp::Error> for Error {
209 fn from(err: crate::tcp::Error) -> Self {
210 Self::Tcp(Arc::new(err))
211 }
212}
213
214#[cfg(all(feature = "uds", unix))]
215impl From<crate::unix::Error> for Error {
216 fn from(err: crate::unix::Error) -> Self {
217 Self::Unix(Arc::new(err))
218 }
219}
220
221pub type Result<T> = std::result::Result<T, Error>;
223
224#[cfg(all(test, feature = "websocket"))]
225mod tests {
226 use super::*;
227
228 #[test]
229 fn transport_race_propagates_nested_connect_errors() {
230 let quic = Error::TransportRace {
231 quic: Arc::new(crate::ConnectError::Unauthorized.into()),
232 websocket: Arc::new(crate::ConnectError::Forbidden.into()),
233 };
234 assert_eq!(quic.connect_error(), Some(crate::ConnectError::Unauthorized));
235
236 let websocket = Error::TransportRace {
237 quic: Arc::new(Error::ConnectFailed),
238 websocket: Arc::new(crate::ConnectError::Forbidden.into()),
239 };
240 assert_eq!(websocket.connect_error(), Some(crate::ConnectError::Forbidden));
241 }
242}