ruma_client_api/rendezvous/
create_rendezvous_session.rs1#[cfg(feature = "unstable-msc4108")]
6pub mod unstable_msc4108 {
7 use http::header::{CONTENT_TYPE, ETAG, EXPIRES, LAST_MODIFIED};
12 #[cfg(feature = "client")]
13 use ruma_common::api::BytesBody;
14 use ruma_common::{
15 api::{
16 auth_scheme::NoAccessToken,
17 error::{DeserializationError, Error, HeaderDeserializationError},
18 },
19 http_headers::TEXT_PLAIN,
20 metadata,
21 };
22 use url::Url;
23 use web_time::SystemTime;
24
25 metadata! {
26 method: POST,
27 rate_limited: true,
28 authentication: NoAccessToken,
29 history: {
30 unstable("org.matrix.msc4108") => "/_matrix/client/unstable/org.matrix.msc4108/rendezvous",
31 }
32 }
33
34 #[derive(Debug, Default, Clone)]
36 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
37 pub struct Request {
38 pub content: String,
40 }
41
42 #[cfg(feature = "client")]
43 impl ruma_common::api::OutgoingRequest for Request {
44 type Body = BytesBody;
45 type EndpointError = Error;
46 type IncomingResponse = Response;
47
48 fn try_into_http_request_inner(
49 self,
50 base_url: &str,
51 considering: std::borrow::Cow<'_, ruma_common::api::SupportedVersions>,
52 ) -> Result<http::Request<BytesBody>, ruma_common::api::error::IntoHttpError> {
53 use http::header::CONTENT_LENGTH;
54 use ruma_common::api::Metadata;
55
56 let url = Self::make_endpoint_url(considering, base_url, &[], "")?;
57 let content_length = self.content.len();
58
59 Ok(http::Request::builder()
60 .method(Self::METHOD)
61 .uri(url)
62 .header(CONTENT_TYPE, TEXT_PLAIN)
63 .header(CONTENT_LENGTH, content_length)
64 .body(BytesBody(self.content.into()))?)
65 }
66 }
67
68 #[cfg(feature = "server")]
69 impl ruma_common::api::IncomingRequest for Request {
70 type EndpointError = Error;
71 type OutgoingResponse = Response;
72
73 fn try_from_http_request_inner(
74 request: http::Request<&[u8]>,
75 _path_args: &[&str],
76 ) -> Result<Self, DeserializationError> {
77 let content_type = request
78 .headers()
79 .get(CONTENT_TYPE)
80 .ok_or(HeaderDeserializationError::MissingHeader(CONTENT_TYPE.to_string()))?;
81
82 if content_type != TEXT_PLAIN {
83 Err(HeaderDeserializationError::InvalidHeaderValue {
84 header: CONTENT_TYPE.to_string(),
85 expected: TEXT_PLAIN
86 .to_str()
87 .expect("expected content type should be a valid static string")
88 .to_owned(),
89 unexpected: content_type.to_str()?.to_owned(),
90 }
91 .into())
92 } else {
93 let body = request.into_body().to_vec();
94 let content = String::from_utf8(body)
95 .map_err(|e| DeserializationError::Utf8(e.utf8_error()))?;
96
97 Ok(Self { content })
98 }
99 }
100 }
101
102 impl Request {
103 pub fn new(content: String) -> Self {
105 Self { content }
106 }
107 }
108
109 #[derive(Debug, Clone)]
111 #[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
112 pub struct Response {
113 pub url: Url,
115
116 pub etag: String,
119
120 pub expires: SystemTime,
123
124 pub last_modified: SystemTime,
127 }
128
129 #[doc(hidden)]
130 #[derive(ruma_common::serde::_FakeDeriveSerde)]
131 #[cfg_attr(feature = "server", derive(serde::Serialize, ruma_common::api::OutgoingBodyJson))]
132 #[cfg_attr(feature = "client", derive(serde::Deserialize))]
133 pub struct ResponseBody {
134 url: Url,
135 }
136
137 #[cfg(feature = "client")]
138 impl ruma_common::api::IncomingResponse for Response {
139 type EndpointError = Error;
140
141 fn try_from_http_response_inner(
142 response: http::Response<&[u8]>,
143 ) -> Result<Self, DeserializationError> {
144 let get_date = |header: http::HeaderName| -> Result<SystemTime, DeserializationError> {
145 let date = response
146 .headers()
147 .get(&header)
148 .ok_or_else(|| HeaderDeserializationError::MissingHeader(header.to_string()))?;
149
150 let date = ruma_common::http_headers::http_date_to_system_time(date)?;
151
152 Ok(date)
153 };
154
155 let etag = response
156 .headers()
157 .get(ETAG)
158 .ok_or(HeaderDeserializationError::MissingHeader(ETAG.to_string()))?
159 .to_str()?
160 .to_owned();
161 let expires = get_date(EXPIRES)?;
162 let last_modified = get_date(LAST_MODIFIED)?;
163
164 let body: ResponseBody = serde_json::from_slice(response.body())?;
165
166 Ok(Self { url: body.url, etag, expires, last_modified })
167 }
168 }
169
170 #[cfg(feature = "server")]
171 impl ruma_common::api::OutgoingResponse for Response {
172 type Body = ResponseBody;
173
174 fn try_into_http_response_inner(
175 self,
176 ) -> Result<http::Response<Self::Body>, ruma_common::api::error::IntoHttpError> {
177 use http::header::{CACHE_CONTROL, PRAGMA};
178 use ruma_common::http_headers::system_time_to_http_date;
179
180 let body = ResponseBody { url: self.url };
181
182 let expires = system_time_to_http_date(&self.expires)?;
183 let last_modified = system_time_to_http_date(&self.last_modified)?;
184
185 Ok(http::Response::builder()
186 .status(http::StatusCode::OK)
187 .header(PRAGMA, "no-cache")
188 .header(CACHE_CONTROL, "no-store")
189 .header(ETAG, self.etag)
190 .header(EXPIRES, expires)
191 .header(LAST_MODIFIED, last_modified)
192 .body(body)?)
193 }
194 }
195}
196
197#[cfg(feature = "unstable-msc4388")]
198pub mod unstable_msc4388 {
199 use std::time::Duration;
203
204 use ruma_common::{
205 api::{auth_scheme::AccessTokenOptional, request, response},
206 metadata,
207 };
208
209 metadata! {
210 method: POST,
211 rate_limited: true,
212 authentication: AccessTokenOptional,
213 history: {
214 unstable => "/_matrix/client/unstable/io.element.msc4388/rendezvous",
215 }
216 }
217
218 #[request]
220 pub struct Request {
221 pub data: String,
223 }
224
225 impl Request {
226 pub fn new(data: String) -> Self {
228 Self { data }
229 }
230 }
231
232 #[response]
234 pub struct Response {
235 pub id: String,
237
238 pub sequence_token: String,
240
241 #[serde(with = "ruma_common::serde::duration::ms", rename = "expires_in_ms")]
243 pub expires_in: Duration,
244 }
245
246 impl Response {
247 pub fn new(id: String, sequence_token: String, expires_in: Duration) -> Self {
249 Self { id, sequence_token, expires_in }
250 }
251 }
252}