1use core::pin::Pin;
7use std::sync::Arc;
8
9use alloc::boxed::Box;
10use async_channel::{Receiver, Sender};
11use futures_util::{FutureExt, StreamExt};
12use spin::RwLock;
13
14use crate::BinaryDecode;
15use crate::batch::with_runtime;
16use crate::function::{CALL_EXPORT_FN_ID, DROP_NATIVE_REF_FN_ID, RustCallback};
17use crate::ipc::MessageType;
18use crate::ipc::{DecodedData, DecodedVariant, IPCMessage};
19use crate::object_store::ObjectHandle;
20use crate::object_store::remove_object;
21
22#[derive(Debug, Clone)]
27pub struct WryBindgenEvent {
28 id: u64,
29 event: AppEventVariant,
30}
31
32impl WryBindgenEvent {
33 pub(crate) fn id(&self) -> u64 {
35 self.id
36 }
37
38 pub(crate) fn ipc(id: u64, msg: IPCMessage) -> Self {
40 Self {
41 id,
42 event: AppEventVariant::Ipc(msg),
43 }
44 }
45
46 pub(crate) fn webview_loaded(id: u64) -> Self {
48 Self {
49 id,
50 event: AppEventVariant::WebviewLoaded,
51 }
52 }
53
54 pub(crate) fn into_variant(self) -> AppEventVariant {
56 self.event
57 }
58}
59
60#[derive(Debug, Clone)]
61pub(crate) enum AppEventVariant {
62 Ipc(IPCMessage),
64 WebviewLoaded,
66}
67
68#[derive(Clone)]
69pub(crate) struct IPCSenders {
70 eval_sender: Sender<IPCMessage>,
71 respond_sender: futures_channel::mpsc::UnboundedSender<IPCMessage>,
72}
73
74impl IPCSenders {
75 pub(crate) fn start_send(&self, msg: IPCMessage) {
76 match msg.ty().unwrap() {
77 MessageType::Evaluate => {
78 self.eval_sender
79 .try_send(msg)
80 .expect("Failed to send evaluate message");
81 }
82 MessageType::Respond => {
83 self.respond_sender
84 .unbounded_send(msg)
85 .expect("Failed to send respond message");
86 }
87 }
88 }
89}
90
91struct IPCReceivers {
92 eval_receiver: Pin<Box<Receiver<IPCMessage>>>,
93 respond_receiver: futures_channel::mpsc::UnboundedReceiver<IPCMessage>,
94}
95
96impl IPCReceivers {
97 pub fn recv_blocking(&mut self) -> IPCMessage {
98 pollster::block_on(async {
99 let Self {
100 eval_receiver,
101 respond_receiver,
102 } = self;
103 futures_util::select_biased! {
104 respond_msg = respond_receiver.next().fuse() => {
107 respond_msg.expect("Failed to receive respond message")
108 },
109 eval_msg = eval_receiver.next().fuse() => {
110 eval_msg.expect("Failed to receive evaluate message")
111 },
112 }
113 })
114 }
115}
116
117pub(crate) struct WryIPC {
122 pub(crate) proxy: Arc<dyn Fn(WryBindgenEvent) + Send + Sync>,
123 receivers: RwLock<IPCReceivers>,
124}
125
126impl WryIPC {
127 pub(crate) fn new(proxy: Arc<dyn Fn(WryBindgenEvent) + Send + Sync>) -> (Self, IPCSenders) {
129 let (eval_sender, eval_receiver) = async_channel::unbounded();
130 let (respond_sender, respond_receiver) = futures_channel::mpsc::unbounded();
131 let senders = IPCSenders {
132 eval_sender,
133 respond_sender,
134 };
135 let receivers = RwLock::new(IPCReceivers {
136 eval_receiver: Box::pin(eval_receiver),
137 respond_receiver,
138 });
139 let ipc = Self { proxy, receivers };
140 (ipc, senders)
141 }
142
143 pub(crate) fn js_response(&self, id: u64, responder: IPCMessage) {
145 (self.proxy)(WryBindgenEvent::ipc(id, responder));
146 }
147}
148
149pub(crate) fn progress_js_with<O>(
150 with_respond: impl for<'a> Fn(DecodedData<'a>) -> O,
151) -> Option<O> {
152 let response = with_runtime(|runtime| runtime.ipc().receivers.write().recv_blocking());
153
154 let decoder = response.decoded().expect("Failed to decode response");
155 match decoder {
156 DecodedVariant::Respond { data } => Some(with_respond(data)),
157 DecodedVariant::Evaluate { mut data } => {
158 handle_rust_callback(&mut data);
159 None
160 }
161 }
162}
163
164pub async fn handle_callbacks() {
165 let receiver = with_runtime(|runtime| runtime.ipc().receivers.read().eval_receiver.clone());
166
167 while let Ok(response) = receiver.recv().await {
168 let decoder = response.decoded().expect("Failed to decode response");
169 match decoder {
170 DecodedVariant::Respond { .. } => unreachable!(),
171 DecodedVariant::Evaluate { mut data } => {
172 handle_rust_callback(&mut data);
173 }
174 }
175 }
176}
177
178fn handle_rust_callback(data: &mut DecodedData) {
180 let fn_id = data.take_u32().expect("Failed to read fn_id");
181 let response = match fn_id {
182 0 => {
184 let key = data.take_u32().unwrap();
185
186 let callback = with_runtime(|state| {
189 let rust_callback = state.get_object::<RustCallback>(key);
190
191 rust_callback.clone_rc()
192 });
193
194 with_runtime(|state| state.push_borrow_frame());
196
197 let response = IPCMessage::new_respond(|encoder| {
199 (callback)(data, encoder);
200 });
201
202 with_runtime(|state| state.pop_borrow_frame());
204
205 response
206 }
207 DROP_NATIVE_REF_FN_ID => {
209 let key = ObjectHandle::decode(data).expect("Failed to decode object handle");
210
211 remove_object::<RustCallback>(key);
213
214 IPCMessage::new_respond(|_| {})
216 }
217 CALL_EXPORT_FN_ID => {
219 let export_name: alloc::string::String =
221 crate::encode::BinaryDecode::decode(data).expect("Failed to decode export name");
222
223 let export = crate::inventory::iter::<crate::JsExportSpec>()
225 .find(|e| e.name == export_name)
226 .unwrap_or_else(|| panic!("Unknown export: {export_name}"));
227
228 let result = (export.handler)(data);
230
231 assert!(data.is_empty(), "Extra data remaining after export call");
232
233 match result {
235 Ok(encoded) => IPCMessage::new_respond(|encoder| {
236 encoder.extend(&encoded);
237 }),
238 Err(err) => {
239 panic!("Export call failed: {err}");
240 }
241 }
242 }
243 _ => todo!(),
244 };
245 with_runtime(|runtime| runtime.ipc().js_response(runtime.webview_id(), response));
246}