medea_control_api_proto/control/endpoint/
web_rtc_play.rsuse std::str::FromStr;
use derive_more::{AsRef, Display, Error, From, Into};
use ref_cast::RefCast;
#[cfg(feature = "serde")]
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use url::Url;
use crate::control::{
endpoint::{self, web_rtc_publish},
member, room,
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct WebRtcPlay {
pub id: Id,
pub spec: Spec,
}
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Spec {
pub src: LocalSrcUri,
#[cfg_attr(feature = "serde", serde(default))]
pub force_relay: bool,
}
#[derive(
AsRef,
Clone,
Debug,
Display,
Eq,
From,
Hash,
Into,
Ord,
PartialEq,
PartialOrd,
RefCast,
)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
#[from(Box<str>, &str, String)]
#[into(Box<str>, String)]
#[repr(transparent)]
pub struct Id(Box<str>);
impl AsRef<endpoint::Id> for Id {
fn as_ref(&self) -> &endpoint::Id {
endpoint::Id::ref_cast(&self.0)
}
}
#[derive(Clone, Debug, Display, Eq, PartialEq)]
#[display("local://{room_id}/{member_id}/{endpoint_id}")]
pub struct LocalSrcUri {
pub room_id: room::Id,
pub member_id: member::Id,
pub endpoint_id: web_rtc_publish::Id,
}
impl FromStr for LocalSrcUri {
type Err = LocalSrcUriParseError;
fn from_str(val: &str) -> Result<Self, Self::Err> {
if val.is_empty() {
return Err(LocalSrcUriParseError::Empty);
}
let url = Url::parse(val)
.map_err(|e| LocalSrcUriParseError::UrlParseErr(val.into(), e))?;
if url.scheme() != "local" {
return Err(LocalSrcUriParseError::NotLocal(val.into()));
}
let room_id = url
.host_str()
.filter(|h| !h.is_empty())
.ok_or_else(|| LocalSrcUriParseError::MissingPaths(val.into()))?
.into();
let mut path = url
.path_segments()
.ok_or_else(|| LocalSrcUriParseError::MissingPaths(val.into()))?;
let member_id = path
.next()
.filter(|id| !id.is_empty())
.ok_or_else(|| LocalSrcUriParseError::MissingPaths(val.into()))?
.into();
let endpoint_id = path
.next()
.filter(|id| !id.is_empty())
.ok_or_else(|| LocalSrcUriParseError::MissingPaths(val.into()))?
.into();
if path.next().is_some() {
return Err(LocalSrcUriParseError::TooManyPaths(val.into()));
}
Ok(Self {
room_id,
member_id,
endpoint_id,
})
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for LocalSrcUri {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
String::deserialize(deserializer)?
.parse::<Self>()
.map_err(D::Error::custom)
}
}
#[cfg(feature = "serde")]
impl Serialize for LocalSrcUri {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
#[derive(Debug, Display, Error)]
pub enum LocalSrcUriParseError {
#[display("Provided URI protocol is not `local://`: {_0}")]
NotLocal(#[error(not(source))] Box<str>),
#[display("Too many paths in URI: {_0}")]
TooManyPaths(#[error(not(source))] Box<str>),
#[display("Missing paths in URI: {_0}")]
MissingPaths(#[error(not(source))] Box<str>),
#[display("Cannot parse provided URI `{_0}`: {_1}")]
UrlParseErr(Box<str>, #[error(source)] url::ParseError),
#[display("Provided URI cannot be empty")]
Empty,
}