1use crate::{
8 fsemul::errors::{FSEmulAPIError, FSEmulFSError, FSEmulNetworkError, FSEmulProtocolError},
9 mion::errors::{MionAPIError, MionProtocolError},
10};
11use bytes::Bytes;
12use miette::{Diagnostic, Report};
13use std::{
14 ffi::FromBytesUntilNulError, num::ParseIntError, str::Utf8Error, string::FromUtf8Error,
15 time::Duration,
16};
17use thiserror::Error;
18use tokio::{io::Error as IoError, task::JoinError};
19use walkdir::Error as WalkdirError;
20
21#[cfg(feature = "clients")]
22use crate::net::client::errors::CommonNetClientNetworkError;
23#[cfg(feature = "clients")]
24use local_ip_address::Error as LocalIpAddressError;
25#[cfg(feature = "clients")]
26use network_interface::Error as NetworkInterfaceError;
27
28#[cfg(any(feature = "clients", feature = "nus"))]
29use reqwest::{Error as ReqwestError, StatusCode};
30
31#[cfg(feature = "nus")]
32use sachet::{errors::SachetError, title::TitleID};
33
34#[cfg(any(feature = "clients", feature = "servers"))]
35use crate::net::errors::{CommonNetAPIError, CommonNetNetworkError};
36
37#[cfg(feature = "servers")]
38use crate::net::server::models::ResponseStreamMessage;
39#[cfg(feature = "servers")]
40use tokio::sync::mpsc::error::SendError;
41
42#[derive(Error, Diagnostic, Debug)]
45pub enum CatBridgeError {
46 #[error(transparent)]
48 #[diagnostic(transparent)]
49 API(#[from] APIError),
50 #[error(
61 "We could not send a message locally to another part of the process. This channel must've been closed unexpectedly."
62 )]
63 #[diagnostic(code(cat_dev::closed_channel))]
64 ClosedChannel,
65 #[error(transparent)]
67 #[diagnostic(transparent)]
68 FS(#[from] FSError),
69 #[error("We could not await an asynchronous task we spawned: {0:?}")]
75 #[diagnostic(code(cat_dev::join_failure))]
76 JoinFailure(#[from] JoinError),
77 #[error(transparent)]
79 #[diagnostic(transparent)]
80 Network(#[from] NetworkError),
81 #[error("We could not spawn a task (a lightweight thread) to do work on.")]
86 #[diagnostic(code(cat_dev::spawn_failure))]
87 SpawnFailure(IoError),
88 #[error("An unknown error we couldn't pin down occured: {0:?}")]
90 #[diagnostic(code(cat_dev::unknown))]
91 UnknownError(Report),
92 #[error(
93 "This cat-dev API requires a 32 bit usize, and this machine does not have it, please upgrade your machine."
94 )]
95 #[diagnostic(code(cat_dev::unsupported_bits_per_core))]
96 UnsupportedBitsPerCore,
97}
98
99#[non_exhaustive]
106#[derive(Error, Diagnostic, Debug)]
107pub enum APIError {
108 #[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
110 #[cfg(any(feature = "clients", feature = "servers"))]
111 #[error(transparent)]
112 #[diagnostic(transparent)]
113 CommonNet(#[from] CommonNetAPIError),
114 #[error(transparent)]
115 #[diagnostic(transparent)]
116 FSEmul(#[from] FSEmulAPIError),
117 #[error(transparent)]
118 #[diagnostic(transparent)]
119 Mion(#[from] MionAPIError),
120 #[error("Could not parse a number that you handed in as a string: {0:?}")]
122 #[diagnostic(code(cat_dev::api::cannot_parse_number))]
123 CannotParseNumber(#[from] ParseIntError),
124 #[error(
129 "We could not find the local hosts ipv4 address which is needed if an ip isn't explicitly passed in."
130 )]
131 #[diagnostic(code(cat_dev::api::no_host_ip_found))]
132 NoHostIpFound,
133}
134
135#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
136#[cfg(any(feature = "clients", feature = "servers"))]
137impl From<CommonNetAPIError> for CatBridgeError {
138 fn from(value: CommonNetAPIError) -> Self {
139 Self::from(APIError::CommonNet(value))
140 }
141}
142
143#[derive(Error, Diagnostic, Debug)]
145pub enum FSError {
146 #[error(
153 "We can't find the path to store a complete list of host-bridges, please use explicit paths instead."
154 )]
155 #[diagnostic(code(cat_dev::fs::cant_find_hostenv_path))]
156 CantFindHostEnvPath,
157 #[error(transparent)]
158 #[diagnostic(transparent)]
159 FSEmul(#[from] FSEmulFSError),
160 #[error("Data read from the filesystem was expected to be a valid INI file: {0}")]
163 #[diagnostic(code(cat_dev::fs::expected_ini))]
164 InvalidDataNeedsToBeINI(String),
165 #[error("Expected file magic of: {0}, got {1} as magic bytes")]
167 #[diagnostic(code(cat_dev::fs::invalid_file_magic))]
168 InvalidFileMagic(u32, u32),
169 #[error("Expected file size of: {0} bytes, got a file sized {1} bytes")]
171 #[diagnostic(code(cat_dev::fs::invalid_file_size))]
172 InvalidFileSize(usize, usize),
173 #[error("Error writing/reading data from the filesystem: {0}")]
175 #[diagnostic(code(cat_dev::fs::io))]
176 IO(#[from] IoError),
177 #[error("Error iterating through folder: {0:?}")]
178 #[diagnostic(code(cat_dev::fs::iterating_folder_error))]
179 IteratingFolderError(#[from] WalkdirError),
180 #[error("Expect file to have at least: {0} line(s), but it was only: {1} line(s) long.")]
181 #[diagnostic(code(cat_dev::fs::too_few_lines))]
182 TooFewLines(usize, usize),
183 #[error("File cannot be larger than: {0} bytes, is {1} bytes")]
185 #[diagnostic(code(cat_dev::fs::too_large))]
186 TooLarge(usize, usize),
187 #[error("File needs to be at least: {0} bytes, is {1} bytes")]
189 #[diagnostic(code(cat_dev::fs::too_small))]
190 TooSmall(usize, usize),
191 #[error("Data read from the filesystem was expected to be UTF-8, but was not: {0}")]
193 #[diagnostic(code(cat_dev::fs::utf8_expected))]
194 Utf8Expected(#[from] FromUtf8Error),
195}
196
197#[derive(Error, Diagnostic, Debug)]
203#[non_exhaustive]
204pub enum NetworkError {
205 #[error("Failed to bind to a local address to receive packets.")]
217 #[diagnostic(code(cat_dev::net::bind_failure))]
218 BindFailure,
219 #[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
220 #[cfg(feature = "clients")]
221 #[error(transparent)]
222 #[diagnostic(transparent)]
223 CommonClient(#[from] CommonNetClientNetworkError),
224 #[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
226 #[cfg(any(feature = "clients", feature = "servers"))]
227 #[error(transparent)]
228 #[diagnostic(transparent)]
229 CommonNet(#[from] CommonNetNetworkError),
230 #[error("Expected some sort of data from other side, but got none.")]
231 #[diagnostic(code(cat_dev::net::expected_data))]
232 ExpectedData,
233 #[error(transparent)]
234 #[diagnostic(transparent)]
235 FSEmul(#[from] FSEmulNetworkError),
236 #[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "nus"))))]
237 #[cfg(any(feature = "clients", feature = "nus"))]
238 #[error("Underlying HTTP client error: {0}")]
240 #[diagnostic(code(cat_dev::net::http_failure))]
241 HTTP(#[from] ReqwestError),
242 #[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "nus"))))]
243 #[cfg(any(feature = "clients", feature = "nus"))]
244 #[error("Bad status code from HTTP Server: {0}, Body: {1:?}")]
246 #[diagnostic(code(cat_dev::net::http_status_failure))]
247 HTTPStatusCode(StatusCode, Option<Bytes>),
248 #[error("Error talking to the network could not send/receive data: {0}")]
250 #[diagnostic(code(cat_dev::net::io_error))]
251 IO(#[from] IoError),
252 #[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
253 #[cfg(feature = "clients")]
254 #[error("Failed to list the network interfaces on your device: {0:?}.")]
256 #[diagnostic(code(cat_dev::net::list_interfaces_error))]
257 ListInterfacesFailure(NetworkInterfaceError),
258 #[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
259 #[cfg(feature = "clients")]
260 #[error("Failure fetching local ip address: {0}")]
262 #[diagnostic(code(cat_dev::net::local_ip_failure))]
263 LocalIp(#[from] LocalIpAddressError),
264 #[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
265 #[cfg(feature = "nus")]
266 #[error(transparent)]
267 #[diagnostic(code(cat_dev::nus))]
268 NUS(#[from] SachetError),
269 #[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
270 #[cfg(feature = "nus")]
271 #[error("Title ID: {0:?} did not have FST table inside of it!")]
272 #[diagnostic(code(cat_dev::nus::missing_fst))]
273 NUSMissingFST(TitleID),
274 #[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
275 #[cfg(feature = "nus")]
276 #[error("Title ID: {0:?} did not have a content id at: {1:04x}!")]
277 #[diagnostic(code(cat_dev::nus::missing_title_key))]
278 NUSInvalidContentID(TitleID, u16),
279 #[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
280 #[cfg(feature = "nus")]
281 #[error("Title ID: {0:?} did not have any valid title keys!")]
282 #[diagnostic(code(cat_dev::nus::missing_title_key))]
283 NUSNoTitleKey(TitleID),
284 #[error(transparent)]
286 #[diagnostic(transparent)]
287 Parse(#[from] NetworkParseError),
288 #[error(
292 "Failed to set the socket we're bound on as a broadcast address, this is needed to discover CAT devices."
293 )]
294 #[diagnostic(code(cat_dev::net::set_broadcast_failure))]
295 SetBroadcastFailure,
296 #[cfg_attr(docsrs, doc(cfg(feature = "servers")))]
298 #[cfg(feature = "servers")]
299 #[error("Error queueing up packet to be sent out over a conenction: {0:?}")]
300 #[diagnostic(code(cat_dev::net::send_queue_failure))]
301 SendQueueMessageFailure(#[from] SendError<ResponseStreamMessage>),
302 #[error(
307 "Timed out while writing/reading data from the network, failed to send and receive data."
308 )]
309 #[diagnostic(code(cat_dev::net::timeout))]
310 Timeout(Duration),
311}
312
313#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
314#[cfg(feature = "clients")]
315impl From<CommonNetClientNetworkError> for CatBridgeError {
316 fn from(value: CommonNetClientNetworkError) -> Self {
317 Self::Network(value.into())
318 }
319}
320
321#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
322#[cfg(any(feature = "clients", feature = "servers"))]
323impl From<CommonNetNetworkError> for CatBridgeError {
324 fn from(value: CommonNetNetworkError) -> Self {
325 Self::Network(value.into())
326 }
327}
328
329#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "nus"))))]
330#[cfg(any(feature = "clients", feature = "nus"))]
331impl From<ReqwestError> for CatBridgeError {
332 fn from(value: ReqwestError) -> Self {
333 Self::Network(value.into())
334 }
335}
336
337#[derive(Error, Diagnostic, Debug, PartialEq, Eq)]
340pub enum NetworkParseError {
341 #[error("Failed reading c style string from packet: {0:?}")]
343 #[diagnostic(code(cat_dev::net::parse::bad_c_string))]
344 BadCString(#[from] FromBytesUntilNulError),
345 #[error(
348 "Tried to read Packet of type ({0}) from network, must be encoded exactly as [{1:02x?}], but got [{2:02x?}]"
349 )]
350 #[diagnostic(code(cat_dev::net::parse::doesnt_match_static_data))]
351 DoesntMatchStaticPayload(&'static str, &'static [u8], Bytes),
352 #[error("Internal Protocol responded with an error code: {0}")]
353 #[diagnostic(code(cat_dev::net::parse::error_code))]
354 ErrorCode(u32),
355 #[error("Reading Field {1} from Packet {0}, was not encoded correctly must be encoded as {2}")]
358 #[diagnostic(code(cat_dev::net::parse::field_encoded_incorrectly))]
359 FieldEncodedIncorrectly(&'static str, &'static str, &'static str),
360 #[error(
363 "Tried Reading Field {1} from Packet {0}. This Field requires at least {2} bytes, but only had {3}, bytes: {4:02x?}"
364 )]
365 #[diagnostic(code(cat_dev::net::parse::field_not_long_enough))]
366 FieldNotLongEnough(&'static str, &'static str, usize, usize, Bytes),
367 #[error(transparent)]
368 #[diagnostic(transparent)]
369 FSEmul(#[from] FSEmulProtocolError),
370 #[error(transparent)]
372 #[diagnostic(transparent)]
373 Mion(#[from] MionProtocolError),
374 #[error(
377 "Tried to read Packet of type ({0}) from network needs at least {1} bytes, but only got {2} bytes: {3:02x?}"
378 )]
379 #[diagnostic(code(cat_dev::net::parse::not_enough_data))]
380 NotEnoughData(&'static str, usize, usize, Bytes),
381 #[error(
384 "Unexpected Trailer for Packet `{0}` received from the network (we're not sure what do with this extra data), extra bytes: {1:02x?}"
385 )]
386 #[diagnostic(code(cat_dev::net::parse::unexpected_trailer))]
387 UnexpectedTrailer(&'static str, Bytes),
388 #[error("Data read from the network was expected to be UTF-8, but was not: {0}")]
390 #[diagnostic(code(cat_dev::net::parse::utf8_expected))]
391 Utf8Expected(#[from] FromUtf8Error),
392 #[error("Data read from a network slice was expected to be UTF-8, but was not: {0}")]
394 #[diagnostic(code(cat_dev::net::parse::utf8_expected_slice))]
395 Utf8ExpectedSlice(#[from] Utf8Error),
396}
397impl From<NetworkParseError> for CatBridgeError {
398 fn from(value: NetworkParseError) -> Self {
399 Self::Network(value.into())
400 }
401}