aboutsummaryrefslogtreecommitdiffstats
path: root/filamento/src/error.rs
diff options
context:
space:
mode:
Diffstat (limited to 'filamento/src/error.rs')
-rw-r--r--filamento/src/error.rs252
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)]