api: Add Metadata::versioning_decision_for
This commit is contained in:
parent
873270db1d
commit
f0177dc429
@ -15,6 +15,7 @@
|
|||||||
use std::{convert::TryInto as _, error::Error as StdError, fmt};
|
use std::{convert::TryInto as _, error::Error as StdError, fmt};
|
||||||
|
|
||||||
use bytes::BufMut;
|
use bytes::BufMut;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::UserId;
|
use crate::UserId;
|
||||||
|
|
||||||
@ -195,7 +196,7 @@ pub use ruma_macros::ruma_api;
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
mod metadata;
|
mod metadata;
|
||||||
|
|
||||||
pub use metadata::{MatrixVersion, Metadata};
|
pub use metadata::{MatrixVersion, Metadata, VersioningDecision};
|
||||||
|
|
||||||
use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};
|
use error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError};
|
||||||
|
|
||||||
@ -401,10 +402,6 @@ pub enum AuthScheme {
|
|||||||
// This function helps picks the right path (or an error) from a set of matrix versions.
|
// This function helps picks the right path (or an error) from a set of matrix versions.
|
||||||
//
|
//
|
||||||
// This function needs to be public, yet hidden, as all `try_into_http_request`s would be using it.
|
// This function needs to be public, yet hidden, as all `try_into_http_request`s would be using it.
|
||||||
//
|
|
||||||
// Note this assumes that `versions`;
|
|
||||||
// - at least has 1 element
|
|
||||||
// - have all elements sorted by its `.into_parts` representation.
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn select_path<'a>(
|
pub fn select_path<'a>(
|
||||||
versions: &'_ [MatrixVersion],
|
versions: &'_ [MatrixVersion],
|
||||||
@ -413,50 +410,48 @@ pub fn select_path<'a>(
|
|||||||
r0: Option<fmt::Arguments<'a>>,
|
r0: Option<fmt::Arguments<'a>>,
|
||||||
stable: Option<fmt::Arguments<'a>>,
|
stable: Option<fmt::Arguments<'a>>,
|
||||||
) -> Result<fmt::Arguments<'a>, IntoHttpError> {
|
) -> Result<fmt::Arguments<'a>, IntoHttpError> {
|
||||||
let greater_or_equal_any =
|
match metadata.versioning_decision_for(versions) {
|
||||||
|version: MatrixVersion| versions.iter().any(|v| v.is_superset_of(version));
|
VersioningDecision::Removed => Err(IntoHttpError::EndpointRemoved(
|
||||||
let greater_or_equal_all =
|
metadata.removed.expect("VersioningDecision::Removed implies metadata.removed"),
|
||||||
|version: MatrixVersion| versions.iter().all(|v| v.is_superset_of(version));
|
)),
|
||||||
|
VersioningDecision::Stable { any_deprecated, all_deprecated, any_removed } => {
|
||||||
let is_stable_any = metadata.added.map(greater_or_equal_any).unwrap_or(false);
|
if any_removed {
|
||||||
|
if all_deprecated {
|
||||||
let is_removed_all = metadata.removed.map(greater_or_equal_all).unwrap_or(false);
|
warn!(
|
||||||
|
"endpoint {} is removed in some (and deprecated in ALL) of the following versions: {:?}",
|
||||||
// Only when all the versions (e.g. 1.6-9) are compatible with the version that added it (e.g.
|
metadata.name,
|
||||||
// 1.1), yet are also "after" the version that removed it (e.g. 1.3), then we return that error.
|
versions
|
||||||
// Otherwise, this all versions may fall into a different major range, such as 2.X, where
|
);
|
||||||
// "after" and "compatible" do not exist with the 1.X range, so we at least need to make sure
|
} else if any_deprecated {
|
||||||
// that the versions are part of the same "range" through the `added` check.
|
warn!(
|
||||||
if is_stable_any && is_removed_all {
|
"endpoint {} is removed (and deprecated) in some of the following versions: {:?}",
|
||||||
return Err(IntoHttpError::EndpointRemoved(metadata.removed.unwrap()));
|
metadata.name,
|
||||||
}
|
versions
|
||||||
|
);
|
||||||
if is_stable_any {
|
} else {
|
||||||
let is_deprecated_any = metadata.deprecated.map(greater_or_equal_any).unwrap_or(false);
|
unreachable!("any_removed implies *_deprecated");
|
||||||
|
}
|
||||||
if is_deprecated_any {
|
} else if all_deprecated {
|
||||||
let is_removed_any = metadata.removed.map(greater_or_equal_any).unwrap_or(false);
|
warn!(
|
||||||
|
"endpoint {} is deprecated in ALL of the following versions: {:?}",
|
||||||
if is_removed_any {
|
metadata.name, versions
|
||||||
tracing::warn!("endpoint {} is deprecated, but also removed in one of more server-passed versions: {:?}", metadata.name, versions)
|
);
|
||||||
} else {
|
} else if any_deprecated {
|
||||||
tracing::warn!(
|
warn!(
|
||||||
"endpoint {} is deprecated in one of more server-passed versions: {:?}",
|
"endpoint {} is deprecated in some of the following versions: {:?}",
|
||||||
metadata.name,
|
metadata.name, versions
|
||||||
versions
|
);
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(r0) = r0 {
|
if let Some(r0) = r0 {
|
||||||
if versions.iter().all(|&v| v == MatrixVersion::V1_0) {
|
if versions.iter().all(|&v| v == MatrixVersion::V1_0) {
|
||||||
// Endpoint was added in 1.0, we return the r0 variant.
|
// Endpoint was added in 1.0, we return the r0 variant.
|
||||||
return Ok(r0);
|
return Ok(r0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(stable.expect("metadata.added enforces the stable path to exist"))
|
||||||
}
|
}
|
||||||
|
VersioningDecision::Unstable => unstable.ok_or(IntoHttpError::NoUnstablePath),
|
||||||
return Ok(stable.expect("metadata.added enforces the stable path to exist"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unstable.ok_or(IntoHttpError::NoUnstablePath)
|
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,69 @@ pub struct Metadata {
|
|||||||
pub removed: Option<MatrixVersion>,
|
pub removed: Option<MatrixVersion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Metadata {
|
||||||
|
/// Will decide how a particular set of matrix versions sees an endpoint.
|
||||||
|
///
|
||||||
|
/// It will pick `Stable` over `R0` and `Unstable`. It'll return `Deprecated` or `Removed` only
|
||||||
|
/// if all versions denote it.
|
||||||
|
///
|
||||||
|
/// In other words, if in any version it tells it supports the endpoint in a stable fashion,
|
||||||
|
/// this will return `Stable`, even if some versions in this set will denote deprecation or
|
||||||
|
/// removal.
|
||||||
|
///
|
||||||
|
/// If resulting [`VersioningDecision`] is `Stable`, it will also detail if any version denoted
|
||||||
|
/// deprecation or removal.
|
||||||
|
pub fn versioning_decision_for(&self, versions: &[MatrixVersion]) -> VersioningDecision {
|
||||||
|
let greater_or_equal_any =
|
||||||
|
|version: MatrixVersion| versions.iter().any(|v| v.is_superset_of(version));
|
||||||
|
let greater_or_equal_all =
|
||||||
|
|version: MatrixVersion| versions.iter().all(|v| v.is_superset_of(version));
|
||||||
|
|
||||||
|
// Check if all versions removed this endpoint.
|
||||||
|
if self.removed.map(greater_or_equal_all).unwrap_or(false) {
|
||||||
|
return VersioningDecision::Removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if *any* version marks this endpoint as stable.
|
||||||
|
if self.added.map(greater_or_equal_any).unwrap_or(false) {
|
||||||
|
let all_deprecated = self.deprecated.map(greater_or_equal_all).unwrap_or(false);
|
||||||
|
|
||||||
|
return VersioningDecision::Stable {
|
||||||
|
any_deprecated: all_deprecated
|
||||||
|
|| self.deprecated.map(greater_or_equal_any).unwrap_or(false),
|
||||||
|
all_deprecated,
|
||||||
|
any_removed: self.removed.map(greater_or_equal_any).unwrap_or(false),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
VersioningDecision::Unstable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A versioning "decision" derived from a set of matrix versions.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
#[allow(clippy::exhaustive_enums)]
|
||||||
|
pub enum VersioningDecision {
|
||||||
|
/// The unstable endpoint should be used.
|
||||||
|
Unstable,
|
||||||
|
/// The stable endpoint should be used.
|
||||||
|
///
|
||||||
|
/// Note, in the special case that all versions note [v1.0](MatrixVersion::V1_0), and the
|
||||||
|
/// [`r0_path`](Metadata::r0_path) is not `None`, that path should be used.
|
||||||
|
Stable {
|
||||||
|
/// If any version denoted deprecation.
|
||||||
|
any_deprecated: bool,
|
||||||
|
|
||||||
|
/// If *all* versions denoted deprecation.
|
||||||
|
all_deprecated: bool,
|
||||||
|
|
||||||
|
/// If any version denoted removal.
|
||||||
|
any_removed: bool,
|
||||||
|
},
|
||||||
|
/// This endpoint was removed in all versions, it should not be used.
|
||||||
|
Removed,
|
||||||
|
}
|
||||||
|
|
||||||
/// The Matrix versions Ruma currently understands to exist.
|
/// The Matrix versions Ruma currently understands to exist.
|
||||||
///
|
///
|
||||||
/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
|
/// Matrix, since fall 2021, has a quarterly release schedule, using a global `vX.Y` versioning
|
||||||
|
Loading…
x
Reference in New Issue
Block a user