bitwarden_ipc/
ipc_client_ext.rs1use bitwarden_threading::cancellation_token::CancellationToken;
2use serde::{Serialize, de::DeserializeOwned};
3
4use crate::{
5 RpcHandler,
6 endpoint::Endpoint,
7 error::{RequestError, SubscribeError},
8 ipc_client::IpcClientTypedSubscription,
9 ipc_client_trait::IpcClient,
10 message::{OutgoingMessage, PayloadTypeName, TypedOutgoingMessage},
11 rpc::{
12 error::RpcError,
13 request::RpcRequest,
14 request_message::{RPC_REQUEST_PAYLOAD_TYPE_NAME, RpcRequestMessage},
15 response_message::IncomingRpcResponseMessage,
16 },
17 serde_utils,
18};
19
20pub trait IpcClientExt: IpcClient {
26 fn register_rpc_handler<H>(&self, handler: H) -> impl std::future::Future<Output = ()> + Send
30 where
31 H: RpcHandler + Send + Sync + 'static,
32 {
33 async move {
34 self.register_rpc_handler_erased(H::Request::NAME, Box::new(handler))
35 .await;
36 }
37 }
38
39 fn send_typed<Payload>(
41 &self,
42 payload: Payload,
43 destination: Endpoint,
44 ) -> impl std::future::Future<Output = Result<(), RequestError>> + Send
45 where
46 Payload: Serialize + PayloadTypeName + Send,
47 {
48 async move {
49 let message = TypedOutgoingMessage {
50 payload,
51 destination,
52 }
53 .try_into()
54 .map_err(|e: serde_utils::DeserializeError| {
55 RequestError::Rpc(RpcError::RequestSerialization(e.to_string()))
56 })?;
57
58 self.send(message).await.map_err(RequestError::from)
59 }
60 }
61
62 fn subscribe_typed<Payload>(
65 &self,
66 ) -> impl std::future::Future<
67 Output = Result<IpcClientTypedSubscription<Payload>, SubscribeError>,
68 > + Send
69 where
70 Payload: DeserializeOwned + PayloadTypeName,
71 {
72 async move {
73 Ok(IpcClientTypedSubscription::new(
74 self.subscribe(Some(Payload::PAYLOAD_TYPE_NAME.to_owned()))
75 .await?,
76 ))
77 }
78 }
79
80 fn request<Request>(
84 &self,
85 request: Request,
86 destination: Endpoint,
87 cancellation_token: Option<CancellationToken>,
88 ) -> impl std::future::Future<Output = Result<Request::Response, RequestError>> + Send
89 where
90 Request: RpcRequest + Send,
91 Request::Response: Send,
92 {
93 async move {
94 let request_payload = RpcRequestMessage::new(request);
95
96 let mut response_subscription = self
101 .subscribe(Some(request_payload.response_topic.clone()))
102 .await?;
103
104 let payload = serde_utils::to_vec(&request_payload)
107 .map_err(|e| RequestError::Rpc(RpcError::RequestSerialization(e.to_string())))?;
108 let message = OutgoingMessage {
109 payload,
110 destination,
111 topic: Some(RPC_REQUEST_PAYLOAD_TYPE_NAME.to_owned()),
112 };
113
114 self.send(message).await.map_err(RequestError::from)?;
115
116 let received = response_subscription
117 .receive(cancellation_token)
118 .await
119 .map_err(|e| RequestError::Receive(e.into()))?;
120
121 let response: IncomingRpcResponseMessage<Request::Response> =
122 serde_utils::from_slice(&received.payload).map_err(|e| {
123 RequestError::Rpc(RpcError::ResponseDeserialization(e.to_string()))
124 })?;
125
126 Ok(response.result?)
127 }
128 }
129}
130
131impl<T: IpcClient + ?Sized> IpcClientExt for T {}