bitwarden_ipc/wasm/
ipc_client.rs

1use 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    IpcClient,
9    ipc_client::{IpcClientSubscription, ReceiveError, SubscribeError},
10    message::{IncomingMessage, OutgoingMessage},
11    traits::{InMemorySessionRepository, NoEncryptionCryptoProvider},
12    wasm::{
13        JsSessionRepository, RawJsSessionRepository,
14        generic_session_repository::GenericSessionRepository,
15    },
16};
17
18/// JavaScript wrapper around the IPC client. For more information, see the
19/// [IpcClient] documentation.
20#[wasm_bindgen(js_name = IpcClient)]
21pub struct JsIpcClient {
22    #[wasm_bindgen(skip)]
23    /// The underlying IPC client instance. Use this to create WASM-compatible functions
24    /// that interact with the IPC client, e.g. to register RPC handlers, trigger RPC requests,
25    /// send typed messages, etc. For examples see
26    /// [wasm::ipc_register_discover_handler](crate::wasm::ipc_register_discover_handler).
27    pub client: Arc<
28        IpcClient<NoEncryptionCryptoProvider, JsCommunicationBackend, GenericSessionRepository>,
29    >,
30}
31
32/// JavaScript wrapper around the IPC client subscription. For more information, see the
33/// [IpcClientSubscription](crate::IpcClientSubscription) documentation.
34#[wasm_bindgen(js_name = IpcClientSubscription)]
35pub struct JsIpcClientSubscription {
36    subscription: IpcClientSubscription,
37}
38
39#[wasm_bindgen(js_class = IpcClientSubscription)]
40impl JsIpcClientSubscription {
41    #[allow(missing_docs)]
42    pub async fn receive(
43        &mut self,
44        abort_signal: Option<AbortSignal>,
45    ) -> Result<IncomingMessage, ReceiveError> {
46        let cancellation_token = abort_signal.map(|signal| signal.to_cancellation_token());
47        self.subscription.receive(cancellation_token).await
48    }
49}
50
51#[wasm_bindgen(js_class = IpcClient)]
52impl JsIpcClient {
53    /// Create a new `IpcClient` instance with an in-memory session repository for saving
54    /// sessions within the SDK.
55    #[wasm_bindgen(js_name = newWithSdkInMemorySessions)]
56    pub fn new_with_sdk_in_memory_sessions(
57        communication_provider: &JsCommunicationBackend,
58    ) -> JsIpcClient {
59        JsIpcClient {
60            client: IpcClient::new(
61                NoEncryptionCryptoProvider,
62                communication_provider.clone(),
63                GenericSessionRepository::InMemory(Arc::new(InMemorySessionRepository::new(
64                    HashMap::new(),
65                ))),
66            ),
67        }
68    }
69    /// Create a new `IpcClient` instance with a client-managed session repository for saving
70    /// sessions using State Provider.
71    #[wasm_bindgen(js_name = newWithClientManagedSessions)]
72    pub fn new_with_client_managed_sessions(
73        communication_provider: &JsCommunicationBackend,
74        session_repository: RawJsSessionRepository,
75    ) -> JsIpcClient {
76        JsIpcClient {
77            client: IpcClient::new(
78                NoEncryptionCryptoProvider,
79                communication_provider.clone(),
80                GenericSessionRepository::JsSessionRepository(Arc::new(JsSessionRepository::new(
81                    session_repository,
82                ))),
83            ),
84        }
85    }
86
87    #[allow(missing_docs)]
88    pub async fn start(&self) {
89        self.client.start().await
90    }
91
92    #[wasm_bindgen(js_name = isRunning)]
93    #[allow(missing_docs)]
94    pub async fn is_running(&self) -> bool {
95        self.client.is_running().await
96    }
97
98    #[allow(missing_docs)]
99    pub async fn send(&self, message: OutgoingMessage) -> Result<(), JsError> {
100        self.client
101            .send(message)
102            .await
103            .map_err(|e| JsError::new(&e))
104    }
105
106    #[allow(missing_docs)]
107    pub async fn subscribe(&self) -> Result<JsIpcClientSubscription, SubscribeError> {
108        let subscription = self.client.subscribe(None).await?;
109        Ok(JsIpcClientSubscription { subscription })
110    }
111}