use wasm_bindgen::JsValue;
#[derive(Debug, thiserror::Error)]
pub enum LibfwError {
#[error("http {status} for `{url}`")]
Http { status: u16, url: String },
#[error("network error: {0}")]
Network(String),
#[error("decompression error: {0}")]
Decompress(String),
#[error("compression error: {0}")]
Compress(String),
#[error("protocol error: {0}")]
Protocol(String),
#[error("js error: {0}")]
Js(String),
#[error("transfer cancelled")]
Cancelled,
#[error("storage error: {0}")]
Storage(String),
}
impl LibfwError {
pub fn to_js(&self) -> JsValue {
let msg = self.to_string();
let err = js_sys::Error::new(&msg);
let _ = js_sys::Reflect::set(
&err,
&JsValue::from_str("isLibfwError"),
&JsValue::TRUE,
);
err.into()
}
}
impl From<JsValue> for LibfwError {
fn from(value: JsValue) -> Self {
LibfwError::Js(
value
.as_string()
.unwrap_or_else(|| format!("{value:?}")),
)
}
}
impl From<libfw_core::error::DecompressError> for LibfwError {
fn from(e: libfw_core::error::DecompressError) -> Self {
LibfwError::Decompress(e.to_string())
}
}
impl From<libfw_core::error::CompressError> for LibfwError {
fn from(e: libfw_core::error::CompressError) -> Self {
LibfwError::Compress(e.to_string())
}
}
pub fn js_value_string(v: &JsValue) -> String {
v.as_string().unwrap_or_else(|| format!("{v:?}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn error_messages_are_stable() {
assert_eq!(
LibfwError::Http {
status: 404,
url: "/f".into()
}
.to_string(),
"http 404 for `/f`"
);
assert_eq!(LibfwError::Cancelled.to_string(), "transfer cancelled");
}
#[test]
#[cfg(target_arch = "wasm32")]
fn js_errors_carry_tag() {
let js = LibfwError::Cancelled.to_js();
let err = js_sys::Error::from(js);
let tag = js_sys::Reflect::get(&err, &JsValue::from_str("isLibfwError"))
.ok()
.and_then(|v| v.as_bool())
.unwrap_or(false);
assert!(tag);
}
}