bitwarden_ipc/wasm/
ipc_client.rs1use std::{collections::HashMap, sync::Arc};
2
3use bitwarden_threading::cancellation_token::wasm::{AbortSignal, AbortSignalExt};
4use wasm_bindgen::prelude::*;
5
6use super::communication_backend::JsCommunicationBackend;
7use crate::{
8 IpcClientImpl,
9 crypto_provider::noise::crypto_provider::NoiseCryptoProvider,
10 error::{AlreadyRunningError, ReceiveError, SubscribeError},
11 ipc_client::IpcClientSubscription,
12 ipc_client_trait::IpcClient,
13 message::{IncomingMessage, OutgoingMessage},
14 traits::InMemorySessionRepository,
15 wasm::{
16 JsSessionRepository, RawJsSessionRepository,
17 generic_session_repository::GenericSessionRepository,
18 },
19};
20
21#[wasm_bindgen(js_name = IpcClient)]
24pub struct JsIpcClient {
25 #[wasm_bindgen(skip)]
26 pub client: Arc<dyn IpcClient>,
31}
32
33#[wasm_bindgen(js_name = IpcClientSubscription)]
36pub struct JsIpcClientSubscription {
37 subscription: IpcClientSubscription,
38}
39
40#[bitwarden_ffi::wasm_export(js_class = IpcClientSubscription)]
41impl JsIpcClientSubscription {
42 #[wasm_only(
43 note = "Use the `subscribe` method on `IpcClient` to create a subscription instance."
44 )]
45 #[allow(missing_docs)]
46 pub async fn receive(
47 &mut self,
48 abort_signal: Option<AbortSignal>,
49 ) -> Result<IncomingMessage, ReceiveError> {
50 let cancellation_token = abort_signal.map(|signal| signal.to_cancellation_token());
51 self.subscription.receive(cancellation_token).await
52 }
53}
54
55#[bitwarden_ffi::wasm_export(js_class = IpcClient)]
56impl JsIpcClient {
57 #[wasm_only]
60 #[wasm_bindgen(js_name = newWithSdkInMemorySessions)]
61 pub fn new_with_sdk_in_memory_sessions(
62 communication_provider: &JsCommunicationBackend,
63 ) -> JsIpcClient {
64 JsIpcClient {
65 client: Arc::new(IpcClientImpl::new(
66 NoiseCryptoProvider::new(),
67 communication_provider.clone(),
68 GenericSessionRepository::InMemory(Arc::new(InMemorySessionRepository::new(
69 HashMap::new(),
70 ))),
71 )),
72 }
73 }
74
75 #[wasm_only]
78 #[wasm_bindgen(js_name = newWithClientManagedSessions)]
79 pub fn new_with_client_managed_sessions(
80 communication_provider: &JsCommunicationBackend,
81 session_repository: RawJsSessionRepository,
82 ) -> JsIpcClient {
83 JsIpcClient {
84 client: Arc::new(IpcClientImpl::new(
85 NoiseCryptoProvider::new(),
86 communication_provider.clone(),
87 GenericSessionRepository::JsSessionRepository(Arc::new(JsSessionRepository::new(
88 session_repository,
89 ))),
90 )),
91 }
92 }
93
94 #[wasm_only]
95 #[allow(missing_docs)]
96 pub async fn start(
97 &self,
98 abort_signal: Option<AbortSignal>,
99 ) -> Result<(), AlreadyRunningError> {
100 self.client
101 .start(abort_signal.map(|signal| signal.to_cancellation_token()))
102 .await
103 }
104
105 #[wasm_only]
106 #[wasm_bindgen(js_name = isRunning)]
107 #[allow(missing_docs)]
108 pub fn is_running(&self) -> bool {
109 self.client.is_running()
110 }
111
112 #[wasm_only]
113 #[allow(missing_docs)]
114 pub async fn send(&self, message: OutgoingMessage) -> Result<(), JsError> {
115 self.client
116 .send(message)
117 .await
118 .map_err(|e| JsError::new(&e.to_string()))
119 }
120
121 #[wasm_only]
122 #[allow(missing_docs)]
123 pub async fn subscribe(&self) -> Result<JsIpcClientSubscription, SubscribeError> {
124 let subscription = self.client.subscribe(None).await?;
125 Ok(JsIpcClientSubscription { subscription })
126 }
127}