use std::{collections::HashMap, ops::Deref, sync::Arc};
use super::{ServeError, Track, TrackReader, TrackWriter};
use crate::coding::TrackNamespace;
use crate::watch::{Queue, State};
#[derive(Hash, Eq, PartialEq, Clone, Debug)]
pub struct FullTrackName {
pub namespace: TrackNamespace,
pub name: String,
}
#[derive(Debug)]
pub struct Tracks {
pub namespace: TrackNamespace,
}
impl Tracks {
pub fn new(namespace: TrackNamespace) -> Self {
Self { namespace }
}
pub fn produce(self) -> (TracksWriter, TracksRequest, TracksReader) {
let info = Arc::new(self);
let state = State::default().split();
let queue = Queue::default().split();
let writer = TracksWriter::new(state.0.clone(), info.clone());
let request = TracksRequest::new(state.0, queue.0, info.clone());
let reader = TracksReader::new(state.1, queue.1, info);
(writer, request, reader)
}
}
#[derive(Default)]
pub struct TracksState {
tracks: HashMap<FullTrackName, TrackReader>,
}
pub struct TracksWriter {
state: State<TracksState>,
pub info: Arc<Tracks>,
}
impl TracksWriter {
fn new(state: State<TracksState>, info: Arc<Tracks>) -> Self {
Self { state, info }
}
pub fn create(&mut self, track: &str) -> Option<TrackWriter> {
let (writer, reader) = Track {
namespace: self.namespace.clone(),
name: track.to_owned(),
}
.produce();
let full_name = FullTrackName {
namespace: self.namespace.clone(),
name: track.to_owned(),
};
self.state.lock_mut()?.tracks.insert(full_name, reader);
Some(writer)
}
pub fn remove(&mut self, namespace: &TrackNamespace, track_name: &str) -> Option<TrackReader> {
let full_name = FullTrackName {
namespace: namespace.clone(),
name: track_name.to_owned(),
};
self.state.lock_mut()?.tracks.remove(&full_name)
}
}
impl Deref for TracksWriter {
type Target = Tracks;
fn deref(&self) -> &Self::Target {
&self.info
}
}
pub struct TracksRequest {
#[allow(dead_code)] state: State<TracksState>,
incoming: Option<Queue<TrackWriter>>,
pub info: Arc<Tracks>,
}
impl TracksRequest {
fn new(state: State<TracksState>, incoming: Queue<TrackWriter>, info: Arc<Tracks>) -> Self {
Self {
state,
incoming: Some(incoming),
info,
}
}
pub async fn next(&mut self) -> Option<TrackWriter> {
self.incoming.as_mut()?.pop().await
}
}
impl Deref for TracksRequest {
type Target = Tracks;
fn deref(&self) -> &Self::Target {
&self.info
}
}
impl Drop for TracksRequest {
fn drop(&mut self) {
for track in self.incoming.take().unwrap().close() {
let _ = track.close(ServeError::not_found_ctx(
"tracks request dropped before track handled",
));
}
}
}
#[derive(Clone)]
pub struct TracksReader {
state: State<TracksState>,
queue: Queue<TrackWriter>,
pub info: Arc<Tracks>,
}
impl TracksReader {
fn new(state: State<TracksState>, queue: Queue<TrackWriter>, info: Arc<Tracks>) -> Self {
Self { state, queue, info }
}
pub fn get_track_reader(
&mut self,
namespace: &TrackNamespace,
track_name: &str,
) -> Option<TrackReader> {
let state = self.state.lock();
let full_name = FullTrackName {
namespace: namespace.clone(),
name: track_name.to_owned(),
};
if let Some(track_reader) = state.tracks.get(&full_name) {
return Some(track_reader.clone());
}
None
}
pub fn subscribe(
&mut self,
namespace: TrackNamespace,
track_name: &str,
) -> Option<TrackReader> {
let state = self.state.lock();
let full_name = FullTrackName {
namespace: namespace.clone(),
name: track_name.to_owned(),
};
if let Some(track_reader) = state.tracks.get(&full_name) {
return Some(track_reader.clone());
}
let mut state = state.into_mut()?;
let track_writer_reader = Track {
namespace: namespace.clone(),
name: track_name.to_owned(),
}
.produce();
if self.queue.push(track_writer_reader.0).is_err() {
return None;
}
state
.tracks
.insert(full_name, track_writer_reader.1.clone());
Some(track_writer_reader.1.clone())
}
}
impl Deref for TracksReader {
type Target = Tracks;
fn deref(&self) -> &Self::Target {
&self.info
}
}