2023-09-15 19:06:28 +00:00
|
|
|
use anyhow::Context;
|
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
use moq_transport::{cache::broadcast, session::Request, setup::Role, MoqError};
|
|
|
|
|
|
|
|
use crate::Origin;
|
2023-09-15 19:06:28 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Session {
|
2023-10-12 04:09:32 +00:00
|
|
|
origin: Origin,
|
2023-09-15 19:06:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Session {
|
2023-10-12 04:09:32 +00:00
|
|
|
pub fn new(origin: Origin) -> Self {
|
|
|
|
Self { origin }
|
2023-09-15 19:06:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn run(&mut self, conn: quinn::Connecting) -> anyhow::Result<()> {
|
2023-09-19 05:37:49 +00:00
|
|
|
log::debug!("received QUIC handshake: ip={:?}", conn.remote_address());
|
|
|
|
|
2023-09-15 19:06:28 +00:00
|
|
|
// Wait for the QUIC connection to be established.
|
|
|
|
let conn = conn.await.context("failed to establish QUIC connection")?;
|
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
log::debug!(
|
|
|
|
"established QUIC connection: ip={:?} id={}",
|
|
|
|
conn.remote_address(),
|
|
|
|
conn.stable_id()
|
|
|
|
);
|
|
|
|
let id = conn.stable_id();
|
|
|
|
|
2023-09-15 19:06:28 +00:00
|
|
|
// Wait for the CONNECT request.
|
|
|
|
let request = webtransport_quinn::accept(conn)
|
|
|
|
.await
|
|
|
|
.context("failed to receive WebTransport request")?;
|
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
// Strip any leading and trailing slashes to get the broadcast name.
|
|
|
|
let path = request.url().path().trim_matches('/').to_string();
|
2023-09-15 19:06:28 +00:00
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
log::debug!("received WebTransport CONNECT: id={} path={}", id, path);
|
|
|
|
|
2023-09-15 19:06:28 +00:00
|
|
|
// Accept the CONNECT request.
|
|
|
|
let session = request
|
|
|
|
.ok()
|
|
|
|
.await
|
|
|
|
.context("failed to respond to WebTransport request")?;
|
|
|
|
|
|
|
|
// Perform the MoQ handshake.
|
|
|
|
let request = moq_transport::session::Server::accept(session)
|
|
|
|
.await
|
|
|
|
.context("failed to accept handshake")?;
|
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
log::debug!("received MoQ SETUP: id={} role={:?}", id, request.role());
|
|
|
|
|
2023-09-15 19:06:28 +00:00
|
|
|
let role = request.role();
|
|
|
|
|
|
|
|
match role {
|
2023-09-19 05:37:49 +00:00
|
|
|
Role::Publisher => self.serve_publisher(id, request, &path).await,
|
|
|
|
Role::Subscriber => self.serve_subscriber(id, request, &path).await,
|
2023-10-12 04:09:32 +00:00
|
|
|
Role::Both => {
|
|
|
|
log::warn!("role both not supported: id={}", id);
|
|
|
|
request.reject(300);
|
|
|
|
}
|
2023-09-15 19:06:28 +00:00
|
|
|
};
|
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
log::debug!("closing connection: id={}", id);
|
|
|
|
|
2023-09-15 19:06:28 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
async fn serve_publisher(&mut self, id: usize, request: Request, path: &str) {
|
|
|
|
log::info!("serving publisher: id={}, path={}", id, path);
|
2023-09-15 19:06:28 +00:00
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
let broadcast = match self.origin.create_broadcast(path).await {
|
|
|
|
Ok(broadcast) => broadcast,
|
|
|
|
Err(err) => {
|
|
|
|
log::warn!("error accepting publisher: id={} path={} err={:#?}", id, path, err);
|
|
|
|
return request.reject(err.code());
|
|
|
|
}
|
2023-09-15 19:06:28 +00:00
|
|
|
};
|
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
if let Err(err) = self.run_publisher(request, broadcast).await {
|
|
|
|
log::warn!("error serving publisher: id={} path={} err={:#?}", id, path, err);
|
2023-09-15 19:06:28 +00:00
|
|
|
}
|
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
// TODO can we do this on drop? Otherwise we might miss it.
|
|
|
|
self.origin.remove_broadcast(path).await.ok();
|
2023-09-15 19:06:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn run_publisher(&mut self, request: Request, publisher: broadcast::Publisher) -> anyhow::Result<()> {
|
|
|
|
let session = request.subscriber(publisher).await?;
|
|
|
|
session.run().await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-19 05:37:49 +00:00
|
|
|
async fn serve_subscriber(&mut self, id: usize, request: Request, path: &str) {
|
|
|
|
log::info!("serving subscriber: id={} path={}", id, path);
|
2023-09-15 19:06:28 +00:00
|
|
|
|
2023-10-12 04:09:32 +00:00
|
|
|
let broadcast = self.origin.get_broadcast(path);
|
2023-09-15 19:06:28 +00:00
|
|
|
|
|
|
|
if let Err(err) = self.run_subscriber(request, broadcast).await {
|
2023-10-12 04:09:32 +00:00
|
|
|
log::warn!("error serving subscriber: id={} path={} err={:#?}", id, path, err);
|
2023-09-15 19:06:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn run_subscriber(&mut self, request: Request, broadcast: broadcast::Subscriber) -> anyhow::Result<()> {
|
|
|
|
let session = request.publisher(broadcast).await?;
|
|
|
|
session.run().await?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|