pub mod v1 {
use std::borrow::Cow;
use ruma_common::{
api::{auth_scheme::AccessToken, request, response},
metadata,
serde::JsonObject,
};
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use serde_json::Value as JsonValue;
metadata! {
method: GET,
rate_limited: false,
authentication: AccessToken,
history: {
unstable => "/_matrix/client/unstable/org.matrix.msc4143/rtc/transports",
}
}
#[request(error = crate::Error)]
#[derive(Default)]
pub struct Request {}
impl Request {
pub fn new() -> Self {
Self {}
}
}
#[response(error = crate::Error)]
#[derive(Default)]
pub struct Response {
pub rtc_transports: Vec<RtcTransport>,
}
impl Response {
pub fn new(rtc_transports: Vec<RtcTransport>) -> Self {
Self { rtc_transports }
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
#[serde(tag = "type")]
pub enum RtcTransport {
#[cfg(feature = "unstable-msc4195")]
#[serde(rename = "livekit_multi_sfu")]
LivekitMultiSfu(LivekitMultiSfuTransport),
#[doc(hidden)]
#[serde(untagged)]
_Custom(CustomRtcTransport),
}
impl RtcTransport {
pub fn new(transport_type: String, data: JsonObject) -> serde_json::Result<Self> {
fn deserialize_variant<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
serde_json::from_value(obj.into())
}
Ok(match transport_type.as_str() {
#[cfg(feature = "unstable-msc4195")]
"livekit_multi_sfu" => Self::LivekitMultiSfu(deserialize_variant(data)?),
_ => Self::_Custom(CustomRtcTransport { transport_type, data }),
})
}
pub fn transport_type(&self) -> &str {
match self {
#[cfg(feature = "unstable-msc4195")]
Self::LivekitMultiSfu(_) => "livekit_multi_sfu",
Self::_Custom(custom) => &custom.transport_type,
}
}
pub fn data(&self) -> Cow<'_, JsonObject> {
fn serialize<T: Serialize>(object: &T) -> JsonObject {
match serde_json::to_value(object).expect("rtc focus type serialization to succeed")
{
JsonValue::Object(object) => object,
_ => panic!("rtc transports must serialize to JSON objects"),
}
}
match self {
#[cfg(feature = "unstable-msc4195")]
Self::LivekitMultiSfu(info) => Cow::Owned(serialize(info)),
Self::_Custom(info) => Cow::Borrowed(&info.data),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
#[cfg(feature = "unstable-msc4195")]
pub struct LivekitMultiSfuTransport {
pub livekit_service_url: String,
}
#[cfg(feature = "unstable-msc4195")]
impl LivekitMultiSfuTransport {
pub fn new(livekit_service_url: String) -> Self {
Self { livekit_service_url }
}
}
#[cfg(feature = "unstable-msc4195")]
impl From<LivekitMultiSfuTransport> for RtcTransport {
fn from(value: LivekitMultiSfuTransport) -> Self {
Self::LivekitMultiSfu(value)
}
}
#[cfg(feature = "unstable-msc4195")]
impl From<LivekitMultiSfuTransport> for crate::discovery::discover_homeserver::LiveKitRtcFocusInfo {
fn from(value: LivekitMultiSfuTransport) -> Self {
let LivekitMultiSfuTransport { livekit_service_url } = value;
Self { service_url: livekit_service_url }
}
}
#[cfg(feature = "unstable-msc4195")]
impl From<crate::discovery::discover_homeserver::LiveKitRtcFocusInfo> for LivekitMultiSfuTransport {
fn from(value: crate::discovery::discover_homeserver::LiveKitRtcFocusInfo) -> Self {
let crate::discovery::discover_homeserver::LiveKitRtcFocusInfo { service_url } = value;
Self { livekit_service_url: service_url }
}
}
#[doc(hidden)]
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct CustomRtcTransport {
#[serde(rename = "type")]
transport_type: String,
#[serde(flatten)]
data: JsonObject,
}
}
#[cfg(test)]
mod tests {
use assert_matches2::assert_matches;
use serde_json::{
Value as JsonValue, from_value as from_json_value, json, to_value as to_json_value,
};
use super::v1::{LivekitMultiSfuTransport, RtcTransport};
#[test]
fn serialize_roundtrip_custom_rtc_transport() {
let transport_type = "local.custom.transport";
assert_matches!(
json!({
"foo": "bar",
"baz": true,
}),
JsonValue::Object(transport_data)
);
let transport =
RtcTransport::new(transport_type.to_owned(), transport_data.clone()).unwrap();
let json = json!({
"type": transport_type,
"foo": "bar",
"baz": true,
});
assert_eq!(transport.transport_type(), transport_type);
assert_eq!(*transport.data().as_ref(), transport_data);
assert_eq!(to_json_value(&transport).unwrap(), json);
assert_eq!(from_json_value::<RtcTransport>(json).unwrap(), transport);
}
#[cfg(feature = "unstable-msc4195")]
#[test]
fn serialize_roundtrip_livekit_multi_sfu_transport() {
let transport_type = "livekit_multi_sfu";
let livekit_service_url = "http://livekit.local/";
let transport =
RtcTransport::from(LivekitMultiSfuTransport::new(livekit_service_url.to_owned()));
let json = json!({
"type": transport_type,
"livekit_service_url": livekit_service_url,
});
assert_eq!(transport.transport_type(), transport_type);
assert_eq!(to_json_value(&transport).unwrap(), json);
assert_eq!(from_json_value::<RtcTransport>(json).unwrap(), transport);
}
}