pub mod callback;
pub mod endpoints;
pub mod error_codes;
pub mod grpc;
pub mod member;
pub mod pipeline;
pub mod refs;
pub mod room;
use std::{convert::TryFrom as _, fs::File, io::Read as _, path::Path};
use actix::Addr;
use derive_more::Display;
use failure::{Error, Fail};
use medea_client_api_proto::{MemberId, RoomId};
use serde::Deserialize;
use crate::{
api::control::callback::url::CallbackUrlParseError,
log::prelude::*,
signalling::room_service::{
RoomService, RoomServiceError, StartStaticRooms,
},
};
use self::{pipeline::Pipeline, refs::src_uri::SrcParseError};
#[doc(inline)]
pub use self::{
endpoints::{
webrtc_play_endpoint::WebRtcPlayId,
webrtc_publish_endpoint::WebRtcPublishId, EndpointSpec,
Id as EndpointId,
},
member::MemberSpec,
room::{RoomElement, RoomSpec},
};
#[derive(Debug, Fail, Display)]
pub enum TryFromProtobufError {
#[display(fmt = "Src uri parse error: {:?}", _0)]
SrcUriError(SrcParseError),
#[display(
fmt = "Room element [id = {}] doesn't have Member element. Currently \
this is unimplemented.",
_0
)]
NotMemberElementInRoomElement(String),
#[display(fmt = "Expected element of type [{}]. Id [{}]", _0, _1)]
ExpectedOtherElement(String, String),
#[display(fmt = "Element is None, expected Some. Id [{}]", _0)]
EmptyElement(String),
#[display(fmt = "Endpoint is unimplemented. Id [{}]", _0)]
UnimplementedEndpoint(String),
#[display(fmt = "Error while parsing callback URL. {:?}", _0)]
CallbackUrlParseErr(CallbackUrlParseError),
#[display(
fmt = "Element [id = {}] contains negative duration field `{}`",
_0,
_1
)]
NegativeDuration(String, &'static str),
}
impl From<SrcParseError> for TryFromProtobufError {
fn from(from: SrcParseError) -> Self {
Self::SrcUriError(from)
}
}
impl From<CallbackUrlParseError> for TryFromProtobufError {
fn from(from: CallbackUrlParseError) -> Self {
Self::CallbackUrlParseErr(from)
}
}
#[derive(Clone, Deserialize, Debug)]
#[serde(tag = "kind")]
pub enum RootElement {
Room {
id: RoomId,
spec: Pipeline<MemberId, RoomElement>,
},
}
#[allow(clippy::pub_enum_variant_names)]
#[derive(Clone, Debug, Display, Fail)]
pub enum TryFromElementError {
#[display(fmt = "Element is not Room")]
NotRoom,
#[display(fmt = "Element is not Member")]
NotMember,
}
#[allow(clippy::pub_enum_variant_names)]
#[derive(Debug, Display, Fail)]
pub enum LoadStaticControlSpecsError {
#[display(fmt = "Error while reading static control API specs dir.")]
SpecDirReadError(std::io::Error),
#[display(fmt = "I/O error while reading specs. {:?}", _0)]
IoError(std::io::Error),
#[display(
fmt = "Try from element error while loading static specs. {:?}",
_0
)]
TryFromElementError(TryFromElementError),
#[display(fmt = "Error while deserialization static spec. {:?}", _0)]
YamlDeserializationError(serde_yaml::Error),
}
impl From<std::io::Error> for LoadStaticControlSpecsError {
fn from(err: std::io::Error) -> Self {
Self::IoError(err)
}
}
impl From<TryFromElementError> for LoadStaticControlSpecsError {
fn from(err: TryFromElementError) -> Self {
Self::TryFromElementError(err)
}
}
impl From<serde_yaml::Error> for LoadStaticControlSpecsError {
fn from(err: serde_yaml::Error) -> Self {
Self::YamlDeserializationError(err)
}
}
pub fn load_from_yaml_file<P: AsRef<Path>>(
path: P,
) -> Result<RoomSpec, LoadStaticControlSpecsError> {
let mut file = File::open(path)?;
let mut buf = String::new();
file.read_to_string(&mut buf)?;
let parsed: RootElement = serde_yaml::from_str(&buf)?;
let room = RoomSpec::try_from(&parsed)?;
Ok(room)
}
pub fn load_static_specs_from_dir<P: AsRef<Path>>(
path: P,
) -> Result<Vec<RoomSpec>, LoadStaticControlSpecsError> {
let mut specs = Vec::new();
for entry in std::fs::read_dir(path)
.map_err(LoadStaticControlSpecsError::SpecDirReadError)?
{
let entry = entry?;
let spec = load_from_yaml_file(entry.path())?;
specs.push(spec)
}
Ok(specs)
}
pub async fn start_static_rooms(
room_service: &Addr<RoomService>,
) -> Result<(), Error> {
match room_service.send(StartStaticRooms).await? {
Err(RoomServiceError::FailedToLoadStaticSpecs(
LoadStaticControlSpecsError::SpecDirReadError(e),
)) => warn!(
"Error while reading static control API specs dir. Control API \
specs not loaded. {}",
e,
),
Err(e) => return Err(Error::from(e)),
Ok(_) => {}
};
Ok(())
}