aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--filamento/Cargo.toml1
-rw-r--r--filamento/src/db.rs13
-rw-r--r--filamento/src/error.rs114
-rw-r--r--filamento/src/files/opfs.rs2
-rw-r--r--filamento/src/logic/connect.rs2
-rw-r--r--filamento/src/logic/mod.rs2
-rw-r--r--filamento/src/logic/online.rs49
7 files changed, 155 insertions, 28 deletions
diff --git a/filamento/Cargo.toml b/filamento/Cargo.toml
index 7d7af0c..b89c577 100644
--- a/filamento/Cargo.toml
+++ b/filamento/Cargo.toml
@@ -52,6 +52,7 @@ tokio = { workspace = true, features = ["sync", "time", "rt", "fs", "io-std"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
tokio = { workspace = true, features = ["sync", "time", "rt"] }
+js-sys.workspace = true
web-sys = { workspace = true, features = [
"FileSystemDirectoryHandle",
"FileSystemWritableFileStream",
diff --git a/filamento/src/db.rs b/filamento/src/db.rs
index 385382a..298d54a 100644
--- a/filamento/src/db.rs
+++ b/filamento/src/db.rs
@@ -88,12 +88,21 @@ impl Db {
spawn_blocking(move || {
spawn_local(async move {
debug!("installing opfs in spawn");
- rusqlite::ffi::install_opfs_sahpool(
+ match rusqlite::ffi::install_opfs_sahpool(
Some(&rusqlite::ffi::OpfsSAHPoolCfg::default()),
false,
)
.await
- .unwrap();
+ {
+ Ok(_) => {}
+ Err(e) => {
+ use crate::error::OpfsSAHError;
+
+ let error: OpfsSAHError = e.into();
+ result_send.send(Err(error.into()));
+ return;
+ }
+ }
debug!("opfs installed");
let file_name = format!("file:{}?vfs=opfs-sahpool", file_name.as_ref());
let result = DbActor::new(file_name, receiver);
diff --git a/filamento/src/error.rs b/filamento/src/error.rs
index 721d532..fb7d778 100644
--- a/filamento/src/error.rs
+++ b/filamento/src/error.rs
@@ -293,6 +293,9 @@ 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<rusqlite::Error>),
// #[error("migration: {0}")]
@@ -311,6 +314,117 @@ pub enum DatabaseOpenError {
// }
// }
+#[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),
+ }
+ }
+}
+
+#[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))
diff --git a/filamento/src/files/opfs.rs b/filamento/src/files/opfs.rs
index fb32c6e..0bcce35 100644
--- a/filamento/src/files/opfs.rs
+++ b/filamento/src/files/opfs.rs
@@ -10,7 +10,7 @@ use web_sys::{
use crate::FileStore;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct FilesOPFS {
directory: String,
}
diff --git a/filamento/src/logic/connect.rs b/filamento/src/logic/connect.rs
index 9d61ca4..6e392f1 100644
--- a/filamento/src/logic/connect.rs
+++ b/filamento/src/logic/connect.rs
@@ -11,7 +11,7 @@ use crate::{
use super::ClientLogic;
-pub async fn handle_connect<Fs: FileStore + Clone + Send + Sync>(
+pub async fn handle_connect<Fs: FileStore + Clone + Send + Sync + 'static>(
logic: ClientLogic<Fs>,
connection: Connected,
) {
diff --git a/filamento/src/logic/mod.rs b/filamento/src/logic/mod.rs
index 146f3b0..ddf0343 100644
--- a/filamento/src/logic/mod.rs
+++ b/filamento/src/logic/mod.rs
@@ -127,7 +127,7 @@ impl<Fs: FileStore> ClientLogic<Fs> {
}
}
-impl<Fs: FileStore + Clone + Send + Sync> Logic for ClientLogic<Fs> {
+impl<Fs: FileStore + Clone + Send + Sync + 'static> Logic for ClientLogic<Fs> {
type Cmd = Command<Fs>;
// pub async fn handle_stream_error(self, error) {}
diff --git a/filamento/src/logic/online.rs b/filamento/src/logic/online.rs
index febd3e1..b36f9a9 100644
--- a/filamento/src/logic/online.rs
+++ b/filamento/src/logic/online.rs
@@ -11,7 +11,9 @@ use stanza::{
iq::{self, Iq, IqType, Query}, Stanza
}, xep_0030::{info, items}, xep_0060::{self, owner, pubsub::{self, Pubsub}}, xep_0084, xep_0172::{self, Nick}, xep_0203::Delay
};
-use tokio::sync::oneshot;
+use tokio::{sync::oneshot, task::spawn_blocking};
+#[cfg(target_arch = "wasm32")]
+use tokio_with_wasm::alias as tokio;
use tracing::{debug, error, info};
use uuid::Uuid;
@@ -27,7 +29,7 @@ use super::{
}, ClientLogic
};
-pub async fn handle_online<Fs: FileStore + Clone>(logic: ClientLogic<Fs>, command: Command<Fs>, connection: Connected) {
+pub async fn handle_online<Fs: FileStore + Clone + 'static>(logic: ClientLogic<Fs>, command: Command<Fs>, connection: Connected) {
let result = handle_online_result(&logic, command, connection).await;
match result {
Ok(_) => {}
@@ -288,12 +290,9 @@ pub async fn handle_accept_subscription_request<Fs: FileStore + Clone>(
connection: Connected,
jid: BareJID,
) -> Result<(), SubscribeError> {
- let client_user = logic.db.read_user(logic.jid.clone()).await?;
- let nick = client_user.nick.map(|nick| Nick(nick));
let presence = Stanza::Presence(stanza::client::presence::Presence {
to: Some(jid.into()),
- r#type: Some(stanza::client::presence::PresenceType::Subscribe),
- nick,
+ r#type: Some(stanza::client::presence::PresenceType::Subscribed),
..Default::default()
});
connection.write_handle().write(presence).await?;
@@ -973,29 +972,33 @@ pub async fn handle_change_nick<Fs: FileStore + Clone>(logic: &ClientLogic<Fs>,
Ok(())
}
-pub async fn handle_change_avatar<Fs: FileStore + Clone>(logic: &ClientLogic<Fs>, img_data: Option<Vec<u8>>) -> Result<(), AvatarPublishError<Fs>> {
+pub async fn handle_change_avatar<Fs: FileStore + Clone + 'static>(logic: &ClientLogic<Fs>, img_data: Option<Vec<u8>>) -> Result<(), AvatarPublishError<Fs>> {
match img_data {
// set avatar
Some(data) => {
- // load the image data and guess the format
- let image = ImageReader::new(Cursor::new(data)).with_guessed_format()?.decode()?;
+ let (bytes, hash, data_png, data_b64) = spawn_blocking(move || -> Result<_, _> {
+ // load the image data and guess the format
+ let image = ImageReader::new(Cursor::new(data)).with_guessed_format()?.decode()?;
+
+ // convert the image to png;
+ let mut data_png = Vec::new();
+ let image = image.resize(192, 192, image::imageops::FilterType::Nearest);
+ image.write_to(&mut Cursor::new(&mut data_png), image::ImageFormat::Jpeg)?;
- // convert the image to png;
- let mut data_png = Vec::new();
- let image = image.resize(192, 192, image::imageops::FilterType::Nearest);
- image.write_to(&mut Cursor::new(&mut data_png), image::ImageFormat::Jpeg)?;
+ // calculate the length of the data in bytes.
+ let bytes = data_png.len().try_into()?;
- // calculate the length of the data in bytes.
- let bytes = data_png.len().try_into()?;
+ // calculate sha1 hash of the data
+ let mut sha1 = Sha1::new();
+ sha1.update(&data_png);
+ let sha1_result = sha1.finalize();
+ let hash = hex::encode(sha1_result);
- // calculate sha1 hash of the data
- let mut sha1 = Sha1::new();
- sha1.update(&data_png);
- let sha1_result = sha1.finalize();
- let hash = hex::encode(sha1_result);
+ // encode the image data as base64
+ let data_b64 = BASE64_STANDARD.encode(data_png.clone());
- // encode the image data as base64
- let data_b64 = BASE64_STANDARD.encode(data_png.clone());
+ Ok::<(u32, String, Vec<u8>, String), AvatarPublishError<Fs>>((bytes, hash, data_png, data_b64))
+ }).await.unwrap()?;
// publish the data to the data node
logic.client().publish(pep::Item::AvatarData(Some(avatar::Data { hash: hash.clone(), data_b64 })), "urn:xmpp:avatar:data".to_string()).await?;
@@ -1081,7 +1084,7 @@ pub async fn handle_delete_pep_node<Fs: FileStore + Clone>(
}
// TODO: could probably macro-ise?
-pub async fn handle_online_result<Fs: FileStore + Clone>(
+pub async fn handle_online_result<Fs: FileStore + Clone + 'static>(
logic: &ClientLogic<Fs>,
command: Command<Fs>,
connection: Connected,