Add Stream/Sink for wasm

This commit is contained in:
Sosthene 2025-08-23 17:47:32 +02:00
parent 1b885606ae
commit aaaec47c23
2 changed files with 74 additions and 38 deletions

View File

@ -10,7 +10,7 @@ crate-type = ["cdylib", "rlib"]
default = [] default = []
parallel = ["sp-client/parallel"] parallel = ["sp-client/parallel"]
blindbit-backend = ["backend-blindbit-native"] blindbit-backend = ["backend-blindbit-native"]
blindbit-wasm = ["backend-blindbit-wasm", "dep:js-sys", "dep:serde-wasm-bindgen"] blindbit-wasm = ["backend-blindbit-wasm", "dep:js-sys", "dep:serde-wasm-bindgen", "dep:futures"]
[dependencies] [dependencies]
aes-gcm = "0.10.3" aes-gcm = "0.10.3"
@ -32,4 +32,5 @@ wasm-bindgen = "0.2.91"
# WASM-specific dependencies (optional) # WASM-specific dependencies (optional)
js-sys = { version = "0.3.69", optional = true } js-sys = { version = "0.3.69", optional = true }
serde-wasm-bindgen = { version = "0.6.5", optional = true } serde-wasm-bindgen = { version = "0.6.5", optional = true }
futures = { version = "0.3", optional = true }

View File

@ -1,15 +1,6 @@
use anyhow::Result; use anyhow::Result;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{ use std::mem;
mem,
sync::{
mpsc::{self, Receiver, Sender},
Arc, RwLock,
},
};
// use wasm_bindgen::prelude::*;
// use sp_client::bitcoin::absolute::Height;
// use sp_client::bitcoin::BlockHash;
use sp_client::{ use sp_client::{
bitcoin::{absolute::Height, BlockHash, OutPoint}, bitcoin::{absolute::Height, BlockHash, OutPoint},
OwnedOutput, Updater, OwnedOutput, Updater,
@ -36,28 +27,28 @@ pub enum StateUpdate {
}, },
} }
// #[cfg(target_arch = "wasm32")] #[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
// #[wasm_bindgen] use std::sync::{mpsc::{self, Receiver, Sender}};
// extern "C" {
// #[wasm_bindgen(js_namespace = window)]
// fn sendScanProgress(progress: JsValue);
// #[wasm_bindgen(js_namespace = window)]
// fn sendStateUpdate(update: JsValue);
// }
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
pub trait UpdateSink: Send + Sync { pub trait UpdateSink: Send + Sync {
fn send_scan_progress(&self, progress: ScanProgress) -> Result<()>; fn send_scan_progress(&self, progress: ScanProgress) -> Result<()>;
fn send_state_update(&self, update: StateUpdate) -> Result<()>; fn send_state_update(&self, update: StateUpdate) -> Result<()>;
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
pub trait UpdateSink {
fn send_scan_progress(&self, progress: ScanProgress) -> Result<()>;
fn send_state_update(&self, update: StateUpdate) -> Result<()>;
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
pub struct NativeUpdateSink { pub struct NativeUpdateSink {
scan_tx: Sender<ScanProgress>, scan_tx: Sender<ScanProgress>,
state_tx: Sender<StateUpdate>, state_tx: Sender<StateUpdate>,
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
impl NativeUpdateSink { impl NativeUpdateSink {
pub fn new() -> (Self, Receiver<ScanProgress>, Receiver<StateUpdate>) { pub fn new() -> (Self, Receiver<ScanProgress>, Receiver<StateUpdate>) {
let (scan_tx, scan_rx) = mpsc::channel(); let (scan_tx, scan_rx) = mpsc::channel();
@ -67,7 +58,7 @@ impl NativeUpdateSink {
} }
} }
#[cfg(not(target_arch = "wasm32"))] #[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
impl UpdateSink for NativeUpdateSink { impl UpdateSink for NativeUpdateSink {
fn send_scan_progress(&self, progress: ScanProgress) -> Result<()> { fn send_scan_progress(&self, progress: ScanProgress) -> Result<()> {
self.scan_tx.send(progress)?; self.scan_tx.send(progress)?;
@ -80,36 +71,80 @@ impl UpdateSink for NativeUpdateSink {
} }
} }
// #[cfg(target_arch = "wasm32")] #[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
// pub struct WasmUpdateSink; use futures::channel::mpsc::{unbounded, UnboundedSender, UnboundedReceiver};
// #[cfg(target_arch = "wasm32")] #[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
// impl UpdateSink for WasmUpdateSink { pub struct WasmUpdateSink {
// fn send_scan_progress(&self, progress: ScanProgress) -> Result<()> { scan_tx: UnboundedSender<ScanProgress>,
// let js_value = serde_wasm_bindgen::to_value(&progress)?; state_tx: UnboundedSender<StateUpdate>,
// sendScanProgress(js_value); }
// Ok(())
// }
// fn send_state_update(&self, update: StateUpdate) -> Result<()> { #[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
// let js_value = serde_wasm_bindgen::to_value(&update)?; impl WasmUpdateSink {
// sendStateUpdate(js_value); pub fn new() -> (Rc<Self>, UnboundedReceiver<ScanProgress>, UnboundedReceiver<StateUpdate>) {
// Ok(()) let (scan_tx, scan_rx) = unbounded();
// } let (state_tx, state_rx) = unbounded();
// }
(Rc::new(Self { scan_tx, state_tx }), scan_rx, state_rx)
}
}
#[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
impl UpdateSink for WasmUpdateSink {
fn send_scan_progress(&self, progress: ScanProgress) -> Result<()> {
self.scan_tx.unbounded_send(progress)
.map_err(|e| anyhow::Error::msg(format!("Failed to send scan progress: {}", e)))?;
Ok(())
}
fn send_state_update(&self, update: StateUpdate) -> Result<()> {
self.state_tx.unbounded_send(update)
.map_err(|e| anyhow::Error::msg(format!("Failed to send state update: {}", e)))?;
Ok(())
}
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
use std::sync::{Arc, RwLock};
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
// Global sink instance // Global sink instance
static UPDATE_SINK: RwLock<Option<Arc<dyn UpdateSink>>> = RwLock::new(None); static UPDATE_SINK: RwLock<Option<Arc<dyn UpdateSink>>> = RwLock::new(None);
#[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
use std::cell::RefCell;
use std::rc::Rc;
#[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
thread_local! {
static UPDATE_SINK: RefCell<Option<Rc<dyn UpdateSink>>> = RefCell::new(None);
}
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
pub fn init_update_sink(sink: Arc<dyn UpdateSink>) { pub fn init_update_sink(sink: Arc<dyn UpdateSink>) {
let mut sink_guard = UPDATE_SINK.write().unwrap(); let mut sink_guard = UPDATE_SINK.write().unwrap();
*sink_guard = Some(sink); *sink_guard = Some(sink);
} }
#[cfg(all(not(target_arch = "wasm32"), not(feature = "blindbit-wasm")))]
pub fn get_update_sink() -> Option<Arc<dyn UpdateSink>> { pub fn get_update_sink() -> Option<Arc<dyn UpdateSink>> {
UPDATE_SINK.read().unwrap().clone() UPDATE_SINK.read().unwrap().clone()
} }
#[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
pub fn init_update_sink(sink: Rc<dyn UpdateSink>) {
UPDATE_SINK.with(|cell| {
*cell.borrow_mut() = Some(sink);
});
}
#[cfg(all(target_arch = "wasm32", feature = "blindbit-wasm"))]
pub fn get_update_sink() -> Option<Rc<dyn UpdateSink>> {
UPDATE_SINK.with(|cell| cell.borrow().clone())
}
#[derive(Debug)] #[derive(Debug)]
pub struct StateUpdater { pub struct StateUpdater {
update: bool, update: bool,