1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
//! `GET /_matrix/client/versions` ([spec])
//!
//! Get the versions of the client-server API supported by this homeserver.
//!
//! [spec]: https://spec.matrix.org/latest/client-server-api/#get_matrixclientversions
use std::collections::BTreeMap;
use ruma_common::{
api::{request, response, MatrixVersion, Metadata},
metadata,
};
const METADATA: Metadata = metadata! {
method: GET,
rate_limited: false,
authentication: AccessTokenOptional,
history: {
1.0 => "/_matrix/client/versions",
}
};
/// Request type for the `api_versions` endpoint.
#[request(error = crate::Error)]
#[derive(Default)]
pub struct Request {}
/// Response type for the `api_versions` endpoint.
#[response(error = crate::Error)]
pub struct Response {
/// A list of Matrix client API protocol versions supported by the homeserver.
pub versions: Vec<String>,
/// Experimental features supported by the server.
///
/// Servers can enable some unstable features only for some users, so this
/// list might differ when an access token is provided.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub unstable_features: BTreeMap<String, bool>,
}
impl Request {
/// Creates an empty `Request`.
pub fn new() -> Self {
Self {}
}
}
impl Response {
/// Creates a new `Response` with the given `versions`.
pub fn new(versions: Vec<String>) -> Self {
Self { versions, unstable_features: BTreeMap::new() }
}
/// Extracts known Matrix versions from this response.
///
/// Matrix versions that Ruma cannot parse, or does not know about, are discarded.
///
/// The versions returned will be sorted from oldest to latest. Use [`.find()`][Iterator::find]
/// or [`.rfind()`][DoubleEndedIterator::rfind] to look for a minimum or maximum version to use
/// given some constraint.
pub fn known_versions(&self) -> impl DoubleEndedIterator<Item = MatrixVersion> {
self.versions
.iter()
// Parse, discard unknown versions
.flat_map(|s| s.parse::<MatrixVersion>())
// Map to key-value pairs where the key is the major-minor representation
// (which can be used as a BTreeMap unlike MatrixVersion itself)
.map(|v| (v.into_parts(), v))
// Collect to BTreeMap
.collect::<BTreeMap<_, _>>()
// Return an iterator over just the values (`MatrixVersion`s)
.into_values()
}
}
#[cfg(test)]
mod tests {
use ruma_common::api::MatrixVersion;
use super::Response;
#[test]
fn known_versions() {
let none = Response::new(vec![]);
assert_eq!(none.known_versions().next(), None);
let single_known = Response::new(vec!["r0.6.0".to_owned()]);
assert_eq!(single_known.known_versions().collect::<Vec<_>>(), vec![MatrixVersion::V1_0]);
let single_unknown = Response::new(vec!["v0.0".to_owned()]);
assert_eq!(single_unknown.known_versions().next(), None);
}
#[test]
fn known_versions_order() {
let sorted = Response::new(vec![
"r0.0.1".to_owned(),
"r0.5.0".to_owned(),
"r0.6.0".to_owned(),
"r0.6.1".to_owned(),
"v1.1".to_owned(),
"v1.2".to_owned(),
]);
assert_eq!(
sorted.known_versions().collect::<Vec<_>>(),
vec![MatrixVersion::V1_0, MatrixVersion::V1_1, MatrixVersion::V1_2],
);
let sorted_reverse = Response::new(vec![
"v1.2".to_owned(),
"v1.1".to_owned(),
"r0.6.1".to_owned(),
"r0.6.0".to_owned(),
"r0.5.0".to_owned(),
"r0.0.1".to_owned(),
]);
assert_eq!(
sorted_reverse.known_versions().collect::<Vec<_>>(),
vec![MatrixVersion::V1_0, MatrixVersion::V1_1, MatrixVersion::V1_2],
);
let random_order = Response::new(vec![
"v1.1".to_owned(),
"r0.6.1".to_owned(),
"r0.5.0".to_owned(),
"r0.6.0".to_owned(),
"r0.0.1".to_owned(),
"v1.2".to_owned(),
]);
assert_eq!(
random_order.known_versions().collect::<Vec<_>>(),
vec![MatrixVersion::V1_0, MatrixVersion::V1_1, MatrixVersion::V1_2],
);
}
}