1use std::{
2 future::Future,
3 pin::Pin,
4 sync::Arc,
5 task::{Context, Poll},
6 time::Duration,
7};
8
9use web_transport_trait::Stats;
10
11use crate::{
12 Error, Version, bandwidth,
13 util::{MaybeBoxedExt, MaybeSendBox},
14};
15
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
23#[non_exhaustive]
24pub struct ConnectionStats {
25 pub rtt: Option<Duration>,
27
28 pub estimated_send_rate: Option<u64>,
30
31 pub estimated_recv_rate: Option<u64>,
35
36 pub bytes_sent: Option<u64>,
38
39 pub bytes_received: Option<u64>,
41
42 pub bytes_lost: Option<u64>,
44
45 pub packets_sent: Option<u64>,
47
48 pub packets_received: Option<u64>,
50
51 pub packets_lost: Option<u64>,
53}
54
55#[derive(Clone)]
66pub struct Session {
67 shared: Arc<SessionShared>,
68 version: Version,
69 send_bandwidth: Option<bandwidth::Consumer>,
70 recv_bandwidth: Option<bandwidth::Consumer>,
71}
72
73impl Session {
74 pub fn version(&self) -> Version {
76 self.version
77 }
78
79 pub fn send_bandwidth(&self) -> Option<bandwidth::Consumer> {
83 self.send_bandwidth.clone()
84 }
85
86 pub fn recv_bandwidth(&self) -> Option<bandwidth::Consumer> {
90 self.recv_bandwidth.clone()
91 }
92
93 pub fn stats(&self) -> ConnectionStats {
98 let mut stats = self.shared.inner.stats();
99 stats.estimated_recv_rate = self.recv_bandwidth.as_ref().and_then(bandwidth::Consumer::peek);
100 stats
101 }
102
103 pub fn abort(&self, err: Error) {
106 self.shared.close(err.to_code(), err.to_string().as_ref());
107 }
108
109 pub async fn closed(&self) -> Error {
111 Error::Transport(self.shared.inner.closed().await)
112 }
113}
114
115pub struct Driver {
128 protocol: MaybeSendBox<'static, Result<(), Error>>,
129 maintenance: Option<MaybeSendBox<'static, ()>>,
134 result: Option<Result<(), Error>>,
137 waiter: Option<kio::Waiter>,
140}
141
142impl Driver {
143 pub fn poll(&mut self, waiter: &kio::Waiter) -> Poll<Result<(), Error>> {
148 if let Some(result) = &self.result {
149 return Poll::Ready(result.clone());
150 }
151
152 if let Some(maintenance) = &mut self.maintenance
153 && waiter.poll_future(maintenance.as_mut()).is_ready()
154 {
155 self.maintenance = None;
156 }
157
158 let result = std::task::ready!(waiter.poll_future(self.protocol.as_mut()));
159 self.result = Some(result.clone());
160 self.maintenance = None;
163 Poll::Ready(result)
164 }
165
166 pub(super) async fn wait_ready(&mut self, poll_ready: impl Fn(&kio::Waiter) -> Poll<()>) {
173 kio::wait(|waiter| {
174 if poll_ready(waiter).is_ready() {
175 return Poll::Ready(());
176 }
177 let _ = self.poll(waiter);
178 Poll::Pending
179 })
180 .await
181 }
182}
183
184impl Future for Driver {
185 type Output = Result<(), Error>;
186
187 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
188 let this = &mut *self;
189 let waiter = kio::Waiter::new(cx.waker().clone());
192 let result = this.poll(&waiter);
193 this.waiter = Some(waiter);
194 result
195 }
196}
197
198struct SessionShared {
202 inner: Box<dyn SessionInner>,
203 closed: std::sync::atomic::AtomicBool,
204}
205
206impl SessionShared {
207 fn close(&self, code: u32, reason: &str) {
208 if !self.closed.swap(true, std::sync::atomic::Ordering::SeqCst) {
209 self.inner.close(code, reason);
210 }
211 }
212}
213
214impl Drop for SessionShared {
215 fn drop(&mut self) {
216 self.close(Error::Cancel.to_code(), "dropped");
217 }
218}
219
220impl Session {
221 pub(super) fn new<S: web_transport_trait::Session>(
222 session: S,
223 version: Version,
224 recv_bandwidth: Option<bandwidth::Consumer>,
225 protocol: MaybeSendBox<'static, Result<(), Error>>,
226 ) -> (Self, Driver) {
227 let (send_bandwidth, maintenance) = if session.stats().estimated_send_rate().is_some() {
229 let producer = bandwidth::Producer::new();
230 let consumer = producer.consume();
231
232 let mut monitor = SendBandwidth::new(session.clone(), producer);
233 let maintenance = async move { kio::wait(|waiter| monitor.poll(waiter)).await }.maybe_boxed();
234
235 (Some(consumer), Some(maintenance))
236 } else {
237 (None, None)
238 };
239
240 let session = Self {
241 shared: Arc::new(SessionShared {
242 inner: Box::new(session),
243 closed: std::sync::atomic::AtomicBool::new(false),
244 }),
245 version,
246 send_bandwidth,
247 recv_bandwidth,
248 };
249 let driver = Driver {
250 protocol,
251 maintenance,
252 result: None,
253 waiter: None,
254 };
255
256 (session, driver)
257 }
258}
259
260struct SendBandwidth<S> {
266 session: S,
267 producer: bandwidth::Producer,
268 closed: MaybeSendBox<'static, ()>,
270 mode: SendBandwidthMode,
271}
272
273enum SendBandwidthMode {
274 Idle,
276 Polling { sleep: MaybeSendBox<'static, ()> },
278}
279
280impl<S: web_transport_trait::Session> SendBandwidth<S> {
281 const POLL_INTERVAL: Duration = Duration::from_millis(100);
282
283 fn new(session: S, producer: bandwidth::Producer) -> Self {
284 let closed = {
285 let session = session.clone();
286 async move {
287 session.closed().await;
288 }
289 }
290 .maybe_boxed();
291
292 Self {
293 session,
294 producer,
295 closed,
296 mode: SendBandwidthMode::Idle,
297 }
298 }
299
300 fn sample(&mut self) -> Result<(), Error> {
303 let bitrate = self.session.stats().estimated_send_rate();
304 self.producer.set(bitrate)?;
305 self.mode = SendBandwidthMode::Polling {
306 sleep: web_async::time::sleep(Self::POLL_INTERVAL).maybe_boxed(),
307 };
308 Ok(())
309 }
310
311 fn poll(&mut self, waiter: &kio::Waiter) -> Poll<()> {
312 if waiter.poll_future(self.closed.as_mut()).is_ready() {
313 return Poll::Ready(());
314 }
315
316 loop {
317 match &mut self.mode {
318 SendBandwidthMode::Idle => {
319 match self.producer.poll_used(waiter) {
320 Poll::Ready(Ok(())) => {}
322 Poll::Ready(Err(_)) => return Poll::Ready(()),
323 Poll::Pending => return Poll::Pending,
324 }
325 if self.sample().is_err() {
326 return Poll::Ready(());
327 }
328 }
329 SendBandwidthMode::Polling { sleep } => {
330 match self.producer.poll_unused(waiter) {
332 Poll::Ready(Ok(())) => {
333 self.mode = SendBandwidthMode::Idle;
334 continue;
335 }
336 Poll::Ready(Err(_)) => return Poll::Ready(()),
337 Poll::Pending => {}
338 }
339
340 if waiter.poll_future(sleep.as_mut()).is_pending() {
341 return Poll::Pending;
342 }
343 if self.sample().is_err() {
344 return Poll::Ready(());
345 }
346 }
348 }
349 }
350 }
351}
352
353trait SessionInner: web_transport_trait::MaybeSend + web_transport_trait::MaybeSync {
357 fn close(&self, code: u32, reason: &str);
358 fn closed(&self) -> MaybeSendBox<'_, String>;
359 fn stats(&self) -> ConnectionStats;
360}
361
362impl<S: web_transport_trait::Session> SessionInner for S {
363 fn close(&self, code: u32, reason: &str) {
364 S::close(self, code, reason);
365 }
366
367 fn closed(&self) -> MaybeSendBox<'_, String> {
368 Box::pin(async move { S::closed(self).await.to_string() })
369 }
370
371 fn stats(&self) -> ConnectionStats {
372 let stats = S::stats(self);
375 ConnectionStats {
376 rtt: stats.rtt(),
377 estimated_send_rate: stats.estimated_send_rate(),
378 bytes_sent: stats.bytes_sent(),
379 bytes_received: stats.bytes_received(),
380 bytes_lost: stats.bytes_lost(),
381 packets_sent: stats.packets_sent(),
382 packets_received: stats.packets_received(),
383 packets_lost: stats.packets_lost(),
384 ..Default::default()
385 }
386 }
387}