1use std::{
2 ops::Deref,
3 pin::Pin,
4 sync::{
5 Arc,
6 atomic::{AtomicBool, Ordering},
7 },
8};
9
10use bytes::Bytes;
11use futures_util::{StreamExt, stream::FuturesUnordered};
12use just_webrtc::{
13 DataChannelExt, PeerConnectionBuilder, PeerConnectionExt, types::PeerConnectionState,
14};
15use pawkit_holy_array::HolyArray;
16use pawkit_net_signaling::{
17 ChannelConfiguration,
18 client::{ClientConnectionCandidate, HostPeerSignalingClient},
19 model::HostId,
20};
21use tokio::sync::{
22 RwLock,
23 mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel},
24};
25
26use crate::{Connection, PacketFuture, RUNTIME, receive_packet};
27
28pub struct NetHostPeer {
29 connected_clients: RwLock<HolyArray<Arc<Connection>>>,
30 ev_dispatcher: UnboundedSender<NetHostPeerEvent>,
31 running: AtomicBool,
32 game_id: u32,
33 host_id: RwLock<HostId>,
34 request_proxy: bool,
35 channel_configurations: Box<[ChannelConfiguration]>,
36}
37
38#[derive(Debug)]
39pub enum NetHostPeerEvent {
40 PeerConnected {
41 peer_id: usize,
42 },
43 PeerDisconnected {
44 peer_id: usize,
45 },
46 PacketReceived {
47 peer_id: usize,
48 channel: usize,
49 data: Vec<u8>,
50 },
51 HostIdUpdated,
52}
53
54impl NetHostPeer {
55 pub fn create(
56 server_url: &str,
57 game_id: u32,
58 request_proxy: bool,
59 channel_configurations: &[ChannelConfiguration],
60 ) -> (Arc<Self>, UnboundedReceiver<NetHostPeerEvent>) {
61 let (ev_dispatcher, ev_queue) = unbounded_channel::<NetHostPeerEvent>();
62
63 let value = Arc::new(Self {
64 connected_clients: RwLock::new(HolyArray::new()),
65 ev_dispatcher,
66 running: AtomicBool::new(true),
67 game_id,
68 host_id: RwLock::new(HostId {
69 server_url: server_url.into(),
70 lobby_id: 0,
71 shard_id: 0,
72 }),
73 request_proxy,
74 channel_configurations: channel_configurations.into(),
75 });
76
77 value.clone().spawn_worker();
78
79 return (value, ev_queue);
80 }
81
82 pub fn get_host_id(&self) -> HostId {
83 return self.host_id.blocking_read().clone();
84 }
85
86 pub fn send_packet(&self, client_id: usize, channel: usize, data: &[u8]) {
87 let clients = self.connected_clients.blocking_read();
88
89 let Some(client) = clients.get(client_id) else {
90 return;
91 };
92
93 let _ = RUNTIME.block_on(client.channels[channel].send(&Bytes::copy_from_slice(data)));
94 }
95
96 async fn handle_candidate(
97 &self,
98 signaling: &mut HostPeerSignalingClient,
99 candidate: ClientConnectionCandidate,
100 channels: usize,
101 ) -> Option<usize> {
102 let Ok(connection) = PeerConnectionBuilder::new()
103 .with_remote_offer(Some(candidate.offer.clone()))
104 .unwrap()
105 .build()
106 .await
107 else {
108 signaling.reject_candidate(candidate.client_id).await;
109 return None;
110 };
111
112 let _ = connection
113 .add_ice_candidates(candidate.candidates.clone())
114 .await;
115
116 let Some(offer) = connection.get_local_description().await else {
117 signaling.reject_candidate(candidate.client_id).await;
118 return None;
119 };
120
121 let Ok(candidates) = connection.collect_ice_candidates().await else {
122 signaling.reject_candidate(candidate.client_id).await;
123 return None;
124 };
125
126 signaling
127 .accept_candidate(candidate.client_id, offer, candidates)
128 .await;
129
130 let mut connected_clients = self.connected_clients.write().await;
131
132 let PeerConnectionState::Connected = connection.state_change().await else {
133 return None;
134 };
135
136 let connection = Connection::from(connection, channels).await.ok()?;
137
138 let peer_id = connected_clients.acquire(Arc::new(connection));
139
140 let _ = self
141 .ev_dispatcher
142 .send(NetHostPeerEvent::PeerConnected { peer_id });
143
144 return Some(peer_id);
145 }
146
147 async fn refresh_signaling(&self, signaling: &mut HostPeerSignalingClient) {
148 if !signaling.is_open() {
149 {
150 let Some(new_signaling) = HostPeerSignalingClient::new(
151 &self.host_id.read().await.server_url,
152 self.game_id,
153 self.request_proxy,
154 )
155 .await
156 else {
157 return;
158 };
159 *signaling = new_signaling;
160 }
161 {
162 *self.host_id.write().await = signaling.host_id.clone();
163 }
164 let _ = self.ev_dispatcher.send(NetHostPeerEvent::HostIdUpdated);
165 }
166 }
167
168 async fn packet_task(
169 peer: Arc<Connection>,
170 peer_id: usize,
171 channel: usize,
172 ) -> (Option<(usize, Vec<u8>)>, usize) {
173 tokio::select! {
174 Some(packet) = receive_packet(&peer.channels[channel]) => {
175 return (Some((channel, packet)), peer_id)
176 }
177
178 PeerConnectionState::Disconnected = peer.raw_connection.state_change() => {
179 return (None, peer_id)
180 }
181 }
182 }
183
184 async fn add_packet_task(
185 &self,
186 tasks: &FuturesUnordered<Pin<Box<PacketFuture>>>,
187 peer_id: usize,
188 channel: usize,
189 ) {
190 let clients = self.connected_clients.read().await;
191 let Some(peer) = clients.get(peer_id) else {
192 tasks.push(Box::pin(async move { (None, peer_id) }));
193 return;
194 };
195
196 tasks.push(Box::pin(Self::packet_task(peer.clone(), peer_id, channel)));
197 }
198
199 async fn worker_loop(&self) {
200 let mut signaling = {
201 loop {
202 let Some(host) = HostPeerSignalingClient::new(
203 &self.host_id.read().await.server_url,
204 self.game_id,
205 self.request_proxy,
206 )
207 .await
208 else {
209 continue;
210 };
211
212 break host;
213 }
214 };
215 {
216 *self.host_id.write().await = signaling.host_id.clone();
217 }
218 let _ = self.ev_dispatcher.send(NetHostPeerEvent::HostIdUpdated);
219
220 let mut tasks = FuturesUnordered::<Pin<Box<PacketFuture>>>::new();
221
222 while self.running.load(Ordering::Relaxed) {
223 self.refresh_signaling(&mut signaling).await;
224
225 tokio::select! {
226 Some(candidate) = signaling.next_candidate() => {
227 let Some(peer_id) = self.handle_candidate(&mut signaling, candidate, self.channel_configurations.len()).await else {
228 continue;
229 };
230
231 for channel in 0..self.channel_configurations.len() {
232 self.add_packet_task(&tasks, peer_id, channel).await;
233 }
234 }
235
236 Some((packet, peer_id)) = tasks.next() => {
237 let Some((channel, data)) = packet else {
238 let mut connected_clients = self.connected_clients.write().await;
239 connected_clients.release(peer_id);
240
241 let _ = self
242 .ev_dispatcher
243 .send(NetHostPeerEvent::PeerDisconnected { peer_id });
244
245 continue;
246 };
247
248 let _ = self
249 .ev_dispatcher
250 .send(NetHostPeerEvent::PacketReceived { peer_id, channel, data });
251
252 self.add_packet_task(&tasks, peer_id, channel).await;
253 }
254
255 else => {
256 continue;
257 }
258 }
259 }
260 }
261
262 pub fn shutdown(&self) {
263 self.running.store(false, Ordering::Relaxed);
264 }
265
266 fn spawn_worker(self: Arc<Self>) {
267 tokio::spawn(async move {
268 self.worker_loop().await;
269 });
270 }
271}
272
273pub struct SimpleNetHostPeer {
274 raw_peer: Arc<NetHostPeer>,
275 ev_queue: UnboundedReceiver<NetHostPeerEvent>,
276}
277
278impl SimpleNetHostPeer {
279 pub fn create(
280 server_url: &str,
281 game_id: u32,
282 request_proxy: bool,
283 channel_configurations: &[ChannelConfiguration],
284 ) -> Self {
285 let (raw_peer, ev_queue) =
286 NetHostPeer::create(server_url, game_id, request_proxy, channel_configurations);
287
288 return Self { raw_peer, ev_queue };
289 }
290
291 pub fn next_event(&mut self) -> Option<NetHostPeerEvent> {
292 return self.ev_queue.try_recv().ok();
293 }
294}
295
296impl Drop for SimpleNetHostPeer {
297 fn drop(&mut self) {
298 self.shutdown();
299 }
300}
301
302impl Deref for SimpleNetHostPeer {
303 type Target = Arc<NetHostPeer>;
304
305 fn deref(&self) -> &Self::Target {
306 return &self.raw_peer;
307 }
308}