diff options
Diffstat (limited to 'filamento/src/error.rs')
| -rw-r--r-- | filamento/src/error.rs | 252 |
1 files changed, 233 insertions, 19 deletions
diff --git a/filamento/src/error.rs b/filamento/src/error.rs index f2bf6ef..be7af92 100644 --- a/filamento/src/error.rs +++ b/filamento/src/error.rs @@ -1,14 +1,23 @@ +// SPDX-FileCopyrightText: 2025 cel <cel@bunny.garden> +// +// SPDX-License-Identifier: AGPL-3.0-or-later + use std::{num::TryFromIntError, string::FromUtf8Error, sync::Arc}; use base64::DecodeError; use image::ImageError; use jid::JID; -use lampada::error::{ActorError, ConnectionError, ReadError, WriteError}; +use jid::JIDError; +use lampada::error::{ActorError, ReadError, WriteError}; use stanza::client::{Stanza, iq::Query}; use thiserror::Error; pub use lampada::error::CommandError; +pub use lampada::error::ConnectionError; +use tokio::sync::mpsc::error::SendError; +use tokio::sync::oneshot::error::RecvError; +use crate::db::DbCommand; use crate::files::FileStore; // for the client logic impl @@ -165,17 +174,104 @@ pub enum ResponseError { } #[derive(Debug, Error, Clone)] -#[error("database error: {0}")] -pub struct DatabaseError(pub Arc<sqlx::Error>); +pub enum DatabaseError { + #[error("database error: {0}")] + Database(Serializeable<Arc<rusqlite::Error>>), + #[error("database command send: {0}")] + Send(Arc<SendError<DbCommand>>), + #[error("database result recv: {0}")] + Recv(#[from] RecvError), +} + +impl From<SendError<DbCommand>> for DatabaseError { + fn from(e: SendError<DbCommand>) -> Self { + Self::Send(Arc::new(e)) + } +} + +pub enum Serializeable<T> { + String(String), + Unserialized(T), +} + +impl<T: std::fmt::Display> std::fmt::Display for Serializeable<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Serializeable::String(s) => s.fmt(f), + Serializeable::Unserialized(t) => t.fmt(f), + } + } +} + +impl<T: std::fmt::Debug> std::fmt::Debug for Serializeable<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Serializeable::String(s) => s.fmt(f), + Serializeable::Unserialized(t) => t.fmt(f), + } + } +} + +impl<T: Clone> Clone for Serializeable<T> { + fn clone(&self) -> Self { + match self { + Serializeable::String(s) => Self::String(s.clone()), + Serializeable::Unserialized(t) => Self::Unserialized(t.clone()), + } + } +} + +#[cfg(feature = "serde")] +struct StringVisitor; -impl From<sqlx::Error> for DatabaseError { - fn from(e: sqlx::Error) -> Self { - Self(Arc::new(e)) +#[cfg(feature = "serde")] +impl<'de> serde::de::Visitor<'de> for StringVisitor { + type Value = String; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string") + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(v) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for DatabaseError { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + let string = deserializer.deserialize_string(StringVisitor)?; + Ok(Self::Database(Serializeable::String(string))) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for DatabaseError { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + match &self.0 { + Serializeable::String(s) => serializer.serialize_str(s), + Serializeable::Unserialized(u) => serializer.serialize_str(&u.to_string()), + } } } -impl From<sqlx::Error> for DatabaseOpenError { - fn from(e: sqlx::Error) -> Self { +impl From<rusqlite::Error> for DatabaseError { + fn from(e: rusqlite::Error) -> Self { + Self::Database(Serializeable::Unserialized(Arc::new(e))) + } +} + +impl From<rusqlite::Error> for DatabaseOpenError { + fn from(e: rusqlite::Error) -> Self { Self::Error(Arc::new(e)) } } @@ -201,24 +297,140 @@ pub enum IqProcessError { #[derive(Debug, Error, Clone)] pub enum DatabaseOpenError { + #[cfg(target_arch = "wasm32")] + #[error("opfs: {0}")] + OpfsSAH(#[from] OpfsSAHError), #[error("error: {0}")] - Error(Arc<sqlx::Error>), - #[error("migration: {0}")] - Migration(Arc<sqlx::migrate::MigrateError>), + Error(Arc<rusqlite::Error>), + // #[error("migration: {0}")] + // Migration(Arc<rusqlite::migrate::MigrateError>), #[error("io: {0}")] - Io(Arc<tokio::io::Error>), + Io(Arc<std::io::Error>), #[error("invalid path")] InvalidPath, + #[error("tokio oneshot recv error: {0}")] + Recv(#[from] tokio::sync::oneshot::error::RecvError), } -impl From<sqlx::migrate::MigrateError> for DatabaseOpenError { - fn from(e: sqlx::migrate::MigrateError) -> Self { - Self::Migration(Arc::new(e)) +// impl From<sqlx::migrate::MigrateError> for DatabaseOpenError { +// fn from(e: sqlx::migrate::MigrateError) -> Self { +// Self::Migration(Arc::new(e)) +// } +// } + +#[cfg(target_arch = "wasm32")] +impl From<rusqlite::ffi::OpfsSAHError> for OpfsSAHError { + fn from(e: rusqlite::ffi::OpfsSAHError) -> Self { + use wasm_bindgen::UnwrapThrowExt; + match e { + rusqlite::ffi::OpfsSAHError::Vfs(_register_vfs_error) => Self::VfsRegistration, + rusqlite::ffi::OpfsSAHError::ImportDb(_import_db_error) => Self::ImportDb, + rusqlite::ffi::OpfsSAHError::NotSuported => Self::NotSupported, + rusqlite::ffi::OpfsSAHError::GetDirHandle(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::GetDirHandle(message) + } + rusqlite::ffi::OpfsSAHError::GetFileHandle(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::GetFileHandle(message) + } + rusqlite::ffi::OpfsSAHError::CreateSyncAccessHandle(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::CreateSyncAccessHandle(message) + } + rusqlite::ffi::OpfsSAHError::IterHandle(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::IterHandle(message) + } + rusqlite::ffi::OpfsSAHError::GetPath(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::GetPath(message) + } + rusqlite::ffi::OpfsSAHError::RemoveEntity(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::RemoveEntity(message) + } + rusqlite::ffi::OpfsSAHError::GetSize(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::GetSize(message) + } + rusqlite::ffi::OpfsSAHError::Read(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::Read(message) + } + rusqlite::ffi::OpfsSAHError::Write(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::Write(message) + } + rusqlite::ffi::OpfsSAHError::Flush(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::Flush(message) + } + rusqlite::ffi::OpfsSAHError::Truncate(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::Truncate(message) + } + rusqlite::ffi::OpfsSAHError::Reflect(js_value) => { + let error: js_sys::Error = js_value.into(); + let message = error.message().as_string().unwrap_throw(); + Self::Reflect(message) + } + rusqlite::ffi::OpfsSAHError::Generic(s) => Self::Generic(s), + rusqlite::ffi::OpfsSAHError::Custom(s) => Self::Generic(s), + } } } -impl From<tokio::io::Error> for DatabaseOpenError { - fn from(e: tokio::io::Error) -> Self { +#[cfg(target_arch = "wasm32")] +#[derive(Debug, Error, Clone)] +pub enum OpfsSAHError { + #[error("VFS registration")] + VfsRegistration, + #[error("import db error")] + ImportDb, + #[error("not supported")] + NotSupported, + #[error("get dir handle: {0}")] + GetDirHandle(String), + #[error("get file handle: {0}")] + GetFileHandle(String), + #[error("create sync access handle: {0}")] + CreateSyncAccessHandle(String), + #[error("iter handle: {0}")] + IterHandle(String), + #[error("get path: {0}")] + GetPath(String), + #[error("remove entity: {0}")] + RemoveEntity(String), + #[error("get size: {0}")] + GetSize(String), + #[error("read: {0}")] + Read(String), + #[error("write: {0}")] + Write(String), + #[error("flush: {0}")] + Flush(String), + #[error("truncate: {0}")] + Truncate(String), + #[error("reflect: {0}")] + Reflect(String), + #[error("generic: {0}")] + Generic(String), +} + +impl From<std::io::Error> for DatabaseOpenError { + fn from(e: std::io::Error) -> Self { Self::Io(Arc::new(e)) } } @@ -237,8 +449,10 @@ pub enum PresenceError { Unsupported, #[error("missing from")] MissingFrom, - #[error("stanza error: {0}")] - StanzaError(#[from] stanza::client::error::Error), + #[error("stanza error: {0:?}")] + StanzaError(Option<stanza::client::error::Error>), + #[error("received subscription request from a non-bare jid")] + InvalidSubscriptionRequest(#[from] JIDError), } #[derive(Debug, Error, Clone)] |
