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 error::{AlreadyRunningError, ReceiveError, SubscribeError},
10 ipc_client::IpcClientSubscription,
11 ipc_client_trait::IpcClient,
12 message::{IncomingMessage, OutgoingMessage},
13 traits::{InMemorySessionRepository, NoEncryptionCryptoProvider},
14 wasm::{
15 JsSessionRepository, RawJsSessionRepository,
16 generic_session_repository::GenericSessionRepository,
17 },
18};
19
20#[wasm_bindgen(js_name = IpcClient)]
23pub struct JsIpcClient {
24 #[wasm_bindgen(skip)]
25 pub client: Arc<dyn IpcClient>,
30}
31
32#[wasm_bindgen(js_name = IpcClientSubscription)]
35pub struct JsIpcClientSubscription {
36 subscription: IpcClientSubscription,
37}
38
39#[bitwarden_ffi::wasm_export]
40#[wasm_bindgen(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]
56#[wasm_bindgen(js_class = IpcClient)]
57impl JsIpcClient {
58 #[wasm_only]
61 #[wasm_bindgen(js_name = newWithSdkInMemorySessions)]
62 pub fn new_with_sdk_in_memory_sessions(
63 communication_provider: &JsCommunicationBackend,
64 ) -> JsIpcClient {
65 JsIpcClient {
66 client: Arc::new(IpcClientImpl::new(
67 NoEncryptionCryptoProvider,
68 communication_provider.clone(),
69 GenericSessionRepository::InMemory(Arc::new(InMemorySessionRepository::new(
70 HashMap::new(),
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 NoEncryptionCryptoProvider,
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}