Skip to main content

moq_lite/
session.rs

1use std::{future::Future, pin::Pin, sync::Arc};
2
3use crate::{Error, Version};
4
5/// A MoQ transport session, wrapping a WebTransport connection.
6///
7/// Created via:
8/// - [`crate::Client::connect`] for clients.
9/// - [`crate::Server::accept`] for servers.
10#[derive(Clone)]
11pub struct Session {
12	session: Arc<dyn SessionInner>,
13	version: Version,
14	closed: bool,
15}
16
17impl Session {
18	pub(super) fn new<S: web_transport_trait::Session>(session: S, version: Version) -> Self {
19		Self {
20			session: Arc::new(session),
21			version,
22			closed: false,
23		}
24	}
25
26	/// Returns the negotiated protocol version.
27	pub fn version(&self) -> Version {
28		self.version
29	}
30
31	/// Close the underlying transport session.
32	pub fn close(&mut self, err: Error) {
33		if self.closed {
34			return;
35		}
36		self.closed = true;
37		self.session.close(err.to_code(), err.to_string().as_ref());
38	}
39
40	/// Block until the transport session is closed.
41	// TODO Remove the Result the next time we make a breaking change.
42	pub async fn closed(&self) -> Result<(), Error> {
43		self.session.closed().await;
44		Err(Error::Transport)
45	}
46}
47
48impl Drop for Session {
49	fn drop(&mut self) {
50		if !self.closed {
51			self.session.close(Error::Cancel.to_code(), "dropped");
52		}
53	}
54}
55
56// We use a wrapper type that is dyn-compatible to remove the generic bounds from Session.
57trait SessionInner: Send + Sync {
58	fn close(&self, code: u32, reason: &str);
59	fn closed(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
60}
61
62impl<S: web_transport_trait::Session> SessionInner for S {
63	fn close(&self, code: u32, reason: &str) {
64		S::close(self, code, reason);
65	}
66
67	fn closed(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
68		Box::pin(async move {
69			let _ = S::closed(self).await;
70		})
71	}
72}