1use crate::{
8	fsemul::errors::{FSEmulAPIError, FSEmulFSError, FSEmulNetworkError, FSEmulProtocolError},
9	mion::errors::{MionAPIError, MionProtocolError},
10};
11use bytes::Bytes;
12use miette::{Diagnostic, Report};
13use std::{ffi::FromBytesUntilNulError, str::Utf8Error, string::FromUtf8Error, time::Duration};
14use thiserror::Error;
15use tokio::{io::Error as IoError, task::JoinError};
16use walkdir::Error as WalkdirError;
17
18#[cfg(feature = "clients")]
19use crate::net::client::errors::CommonNetClientNetworkError;
20#[cfg(feature = "clients")]
21use local_ip_address::Error as LocalIpAddressError;
22#[cfg(feature = "clients")]
23use network_interface::Error as NetworkInterfaceError;
24#[cfg(feature = "clients")]
25use reqwest::Error as ReqwestError;
26
27#[cfg(any(feature = "clients", feature = "servers"))]
28use crate::net::errors::{CommonNetAPIError, CommonNetNetworkError};
29
30#[cfg(feature = "servers")]
31use crate::net::server::models::ResponseStreamMessage;
32#[cfg(feature = "servers")]
33use tokio::sync::mpsc::error::SendError;
34
35#[derive(Error, Diagnostic, Debug)]
38pub enum CatBridgeError {
39	#[error(transparent)]
41	#[diagnostic(transparent)]
42	API(#[from] APIError),
43	#[error(
54		"We could not send a message locally to another part of the process. This channel must've been closed unexpectedly."
55	)]
56	#[diagnostic(code(cat_dev::closed_channel))]
57	ClosedChannel,
58	#[error(transparent)]
60	#[diagnostic(transparent)]
61	FS(#[from] FSError),
62	#[error("We could not await an asynchronous task we spawned: {0:?}")]
68	#[diagnostic(code(cat_dev::join_failure))]
69	JoinFailure(#[from] JoinError),
70	#[error(transparent)]
72	#[diagnostic(transparent)]
73	Network(#[from] NetworkError),
74	#[error("We could not spawn a task (a lightweight thread) to do work on.")]
79	#[diagnostic(code(cat_dev::spawn_failure))]
80	SpawnFailure(IoError),
81	#[error("An unknown error we couldn't pin down occured: {0:?}")]
83	#[diagnostic(code(cat_dev::unknown))]
84	UnknownError(Report),
85	#[error(
86		"This cat-dev API requires a 32 bit usize, and this machine does not have it, please upgrade your machine."
87	)]
88	#[diagnostic(code(cat_dev::unsupported_bits_per_core))]
89	UnsupportedBitsPerCore,
90}
91
92#[non_exhaustive]
99#[derive(Error, Diagnostic, Debug)]
100pub enum APIError {
101	#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
103	#[cfg(any(feature = "clients", feature = "servers"))]
104	#[error(transparent)]
105	#[diagnostic(transparent)]
106	CommonNet(#[from] CommonNetAPIError),
107	#[error(transparent)]
108	#[diagnostic(transparent)]
109	FSEmul(#[from] FSEmulAPIError),
110	#[error(transparent)]
111	#[diagnostic(transparent)]
112	Mion(#[from] MionAPIError),
113	#[error(
118		"We could not find the local hosts ipv4 address which is needed if an ip isn't explicitly passed in."
119	)]
120	#[diagnostic(code(cat_dev::api::no_host_ip_found))]
121	NoHostIpFound,
122}
123
124#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
125#[cfg(any(feature = "clients", feature = "servers"))]
126impl From<CommonNetAPIError> for CatBridgeError {
127	fn from(value: CommonNetAPIError) -> Self {
128		Self::from(APIError::CommonNet(value))
129	}
130}
131
132#[derive(Error, Diagnostic, Debug)]
134pub enum FSError {
135	#[error(
142		"We can't find the path to store a complete list of host-bridges, please use explicit paths instead."
143	)]
144	#[diagnostic(code(cat_dev::fs::cant_find_hostenv_path))]
145	CantFindHostEnvPath,
146	#[error(transparent)]
147	#[diagnostic(transparent)]
148	FSEmul(#[from] FSEmulFSError),
149	#[error("Data read from the filesystem was expected to be a valid INI file: {0}")]
152	#[diagnostic(code(cat_dev::fs::expected_ini))]
153	InvalidDataNeedsToBeINI(String),
154	#[error("Expected file magic of: {0}, got {1} as magic bytes")]
156	#[diagnostic(code(cat_dev::fs::invalid_file_magic))]
157	InvalidFileMagic(u32, u32),
158	#[error("Expected file size of: {0} bytes, got a file sized {1} bytes")]
160	#[diagnostic(code(cat_dev::fs::invalid_file_size))]
161	InvalidFileSize(usize, usize),
162	#[error("Error writing/reading data from the filesystem: {0}")]
164	#[diagnostic(code(cat_dev::fs::io))]
165	IO(#[from] IoError),
166	#[error("Error iterating through folder: {0:?}")]
167	#[diagnostic(code(cat_dev::fs::iterating_folder_error))]
168	IteratingFolderError(#[from] WalkdirError),
169	#[error("Expect file to have at least: {0} line(s), but it was only: {1} line(s) long.")]
170	#[diagnostic(code(cat_dev::fs::too_few_lines))]
171	TooFewLines(usize, usize),
172	#[error("File cannot be larger than: {0} bytes, is {1} bytes")]
174	#[diagnostic(code(cat_dev::fs::too_large))]
175	TooLarge(usize, usize),
176	#[error("File needs to be at least: {0} bytes, is {1} bytes")]
178	#[diagnostic(code(cat_dev::fs::too_small))]
179	TooSmall(usize, usize),
180	#[error("Data read from the filesystem was expected to be UTF-8, but was not: {0}")]
182	#[diagnostic(code(cat_dev::fs::utf8_expected))]
183	Utf8Expected(#[from] FromUtf8Error),
184}
185
186#[derive(Error, Diagnostic, Debug)]
192#[non_exhaustive]
193pub enum NetworkError {
194	#[error("Failed to bind to a local address to receive packets.")]
206	#[diagnostic(code(cat_dev::net::bind_failure))]
207	BindFailure,
208	#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
209	#[cfg(feature = "clients")]
210	#[error(transparent)]
211	#[diagnostic(transparent)]
212	CommonClient(#[from] CommonNetClientNetworkError),
213	#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
215	#[cfg(any(feature = "clients", feature = "servers"))]
216	#[error(transparent)]
217	#[diagnostic(transparent)]
218	CommonNet(#[from] CommonNetNetworkError),
219	#[error("Expected some sort of data from other side, but got none.")]
220	#[diagnostic(code(cat_dev::net::expected_data))]
221	ExpectedData,
222	#[error(transparent)]
223	#[diagnostic(transparent)]
224	FSEmul(#[from] FSEmulNetworkError),
225	#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
226	#[cfg(feature = "clients")]
227	#[error("Underlying HTTP client error: {0}")]
229	#[diagnostic(code(cat_dev::net::http_failure))]
230	HTTP(#[from] ReqwestError),
231	#[error("Error talking to the network could not send/receive data: {0}")]
233	#[diagnostic(code(cat_dev::net::io_error))]
234	IO(#[from] IoError),
235	#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
236	#[cfg(feature = "clients")]
237	#[error("Failed to list the network interfaces on your device: {0:?}.")]
239	#[diagnostic(code(cat_dev::net::list_interfaces_error))]
240	ListInterfacesFailure(NetworkInterfaceError),
241	#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
242	#[cfg(feature = "clients")]
243	#[error("Failure fetching local ip address: {0}")]
245	#[diagnostic(code(cat_dev::net::local_ip_failure))]
246	LocalIp(#[from] LocalIpAddressError),
247	#[error(transparent)]
249	#[diagnostic(transparent)]
250	Parse(#[from] NetworkParseError),
251	#[error(
255		"Failed to set the socket we're bound on as a broadcast address, this is needed to discover CAT devices."
256	)]
257	#[diagnostic(code(cat_dev::net::set_broadcast_failure))]
258	SetBroadcastFailure,
259	#[cfg_attr(docsrs, doc(cfg(feature = "servers")))]
261	#[cfg(feature = "servers")]
262	#[error("Error queueing up packet to be sent out over a conenction: {0:?}")]
263	#[diagnostic(code(cat_dev::net::send_queue_failure))]
264	SendQueueMessageFailure(#[from] SendError<ResponseStreamMessage>),
265	#[error(
270		"Timed out while writing/reading data from the network, failed to send and receive data."
271	)]
272	#[diagnostic(code(cat_dev::net::timeout))]
273	Timeout(Duration),
274}
275
276#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
277#[cfg(feature = "clients")]
278impl From<CommonNetClientNetworkError> for CatBridgeError {
279	fn from(value: CommonNetClientNetworkError) -> Self {
280		Self::Network(value.into())
281	}
282}
283
284#[cfg_attr(docsrs, doc(cfg(any(feature = "clients", feature = "servers"))))]
285#[cfg(any(feature = "clients", feature = "servers"))]
286impl From<CommonNetNetworkError> for CatBridgeError {
287	fn from(value: CommonNetNetworkError) -> Self {
288		Self::Network(value.into())
289	}
290}
291
292#[cfg_attr(docsrs, doc(cfg(feature = "clients")))]
293#[cfg(feature = "clients")]
294impl From<ReqwestError> for CatBridgeError {
295	fn from(value: ReqwestError) -> Self {
296		Self::Network(value.into())
297	}
298}
299
300#[derive(Error, Diagnostic, Debug, PartialEq, Eq)]
303pub enum NetworkParseError {
304	#[error("Failed reading c style string from packet: {0:?}")]
306	#[diagnostic(code(cat_dev::net::parse::bad_c_string))]
307	BadCString(#[from] FromBytesUntilNulError),
308	#[error(
311		"Tried to read Packet of type ({0}) from network, must be encoded exactly as [{1:02x?}], but got [{2:02x?}]"
312	)]
313	#[diagnostic(code(cat_dev::net::parse::doesnt_match_static_data))]
314	DoesntMatchStaticPayload(&'static str, &'static [u8], Bytes),
315	#[error("Internal Protocol responded with an error code: {0}")]
316	#[diagnostic(code(cat_dev::net::parse::error_code))]
317	ErrorCode(u32),
318	#[error("Reading Field {1} from Packet {0}, was not encoded correctly must be encoded as {2}")]
321	#[diagnostic(code(cat_dev::net::parse::field_encoded_incorrectly))]
322	FieldEncodedIncorrectly(&'static str, &'static str, &'static str),
323	#[error(
326		"Tried Reading Field {1} from Packet {0}. This Field requires at least {2} bytes, but only had {3}, bytes: {4:02x?}"
327	)]
328	#[diagnostic(code(cat_dev::net::parse::field_not_long_enough))]
329	FieldNotLongEnough(&'static str, &'static str, usize, usize, Bytes),
330	#[error(transparent)]
331	#[diagnostic(transparent)]
332	FSEmul(#[from] FSEmulProtocolError),
333	#[error(transparent)]
335	#[diagnostic(transparent)]
336	Mion(#[from] MionProtocolError),
337	#[error(
340		"Tried to read Packet of type ({0}) from network needs at least {1} bytes, but only got {2} bytes: {3:02x?}"
341	)]
342	#[diagnostic(code(cat_dev::net::parse::not_enough_data))]
343	NotEnoughData(&'static str, usize, usize, Bytes),
344	#[error(
347		"Unexpected Trailer for Packet `{0}` received from the network (we're not sure what do with this extra data), extra bytes: {1:02x?}"
348	)]
349	#[diagnostic(code(cat_dev::net::parse::unexpected_trailer))]
350	UnexpectedTrailer(&'static str, Bytes),
351	#[error("Data read from the network was expected to be UTF-8, but was not: {0}")]
353	#[diagnostic(code(cat_dev::net::parse::utf8_expected))]
354	Utf8Expected(#[from] FromUtf8Error),
355	#[error("Data read from a network slice was expected to be UTF-8, but was not: {0}")]
357	#[diagnostic(code(cat_dev::net::parse::utf8_expected_slice))]
358	Utf8ExpectedSlice(#[from] Utf8Error),
359}
360impl From<NetworkParseError> for CatBridgeError {
361	fn from(value: NetworkParseError) -> Self {
362		Self::Network(value.into())
363	}
364}