use webtransport_quinn::{RecvStream, SendStream, Session};
use std::{
collections::HashMap,
sync::{Arc, Mutex},
};
use crate::{
message,
message::Message,
model::{broadcast, broker, segment, track},
Error, VarInt,
};
use super::Control;
#[derive(Debug)]
struct Announces {
publisher: broker::Publisher,
subscriber: broker::Subscriber,
}
impl Default for Announces {
fn default() -> Self {
let (publisher, subscriber) = broker::new();
Self { publisher, subscriber }
}
}
#[derive(Default, Debug)]
struct Subscribes {
tracks: HashMap<VarInt, track::Publisher>,
next: u32,
}
#[derive(Clone, Debug)]
pub struct Subscriber {
webtransport: Session,
announces: Arc<Mutex<Announces>>,
subscribes: Arc<Mutex<Subscribes>>,
control: Control,
}
impl Subscriber {
pub(crate) fn new(webtransport: Session, control: (SendStream, RecvStream)) -> Self {
let (send, recv) = control;
let control = Control::new(send);
let this = Self {
webtransport,
announces: Default::default(),
subscribes: Default::default(),
control,
};
tokio::spawn(this.clone().run(recv));
this
}
pub fn announced(&self) -> broker::Subscriber {
self.announces.lock().unwrap().subscriber.clone()
}
pub async fn subscribe(&self, broadcast: &str, track: track::Publisher) -> Result<(), Error> {
let name = track.name.clone();
let id = {
let mut subscribes = self.subscribes.lock().unwrap();
let id = VarInt::from_u32(subscribes.next);
subscribes.next += 1;
subscribes.tracks.insert(id, track);
id
};
let msg = message::Subscribe {
id,
namespace: broadcast.to_string(),
name,
};
self.control.send(msg).await?;
Ok(())
}
pub fn close(self, code: u32, reason: &str) {
self.webtransport.close(code, reason.as_bytes())
}
async fn run(self, control: RecvStream) -> Result<(), Error> {
let inbound = self.clone().run_inbound(control);
let streams = self.clone().run_streams();
tokio::select! {
res = inbound => res,
res = streams => res,
}
}
async fn run_inbound(mut self, mut control: RecvStream) -> Result<(), Error> {
loop {
let msg = Message::decode(&mut control).await.map_err(|_e| Error::Unknown)?;
log::info!("message received: {:?}", msg);
if let Err(err) = self.recv_message(&msg).await {
log::warn!("message error: {:?} {:?}", err, msg);
}
}
}
async fn recv_message(&mut self, msg: &Message) -> Result<(), Error> {
match msg {
Message::Announce(msg) => self.recv_announce(msg).await,
Message::AnnounceReset(msg) => self.recv_announce_reset(msg).await,
Message::SubscribeOk(msg) => self.recv_subscribe_ok(msg).await,
Message::SubscribeStop(msg) => self.recv_subscribe_stop(msg).await,
Message::GoAway(_msg) => unimplemented!("GOAWAY"),
_ => Err(Error::Role(msg.id())),
}
}
async fn recv_announce(&mut self, msg: &message::Announce) -> Result<(), Error> {
let name = msg.namespace.clone();
let (_, mut unknown) = self.announces.lock().unwrap().publisher.create_broadcast(&name)?;
let mut this = self.clone();
tokio::spawn(async move {
log::info!("serving broadcast: name={}", name);
if let Err(err) = this.serve_broadcast(&mut unknown).await {
log::warn!("serving broadcast error: name={} err={:?}", name, err);
}
});
let msg = message::AnnounceOk {
namespace: msg.namespace.clone(),
};
self.control.send(msg).await?;
Ok(())
}
async fn serve_broadcast(&mut self, unknown: &mut broadcast::Unknown) -> Result<(), Error> {
while let Some(track) = unknown.next_track().await? {
self.subscribe(&unknown.name, track).await?;
}
Ok(())
}
async fn recv_announce_reset(&mut self, msg: &message::AnnounceReset) -> Result<(), Error> {
self.announces
.lock()
.unwrap()
.publisher
.remove_broadcast(&msg.namespace)
}
async fn recv_subscribe_ok(&mut self, _msg: &message::SubscribeOk) -> Result<(), Error> {
Ok(())
}
async fn recv_subscribe_stop(&mut self, msg: &message::SubscribeStop) -> Result<(), Error> {
let err = Error::Stop(msg.code);
{
let mut subscribes = self.subscribes.lock().unwrap();
let subscribe = subscribes.tracks.remove(&msg.id).ok_or(Error::NotFound)?;
subscribe.close(err)?;
}
let msg = message::SubscribeReset {
id: msg.id,
code: msg.code,
reason: err.reason().to_string(),
};
self.control.send(msg).await?;
Ok(())
}
async fn run_streams(self) -> Result<(), Error> {
loop {
let stream = self.webtransport.accept_uni().await.map_err(|_| Error::Unknown)?;
let this = self.clone();
tokio::spawn(async move {
if let Err(err) = this.run_stream(stream).await {
log::warn!("failed to receive stream: err={:?}", err);
}
});
}
}
async fn run_stream(self, mut stream: RecvStream) -> Result<(), Error> {
let object = message::Object::decode(&mut stream).await.map_err(|_| Error::Read)?;
log::debug!("received object: {:?}", object);
let mut publisher = {
let mut subscribes = self.subscribes.lock().unwrap();
let track = subscribes.tracks.get_mut(&object.track).ok_or(Error::NotFound)?;
track.create_segment(segment::Info {
sequence: object.sequence,
priority: object.priority,
expires: object.expires,
})?
};
while let Some(data) = stream.read_chunk(usize::MAX, true).await.map_err(|_| Error::Read)? {
publisher.write_chunk(data.bytes)?;
}
Ok(())
}
}