1use std::{any::TypeId, collections::VecDeque, marker::PhantomData};
2
3use bevy::{
4 ecs::system::SystemParam,
5 platform::collections::{HashMap, hash_map::Entry},
6 prelude::*,
7};
8use bytes::Bytes;
9use nevy_transport::prelude::*;
10use serde::Serialize;
11
12use crate::{
13 protocol::{ConnectionProtocolEntity, Protocol},
14 varint::VarInt,
15};
16
17pub struct MessageStreamState {
21 stream: Stream,
22 buffer: VecDeque<Bytes>,
25}
26
27impl MessageStreamState {
28 pub fn new(mut connection: Connection, requirements: StreamRequirements) -> Result<Self> {
29 let stream = connection.new_stream(requirements)?;
30
31 Ok(MessageStreamState {
32 stream,
33 buffer: VecDeque::new(),
34 })
35 }
36
37 pub fn flush(&mut self, mut connection: Connection) -> Result<bool> {
39 while let Some(message) = self.buffer.front_mut() {
40 let written = connection.write(&self.stream, message.clone(), true)?;
41 let _ = message.split_to(written);
42
43 if message.is_empty() {
44 self.buffer.pop_front();
45 } else {
46 return Ok(false);
47 }
48 }
49
50 Ok(true)
51 }
52
53 pub fn write<T>(
54 &mut self,
55 mut connection: Connection,
56 message_id: usize,
57 queue: bool,
58 message: &T,
59 ) -> Result<bool>
60 where
61 T: Serialize,
62 {
63 let buffer_empty = self.flush(connection.reborrow())?;
64
65 if !(queue || buffer_empty) {
67 return Ok(false);
68 }
69
70 let message = postcard::to_stdvec(message)?;
71
72 let mut buffer = Vec::with_capacity(message.len() + 16);
73
74 VarInt::from_u64(message_id as u64)
75 .ok_or("Message id was too big for VarInt")?
76 .encode(&mut buffer);
77
78 VarInt::from_u64(message.len() as u64)
79 .ok_or("Message length was too big for VarInt")?
80 .encode(&mut buffer);
81
82 buffer.extend(message);
83
84 self.buffer.push_back(buffer.into());
85
86 self.flush(connection)?;
87
88 Ok(true)
89 }
90
91 pub fn close(&mut self, mut connection: Connection, graceful: bool) -> Result {
92 connection.close_send_stream(&self.stream, graceful)
93 }
94}
95
96#[derive(Default)]
99pub struct MessageSenderState {
100 streams: HashMap<Entity, MessageStreamState>,
101}
102
103#[derive(SystemParam)]
105pub struct MessageSenderParams<'w, 's> {
106 connection_q: Query<'w, 's, (&'static ConnectionOf, &'static ConnectionProtocolEntity)>,
107 endpoint_q: Query<'w, 's, &'static mut Endpoint>,
108 protocol_q: Query<'w, 's, &'static Protocol>,
109}
110
111#[derive(SystemParam)]
122pub struct LocalMessageSender<'w, 's, const RELIABLE: bool = true, const ORDERED: bool = true> {
123 state: Local<'s, MessageSenderState>,
124 params: MessageSenderParams<'w, 's>,
125}
126
127pub type LocalMessageSenderUnrel<'w, 's> = LocalMessageSender<'w, 's, true, false>;
128pub type LocalMessageSenderUnord<'w, 's> = LocalMessageSender<'w, 's, false, true>;
129pub type LocalMessageSenderUnordUnrel<'w, 's> = LocalMessageSender<'w, 's, false, false>;
130
131#[derive(SystemParam)]
142pub struct SharedMessageSender<'w, 's, S>
143where
144 S: Send + Sync + 'static,
145{
146 state: ResMut<'w, SharedMessageSenderState<S>>,
147 params: MessageSenderParams<'w, 's>,
148}
149
150#[derive(Resource)]
152struct SharedMessageSenderState<S> {
153 _p: PhantomData<S>,
154 requirements: StreamRequirements,
155 state: MessageSenderState,
156}
157
158pub trait MessageSender<'w, 's> {
159 fn context(
160 &mut self,
161 ) -> (
162 &mut MessageSenderState,
163 &mut MessageSenderParams<'w, 's>,
164 StreamRequirements,
165 );
166
167 fn flush(&mut self) -> Result {
169 let (state, params, _) = self.context();
170
171 let mut remove_streams = Vec::new();
172
173 for (&connection_entity, stream_state) in &mut state.streams {
174 let Ok((&ConnectionOf(endpoint_entity), _)) =
175 params.connection_q.get(connection_entity)
176 else {
177 remove_streams.push(connection_entity);
179 continue;
180 };
181
182 let mut endpoint = params.endpoint_q.get_mut(endpoint_entity)?;
183 let connection = endpoint.get_connection(connection_entity)?;
184
185 stream_state.flush(connection)?;
186 }
187
188 for connection_entity in remove_streams {
189 state.streams.remove(&connection_entity);
190 }
191
192 Ok(())
193 }
194
195 fn write<T>(&mut self, connection_entity: Entity, queue: bool, message: &T) -> Result<bool>
200 where
201 T: Serialize + 'static,
202 {
203 let (state, params, requirements) = self.context();
204
205 let (&ConnectionOf(endpoint_entity), protocol_entity) = params
206 .connection_q
207 .get(connection_entity)
208 .ok()
209 .ok_or("Entity is not a connection with a messaging protocol.")?;
210
211 let protocol = params.protocol_q.get(**protocol_entity)?;
212 let &message_id = protocol.lookup.get(&TypeId::of::<T>()).ok_or_else(|| {
213 format!(
214 "This connection's protocol doesn't have an id assigned for message `{}`",
215 std::any::type_name::<T>()
216 )
217 })?;
218
219 let mut endpoint = params.endpoint_q.get_mut(endpoint_entity)?;
220 let mut connection = endpoint.get_connection(connection_entity)?;
221
222 let stream_state = match state.streams.entry(connection_entity) {
223 Entry::Occupied(entry) => entry.into_mut(),
224 Entry::Vacant(entry) => entry.insert(MessageStreamState::new(
225 connection.reborrow(),
226 requirements,
227 )?),
228 };
229
230 stream_state.write(connection, message_id, queue, message)
231 }
232
233 fn queue_size(&mut self, connection_entity: Entity) -> usize {
235 let (state, _, _) = self.context();
236 state
237 .streams
238 .get(&connection_entity)
239 .map(|state| state.buffer.len())
240 .unwrap_or(0)
241 }
242
243 fn close_unused_streams(&mut self) -> Result {
245 let (state, params, _) = self.context();
246
247 let mut remove_streams = Vec::new();
248
249 for (&connection_entity, state) in &mut state.streams {
250 if !state.buffer.is_empty() {
251 continue;
252 }
253
254 let Ok((&ConnectionOf(endpoint_entity), _)) =
255 params.connection_q.get(connection_entity)
256 else {
257 remove_streams.push(connection_entity);
258 continue;
259 };
260
261 let mut endpoint = params.endpoint_q.get_mut(endpoint_entity)?;
262 let connection = endpoint.get_connection(connection_entity)?;
263
264 state.close(connection, true)?;
265
266 remove_streams.push(connection_entity);
267 }
268
269 for connection_entity in remove_streams {
270 state.streams.remove(&connection_entity);
271 }
272
273 Ok(())
274 }
275
276 fn close_all_streams(&mut self, graceful: bool) -> Result {
278 let (state, params, _) = self.context();
279
280 for (connection_entity, mut state) in std::mem::take(&mut state.streams) {
281 let Ok((&ConnectionOf(endpoint_entity), _)) =
282 params.connection_q.get(connection_entity)
283 else {
284 continue;
285 };
286
287 let mut endpoint = params.endpoint_q.get_mut(endpoint_entity)?;
288 let connection = endpoint.get_connection(connection_entity)?;
289
290 state.close(connection, graceful)?;
291 }
292
293 Ok(())
294 }
295}
296
297impl<'w, 's, const RELIABLE: bool, const ORDERED: bool> MessageSender<'w, 's>
298 for LocalMessageSender<'w, 's, RELIABLE, ORDERED>
299{
300 fn context(
301 &mut self,
302 ) -> (
303 &mut MessageSenderState,
304 &mut MessageSenderParams<'w, 's>,
305 StreamRequirements,
306 ) {
307 let requirements = StreamRequirements {
308 reliable: RELIABLE,
309 ordered: ORDERED,
310 bidirectional: false,
311 };
312
313 (&mut *self.state, &mut self.params, requirements)
314 }
315}
316
317impl<'w, 's, S> MessageSender<'w, 's> for SharedMessageSender<'w, 's, S>
318where
319 S: Send + Sync + 'static,
320{
321 fn context(
322 &mut self,
323 ) -> (
324 &mut MessageSenderState,
325 &mut MessageSenderParams<'w, 's>,
326 StreamRequirements,
327 ) {
328 let requirements = self.state.requirements;
329
330 (&mut self.state.state, &mut self.params, requirements)
331 }
332}
333
334pub trait AddSharedMessageSender {
335 fn add_shared_message_sender<S>(&mut self, requirements: StreamRequirements)
336 where
337 S: Send + Sync + 'static;
338}
339
340impl AddSharedMessageSender for App {
341 fn add_shared_message_sender<S>(&mut self, requirements: StreamRequirements)
343 where
344 S: Send + Sync + 'static,
345 {
346 self.insert_resource(SharedMessageSenderState::<S> {
347 _p: PhantomData,
348 requirements: requirements.with_ordered(true),
349 state: MessageSenderState::default(),
350 });
351
352 self.add_systems(
353 DEFAULT_TRANSPORT_SCHEDULE,
354 flush_shared_message_sender::<S>.before(TransportUpdateSystems),
355 );
356 }
357}
358
359fn flush_shared_message_sender<S>(mut sender: SharedMessageSender<'_, '_, S>) -> Result
360where
361 S: Send + Sync + 'static,
362{
363 sender.flush()
364}