use std::{convert::TryFrom, fmt};
use derive_more::Display;
use failure::Fail;
use medea_client_api_proto::{MemberId, RoomId};
use serde::{
de::{self, Deserializer, Error, Visitor},
Deserialize,
};
use crate::api::control::{
endpoints::webrtc_publish_endpoint::WebRtcPublishId,
refs::{
local_uri::{LocalUriParseError, StatefulLocalUri},
LocalUri, ToEndpoint,
},
};
#[derive(Debug, Fail, Display)]
pub enum SrcParseError {
#[display(fmt = "Provided not src uri {}", _0)]
NotSrcUri(String),
#[display(fmt = "Local URI parse error: {:?}", _0)]
LocalUriParseError(LocalUriParseError),
}
#[derive(Clone, Debug)]
pub struct SrcUri {
pub room_id: RoomId,
pub member_id: MemberId,
pub endpoint_id: WebRtcPublishId,
}
impl TryFrom<String> for SrcUri {
type Error = SrcParseError;
fn try_from(value: String) -> Result<Self, Self::Error> {
let local_uri = StatefulLocalUri::try_from(value)
.map_err(SrcParseError::LocalUriParseError)?;
match local_uri {
StatefulLocalUri::Room(uri) => {
Err(SrcParseError::NotSrcUri(uri.to_string()))
}
StatefulLocalUri::Member(uri) => {
Err(SrcParseError::NotSrcUri(uri.to_string()))
}
StatefulLocalUri::Endpoint(uri) => Ok(uri.into()),
}
}
}
impl From<LocalUri<ToEndpoint>> for SrcUri {
fn from(uri: LocalUri<ToEndpoint>) -> Self {
let (room_id, member_id, endpoint_id) = uri.take_all();
Self {
room_id,
member_id,
endpoint_id: endpoint_id.into(),
}
}
}
impl<'de> Deserialize<'de> for SrcUri {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct SrcUriVisitor;
impl<'de> Visitor<'de> for SrcUriVisitor {
type Value = SrcUri;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(
"Uri in format local://room_id/member_id/endpoint_id",
)
}
fn visit_str<E>(self, value: &str) -> Result<SrcUri, E>
where
E: de::Error,
{
match SrcUri::try_from(value.to_owned()) {
Ok(src_uri) => Ok(src_uri),
Err(e) => Err(Error::custom(e)),
}
}
}
deserializer.deserialize_identifier(SrcUriVisitor)
}
}
impl fmt::Display for SrcUri {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"local://{}/{}/{}",
self.room_id, self.member_id, self.endpoint_id
)
}
}