1use std::collections::HashMap;
2
3use bevy::{ecs::system::SystemId, prelude::*};
4use bevy_crossbeam_event::CrossbeamEventSender;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8use crate::Channel;
9
10#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
12#[serde(rename_all = "snake_case")]
13pub enum PresenceEvent {
14 Track,
15 Untrack,
16 Join,
17 Leave,
18 Sync,
19}
20
21pub type RawPresenceState = HashMap<String, RawPresenceMetas>;
22
23#[derive(Clone)]
24pub(crate) struct PresenceCallback(pub SystemId<In<(String, PresenceState, PresenceState)>>);
25
26#[derive(Event, Clone)]
27pub struct PresenceCallbackEvent(
28 pub (
29 SystemId<In<(String, PresenceState, PresenceState)>>,
30 (String, PresenceState, PresenceState),
31 ),
32);
33pub type PresenceStateInner = HashMap<String, PhxMap>;
40
41pub type PhxMap = HashMap<String, StateData>;
42
43pub type StateData = HashMap<String, Value>;
44
45#[derive(Default, Clone, Debug)]
51pub struct PresenceState(pub PresenceStateInner);
52
53impl PresenceState {
54 pub fn get_phx_map(&self) -> PhxMap {
57 let mut new_map = HashMap::new();
58 for (_id, map) in self.0.clone() {
59 for (phx_id, state_data) in map {
60 new_map.insert(phx_id, state_data);
61 }
62 }
63 new_map
64 }
65}
66
67type PresenceIteratorItem = (String, HashMap<String, HashMap<String, Value>>);
68
69impl FromIterator<PresenceIteratorItem> for PresenceState {
70 fn from_iter<T: IntoIterator<Item = PresenceIteratorItem>>(iter: T) -> Self {
71 let mut new_id_map = HashMap::new();
72
73 for (id, id_map) in iter {
74 new_id_map.insert(id, id_map);
75 }
76
77 PresenceState(new_id_map)
78 }
79}
80
81#[derive(Serialize, Deserialize, Debug, Clone, Default)]
83pub struct RawPresenceMeta {
84 pub phx_ref: String,
85 #[serde(flatten)]
86 pub state_data: HashMap<String, Value>,
87}
88
89#[derive(Serialize, Deserialize, Debug, Clone, Default)]
91pub struct RawPresenceMetas {
92 pub metas: Vec<RawPresenceMeta>,
93}
94
95impl From<RawPresenceState> for PresenceState {
96 fn from(val: RawPresenceState) -> Self {
97 let mut transformed_state = PresenceState(HashMap::new());
98
99 for (id, metas) in val {
100 let mut transformed_inner = HashMap::new();
101
102 for meta in metas.metas {
103 transformed_inner.insert(meta.phx_ref, meta.state_data);
104 }
105
106 transformed_state.0.insert(id, transformed_inner);
107 }
108
109 transformed_state
110 }
111}
112
113#[derive(Serialize, Deserialize, Debug, Clone)]
115pub struct RawPresenceDiff {
116 joins: RawPresenceState,
117 leaves: RawPresenceState,
118}
119
120impl From<RawPresenceDiff> for PresenceDiff {
121 fn from(val: RawPresenceDiff) -> Self {
122 PresenceDiff {
123 joins: val.joins.into(),
124 leaves: val.leaves.into(),
125 }
126 }
127}
128
129#[derive(Debug, Clone)]
130pub(crate) struct PresenceDiff {
131 joins: PresenceState,
132 leaves: PresenceState,
133}
134
135pub(crate) struct Presence {
136 pub state: PresenceState,
137 callbacks: HashMap<PresenceEvent, Vec<PresenceCallback>>,
138 presence_callback_event_sender: CrossbeamEventSender<PresenceCallbackEvent>,
139}
140
141impl Presence {
142 pub(crate) fn from_channel_builder(
143 callbacks: HashMap<PresenceEvent, Vec<PresenceCallback>>,
144 presence_callback_event_sender: CrossbeamEventSender<PresenceCallbackEvent>,
145 ) -> Self {
146 Self {
147 state: PresenceState::default(),
148 callbacks,
149 presence_callback_event_sender,
150 }
151 }
152
153 pub(crate) fn sync(&mut self, new_state: PresenceState) {
154 let joins: PresenceState = new_state
156 .0
157 .clone()
158 .into_iter()
159 .map(|(new_id, mut new_phx_map)| {
160 new_phx_map.retain(|new_phx_ref, _new_state_data| {
161 let mut retain = true;
162 let _ = self.state.0.clone().into_values().map(|self_phx_map| {
163 if self_phx_map.contains_key(new_phx_ref) {
164 retain = false;
165 }
166 });
167 retain
168 });
169
170 (new_id, new_phx_map)
171 })
172 .collect();
173
174 let leaves: PresenceState = self
175 .state
176 .0
177 .clone()
178 .into_iter()
179 .map(|(current_id, mut current_phx_map)| {
180 current_phx_map.retain(|current_phx_ref, _current_state_data| {
181 let mut retain = false;
182 let _ = new_state.0.clone().into_values().map(|new_phx_map| {
183 if !new_phx_map.contains_key(current_phx_ref) {
184 retain = true;
185 }
186 });
187 retain
188 });
189
190 (current_id, current_phx_map)
191 })
192 .collect();
193
194 let prev_state = self.state.clone();
195
196 self.sync_diff(PresenceDiff { joins, leaves });
197
198 for (id, _data) in self.state.0.clone() {
199 for cb in self
200 .callbacks
201 .get_mut(&PresenceEvent::Sync)
202 .unwrap_or(&mut vec![])
203 {
204 self.presence_callback_event_sender
205 .send(PresenceCallbackEvent((
206 cb.0,
207 (id.clone(), prev_state.clone(), self.state.clone()),
208 )));
209 }
210 }
211 }
212
213 pub(crate) fn sync_diff(&mut self, diff: PresenceDiff) -> &PresenceState {
214 for (id, _data) in diff.joins.0.clone() {
219 for cb in self
220 .callbacks
221 .get_mut(&PresenceEvent::Join)
222 .unwrap_or(&mut vec![])
223 {
224 self.presence_callback_event_sender
225 .send(PresenceCallbackEvent((
226 cb.0,
227 (id.clone(), self.state.clone(), diff.clone().joins),
228 )));
229 }
230 }
231
232 for (id, _data) in diff.leaves.0.clone() {
233 for cb in self
234 .callbacks
235 .get_mut(&PresenceEvent::Leave)
236 .unwrap_or(&mut vec![])
237 {
238 self.presence_callback_event_sender
239 .send(PresenceCallbackEvent((
240 cb.0,
241 (id.clone(), self.state.clone(), diff.clone().leaves),
242 )));
243 }
244
245 self.state.0.remove(&id);
246 }
247
248 self.state.0.extend(diff.joins.0);
249
250 &self.state
251 }
252}
253
254#[derive(Component)]
257pub struct PrescenceTrack {
258 pub payload: HashMap<String, Value>,
259}
260
261pub fn update_presence_track(
262 q: Query<(&PrescenceTrack, &Channel), Or<(Changed<PrescenceTrack>, Added<Channel>)>>,
263) {
264 for (p, c) in q.iter() {
265 c.track(p.payload.clone()).unwrap();
266 }
267}
268
269pub fn presence_untrack(q: Query<&Channel>, mut removed: RemovedComponents<PrescenceTrack>) {
270 for r in removed.read() {
271 if let Ok(c) = q.get(r) {
272 c.untrack().unwrap();
273 }
274 }
275}