1use std::{any::TypeId, collections::HashMap, sync::atomic::AtomicBool};
2
3use bevy::{
4 ecs::system::{Resource, SystemParam},
5 prelude::*,
6};
7use headless_webview::webview::RpcRequest;
8use serde::{Deserialize, Serialize};
9
10use crate::{systems, PostUpdateLabel, PreUpdateLabel};
11
12#[derive(Default)]
14pub(crate) struct InputEventMapping {
15 pub events: HashMap<TypeId, &'static str>,
16}
17
18#[derive(Default)]
20pub(crate) struct OutputEventMapping {
21 pub events: HashMap<TypeId, &'static str>,
22}
23
24pub(crate) struct InputEvent {
26 pub entity: Entity,
28
29 pub request: RpcRequest,
31
32 pub matched: AtomicBool,
35}
36
37impl InputEvent {
38 pub fn new(entity: Entity, request: RpcRequest) -> Self {
39 Self {
40 matched: AtomicBool::new(false),
41 entity,
42 request,
43 }
44 }
45}
46
47#[derive(Deserialize, Serialize, Debug)]
49pub struct WebviewEvent<T> {
50 pub(crate) entity: Option<Entity>,
51 pub(crate) val: T,
52}
53
54impl<T> WebviewEvent<T> {
55 pub fn new(entity: Option<Entity>, val: T) -> Self {
56 Self { entity, val }
57 }
58}
59
60#[derive(SystemParam)]
62pub struct WebviewEventReader<'w, 's, T: Resource> {
63 pub events: EventReader<'w, 's, WebviewEvent<T>>,
64}
65
66impl<'w, 's, T: Resource> WebviewEventReader<'w, 's, T> {
67 pub fn iter(&mut self) -> impl DoubleEndedIterator<Item = &T> {
68 self.events
69 .iter_with_id()
70 .map(|(event, _id)| event)
71 .map(|event| &event.val)
72 }
73
74 pub fn iter_with_entity(&mut self) -> impl DoubleEndedIterator<Item = (&T, Entity)> {
75 self.events
76 .iter_with_id()
77 .map(|(event, _id)| event)
78 .map(|event| (&event.val, event.entity.unwrap()))
79 }
80
81 }
91
92#[derive(SystemParam)]
94pub struct WebviewEventWriter<'w, 's, T: Resource> {
95 pub events: EventWriter<'w, 's, WebviewEvent<T>>,
96}
97
98impl<'w, 's, T: Resource> WebviewEventWriter<'w, 's, T> {
99 pub fn send(&mut self, event: T) {
101 self.events.send(WebviewEvent::new(None, event));
102 }
103
104 pub fn send_to_entity(&mut self, entity: Entity, event: T) {
106 self.events.send(WebviewEvent::new(Some(entity), event));
107 }
108}
109
110pub trait WebviewApp {
152 fn add_webview_input_event<T>(&mut self, method: &'static str) -> &mut Self
154 where
155 T: Resource + for<'de> serde::Deserialize<'de>;
156
157 fn add_webview_output_event<T>(&mut self, method: &'static str) -> &mut Self
159 where
160 T: Resource + for<'de> serde::Serialize;
161}
162
163impl WebviewApp for App {
164 fn add_webview_input_event<T>(&mut self, method: &'static str) -> &mut Self
165 where
166 T: Resource + for<'de> serde::Deserialize<'de>,
167 {
168 let mut rpc_input_events = self
169 .world
170 .get_resource_mut::<InputEventMapping>()
171 .expect("Add `WebviewPlugin` before calling `.add_webview_input_event`");
172
173 rpc_input_events.events.insert(TypeId::of::<T>(), method);
174
175 self.add_event::<WebviewEvent<T>>();
176
177 self.add_system_to_stage(
178 CoreStage::PreUpdate,
179 systems::rpc_event_receiver::<T>.after(PreUpdateLabel::Pre),
180 );
181 self
182 }
183
184 fn add_webview_output_event<T>(&mut self, method: &'static str) -> &mut Self
185 where
186 T: Resource + for<'de> serde::Serialize,
187 {
188 let mut rpc_output_events = self
189 .world
190 .get_resource_mut::<OutputEventMapping>()
191 .expect("Add `WebviewPlugin` before calling `.add_webview_input_event`");
192
193 rpc_output_events.events.insert(TypeId::of::<T>(), method);
194
195 self.add_event::<WebviewEvent<T>>();
196
197 self.add_system_to_stage(
198 CoreStage::PostUpdate,
199 systems::rpc_event_sender::<T>.label(PostUpdateLabel::Pre),
200 );
201
202 self
203 }
204}
205
206#[derive(Deserialize, Debug)]
208#[serde(rename_all(deserialize = "lowercase"))]
209pub(crate) enum BuiltinWebviewEvent {
210 Despawn,
211 Initialize,
212}