1use std::{
2 ops::Deref,
3 sync::{
4 Arc,
5 atomic::{AtomicBool, Ordering},
6 },
7};
8
9use bytes::Bytes;
10use just_webrtc::{
11 DataChannelExt, PeerConnectionBuilder, PeerConnectionExt,
12 types::{DataChannelOptions, PeerConnectionState},
13};
14use pawkit_net_signaling::{
15 ChannelConfiguration, Reliability, client::ClientPeerSignalingClient, model::HostId,
16};
17use tokio::sync::{
18 RwLock,
19 mpsc::{UnboundedReceiver, UnboundedSender, unbounded_channel},
20};
21
22use crate::{Connection, RUNTIME, receive_packets};
23
24pub struct NetClientPeer {
25 connection: RwLock<Option<Connection>>,
26 ev_dispatcher: UnboundedSender<NetClientPeerEvent>,
27 running: AtomicBool,
28 host_id: HostId,
29 game_id: u32,
30 channel_configurations: Box<[ChannelConfiguration]>,
31}
32
33#[derive(Debug)]
34pub enum NetClientPeerEvent {
35 Connected,
36 Disconnected,
37 ConnectionFailed,
38 PacketReceived { channel: usize, data: Vec<u8> },
39}
40
41impl NetClientPeer {
42 pub fn create(
43 game_id: u32,
44 host_id: HostId,
45 channel_configurations: &[ChannelConfiguration],
46 ) -> (Arc<Self>, UnboundedReceiver<NetClientPeerEvent>) {
47 let (ev_dispatcher, ev_queue) = unbounded_channel::<NetClientPeerEvent>();
48
49 let peer = Arc::new(Self {
50 connection: RwLock::new(None),
51 ev_dispatcher,
52 running: AtomicBool::new(true),
53 host_id,
54 game_id,
55 channel_configurations: channel_configurations.into(),
56 });
57
58 peer.clone().spawn_worker();
59
60 return (peer, ev_queue);
61 }
62
63 pub fn send_packet(&self, channel: usize, data: &[u8]) {
64 let conn = self.connection.blocking_read();
65
66 if let Some(conn) = &*conn {
67 let _ = RUNTIME.block_on(conn.channels[channel].send(&Bytes::copy_from_slice(data)));
68 }
69 }
70
71 fn channel_config_to_option(config: &ChannelConfiguration) -> DataChannelOptions {
72 let max_retransmits = if let Reliability::Retry(n) = config.reliability {
73 Some(n.get())
74 } else if let Reliability::Unreliable = config.reliability {
75 Some(0)
76 } else {
77 None
78 };
79
80 let max_packet_life_time = if let Reliability::ExpireAfter(deadline) = config.reliability {
81 Some(deadline.get())
82 } else {
83 None
84 };
85
86 return DataChannelOptions {
87 ordered: Some(config.ordered),
88 max_retransmits,
89 max_packet_life_time,
90
91 ..Default::default()
92 };
93 }
94
95 async fn connect_to_host(&self) -> Option<Connection> {
96 let mut signaling =
97 ClientPeerSignalingClient::new(&self.host_id.server_url, self.game_id).await?;
98
99 let channel_options = self
100 .channel_configurations
101 .iter()
102 .map(|it| ("pawkit_".to_string(), Self::channel_config_to_option(it)))
103 .collect::<Vec<_>>();
104
105 let channels = channel_options.len();
106
107 let connection = PeerConnectionBuilder::new()
108 .with_channel_options(channel_options)
109 .unwrap()
110 .build()
111 .await
112 .ok()?;
113
114 let offer = connection.get_local_description().await?;
115 let candidates = connection.collect_ice_candidates().await.ok()?;
116
117 let candidate = signaling
118 .offer_connection(self.host_id.clone(), offer, candidates)
119 .await?;
120
121 connection
122 .set_remote_description(candidate.offer)
123 .await
124 .ok()?;
125 let _ = connection.add_ice_candidates(candidate.candidates).await;
126
127 if let PeerConnectionState::Connected = connection.state_change().await {
128 return Connection::from(connection, channels).await.ok();
129 }
130
131 return None;
132 }
133
134 async fn worker_loop(self: Arc<Self>) {
135 let Some(conn) = self.connect_to_host().await else {
136 let _ = self
137 .ev_dispatcher
138 .send(NetClientPeerEvent::ConnectionFailed);
139 return;
140 };
141
142 {
143 let mut lock = self.connection.write().await;
144 *lock = Some(conn);
145 }
146
147 let _ = self.ev_dispatcher.send(NetClientPeerEvent::Connected);
148
149 while self.running.load(Ordering::Relaxed) {
150 let connection = self.connection.read().await;
151 let Some(connection) = &*connection else {
152 break;
153 };
154
155 tokio::select! {
156 Some((channel, data)) = receive_packets(&connection.channels) => {
157 let _ = self
158 .ev_dispatcher
159 .send(NetClientPeerEvent::PacketReceived { channel, data });
160 }
161
162 PeerConnectionState::Disconnected = connection.raw_connection.state_change() => {
163 break;
164 }
165
166 else => break
167 }
168 }
169
170 let _ = self.ev_dispatcher.send(NetClientPeerEvent::Disconnected);
171
172 self.running.store(false, Ordering::Relaxed);
173 }
174
175 pub fn disconnect(&self) {
176 self.running.store(false, Ordering::Relaxed);
177 }
178
179 fn spawn_worker(self: Arc<Self>) {
180 tokio::spawn(async move {
181 self.worker_loop().await;
182 });
183 }
184}
185
186pub struct SimpleNetClientPeer {
187 raw_peer: Arc<NetClientPeer>,
188 ev_queue: UnboundedReceiver<NetClientPeerEvent>,
189}
190
191impl SimpleNetClientPeer {
192 pub fn create(
193 game_id: u32,
194 host_id: HostId,
195 channel_configurations: &[ChannelConfiguration],
196 ) -> Self {
197 let (raw_peer, ev_queue) = NetClientPeer::create(game_id, host_id, channel_configurations);
198 Self { raw_peer, ev_queue }
199 }
200
201 pub fn next_event(&mut self) -> Option<NetClientPeerEvent> {
202 return self.ev_queue.try_recv().ok();
203 }
204}
205
206impl Drop for SimpleNetClientPeer {
207 fn drop(&mut self) {
208 self.disconnect();
209 }
210}
211
212impl Deref for SimpleNetClientPeer {
213 type Target = Arc<NetClientPeer>;
214
215 fn deref(&self) -> &Self::Target {
216 &self.raw_peer
217 }
218}