ruma_client_api/rtc/
transports.rs1pub mod v1 {
6 use std::borrow::Cow;
11
12 use ruma_common::{
13 api::{auth_scheme::AccessToken, request, response},
14 metadata,
15 serde::{JsonObject, from_raw_json_value},
16 };
17 use serde::{Deserialize, Deserializer, Serialize, de::DeserializeOwned};
18 use serde_json::{Value as JsonValue, value::RawValue as RawJsonValue};
19
20 metadata! {
21 method: GET,
22 rate_limited: false,
23 authentication: AccessToken,
24 history: {
25 unstable => "/_matrix/client/unstable/org.matrix.msc4143/rtc/transports",
26 }
27 }
28
29 #[request]
31 #[derive(Default)]
32 pub struct Request {}
33
34 impl Request {
35 pub fn new() -> Self {
37 Self {}
38 }
39 }
40
41 #[response]
43 #[derive(Default)]
44 pub struct Response {
45 pub rtc_transports: Vec<RtcTransport>,
47 }
48
49 impl Response {
50 pub fn new(rtc_transports: Vec<RtcTransport>) -> Self {
52 Self { rtc_transports }
53 }
54 }
55
56 #[derive(Clone, Debug, Serialize, PartialEq, Eq)]
61 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
62 #[serde(tag = "type")]
63 pub enum RtcTransport {
64 #[cfg(feature = "unstable-msc4195")]
66 #[serde(rename = "livekit_multi_sfu")]
67 LivekitMultiSfu(LivekitMultiSfuTransport),
68
69 #[doc(hidden)]
71 #[serde(untagged)]
72 _Custom(CustomRtcTransport),
73 }
74
75 impl RtcTransport {
76 pub fn new(transport_type: String, data: JsonObject) -> serde_json::Result<Self> {
87 fn deserialize_variant<T: DeserializeOwned>(obj: JsonObject) -> serde_json::Result<T> {
88 serde_json::from_value(obj.into())
89 }
90
91 Ok(match transport_type.as_str() {
92 #[cfg(feature = "unstable-msc4195")]
93 "livekit_multi_sfu" => Self::LivekitMultiSfu(deserialize_variant(data)?),
94 _ => Self::_Custom(CustomRtcTransport { transport_type, data }),
95 })
96 }
97
98 pub fn transport_type(&self) -> &str {
100 match self {
101 #[cfg(feature = "unstable-msc4195")]
102 Self::LivekitMultiSfu(_) => "livekit_multi_sfu",
103 Self::_Custom(custom) => &custom.transport_type,
104 }
105 }
106
107 pub fn data(&self) -> Cow<'_, JsonObject> {
115 fn serialize<T: Serialize>(object: &T) -> JsonObject {
116 match serde_json::to_value(object).expect("rtc focus type serialization to succeed")
117 {
118 JsonValue::Object(object) => object,
119 _ => panic!("rtc transports must serialize to JSON objects"),
120 }
121 }
122
123 match self {
124 #[cfg(feature = "unstable-msc4195")]
125 Self::LivekitMultiSfu(info) => Cow::Owned(serialize(info)),
126 Self::_Custom(info) => Cow::Borrowed(&info.data),
127 }
128 }
129 }
130
131 impl<'de> Deserialize<'de> for RtcTransport {
132 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
133 where
134 D: Deserializer<'de>,
135 {
136 #[derive(Deserialize)]
137 struct RtcTransportDeHelper {
138 #[serde(rename = "type")]
139 transport_type: String,
140 }
141
142 let json = Box::<RawJsonValue>::deserialize(deserializer)?;
143 let RtcTransportDeHelper { transport_type } = from_raw_json_value(&json)?;
144
145 Ok(match transport_type.as_str() {
146 #[cfg(feature = "unstable-msc4195")]
147 "livekit_multi_sfu" => Self::LivekitMultiSfu(from_raw_json_value(&json)?),
148 _ => {
149 let mut data = from_raw_json_value::<JsonObject, _>(&json)?;
150 data.remove("type");
151
152 Self::_Custom(CustomRtcTransport { transport_type, data })
153 }
154 })
155 }
156 }
157
158 #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
160 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
161 #[cfg(feature = "unstable-msc4195")]
162 pub struct LivekitMultiSfuTransport {
163 pub livekit_service_url: String,
165 }
166
167 #[cfg(feature = "unstable-msc4195")]
168 impl LivekitMultiSfuTransport {
169 pub fn new(livekit_service_url: String) -> Self {
171 Self { livekit_service_url }
172 }
173 }
174
175 #[cfg(feature = "unstable-msc4195")]
176 impl From<LivekitMultiSfuTransport> for RtcTransport {
177 fn from(value: LivekitMultiSfuTransport) -> Self {
178 Self::LivekitMultiSfu(value)
179 }
180 }
181
182 #[cfg(feature = "unstable-msc4195")]
183 impl From<LivekitMultiSfuTransport> for crate::discovery::discover_homeserver::LiveKitRtcFocusInfo {
184 fn from(value: LivekitMultiSfuTransport) -> Self {
185 let LivekitMultiSfuTransport { livekit_service_url } = value;
186 Self { service_url: livekit_service_url }
187 }
188 }
189
190 #[cfg(feature = "unstable-msc4195")]
191 impl From<crate::discovery::discover_homeserver::LiveKitRtcFocusInfo> for LivekitMultiSfuTransport {
192 fn from(value: crate::discovery::discover_homeserver::LiveKitRtcFocusInfo) -> Self {
193 let crate::discovery::discover_homeserver::LiveKitRtcFocusInfo { service_url } = value;
194 Self { livekit_service_url: service_url }
195 }
196 }
197
198 #[doc(hidden)]
200 #[derive(Clone, Debug, Serialize, PartialEq, Eq)]
201 pub struct CustomRtcTransport {
202 #[serde(rename = "type")]
204 transport_type: String,
205
206 #[serde(flatten)]
208 data: JsonObject,
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use assert_matches2::assert_let;
215 use ruma_common::canonical_json::assert_to_canonical_json_eq;
216 use serde_json::{Value as JsonValue, from_value as from_json_value, json};
217
218 use super::v1::{LivekitMultiSfuTransport, RtcTransport};
219
220 #[test]
221 fn serialize_roundtrip_custom_rtc_transport() {
222 let transport_type = "local.custom.transport";
223 assert_let!(
224 JsonValue::Object(transport_data) = json!({
225 "foo": "bar",
226 "baz": true,
227 })
228 );
229 let transport =
230 RtcTransport::new(transport_type.to_owned(), transport_data.clone()).unwrap();
231 let json = json!({
232 "type": transport_type,
233 "foo": "bar",
234 "baz": true,
235 });
236
237 assert_eq!(transport.transport_type(), transport_type);
238 assert_eq!(*transport.data().as_ref(), transport_data);
239 assert_to_canonical_json_eq!(transport, json.clone());
240 assert_eq!(from_json_value::<RtcTransport>(json).unwrap(), transport);
241 }
242
243 #[cfg(feature = "unstable-msc4195")]
244 #[test]
245 fn serialize_roundtrip_livekit_multi_sfu_transport() {
246 let transport_type = "livekit_multi_sfu";
247 let livekit_service_url = "http://livekit.local/";
248 let transport =
249 RtcTransport::from(LivekitMultiSfuTransport::new(livekit_service_url.to_owned()));
250 let json = json!({
251 "type": transport_type,
252 "livekit_service_url": livekit_service_url,
253 });
254
255 assert_eq!(transport.transport_type(), transport_type);
256 assert_to_canonical_json_eq!(transport, json.clone());
257 assert_eq!(from_json_value::<RtcTransport>(json).unwrap(), transport);
258 }
259}