use axum::{Json, extract::State, response::IntoResponse}; use conduwuit::{ Err, Result, matrix::versions::{unstable_features, versions}, metrics::PROMETHEUS_CONTENT_TYPE, utils::string::constant_time_eq, }; use futures::StreamExt; use http::{HeaderMap, header}; use ruma::{api::client::discovery::get_supported_versions, assign}; use crate::Ruma; /// # `GET /_matrix/client/versions` /// /// Get the versions of the specification and unstable features supported by /// this server. /// /// - Versions take the form MAJOR.MINOR.PATCH /// - Only the latest PATCH release will be reported for each MAJOR.MINOR value /// - Unstable features are namespaced and may include version information in /// their name /// /// Note: Unstable features are used while developing new features. Clients /// should avoid using unstable features in their stable releases pub(crate) async fn get_supported_versions_route( State(services): State, _body: Ruma, ) -> Result { let mut unstable_features = unstable_features(); if services.config.allow_sticky_events { // sticky events (https://github.com/matrix-org/matrix-spec-proposals/pull/4354) unstable_features.insert("org.matrix.msc4354".to_owned(), true); } Ok(assign!(get_supported_versions::Response::new(versions()), { unstable_features })) } /// # `GET /_continuwuity/server_version` /// /// Conduwuit-specific API to get the server version, results akin to /// `/_matrix/federation/v1/version` pub(crate) async fn continuwuity_server_version() -> Result { Ok(Json(serde_json::json!({ "name": conduwuit::BRANDING, "version": conduwuit::version(), }))) } /// # `GET /_continuwuity/local_user_count` /// /// conduwuit-specific API to return the amount of users registered on this /// homeserver. Endpoint is disabled if federation is disabled for privacy. This /// /// only includes active users (not deactivated, etc) pub(crate) async fn continuwuity_local_user_count( State(services): State, ) -> Result { let user_count = services .users .stream_local_users() .filter_map(async |user_id| { if !services.users.status(&user_id).await.is_active() || services.appservice.is_exclusive_user_id(&user_id).await { None } else { Some(user_id) } }) .count() .await; Ok(Json(serde_json::json!({ "count": user_count }))) } /// # `GET /_continuwuity/metrics` /// /// Prometheus metrics in the text exposition format. Only routed when /// `allow_prometheus_metrics` is enabled. pub(crate) async fn continuwuity_metrics( State(services): State, headers: HeaderMap, ) -> Result { if let Some(token) = &services.config.prometheus_metrics_token { let authorized = headers .get(header::AUTHORIZATION) .and_then(|value| value.to_str().ok()) .and_then(|value| value.split_once(' ')) .is_some_and(|(scheme, provided)| { scheme.eq_ignore_ascii_case("bearer") && constant_time_eq(provided, token) }); if !authorized { return Err!(Request(Forbidden("Invalid metrics token"))); } } let body = services.server.metrics.render()?; Ok(([(header::CONTENT_TYPE, PROMETHEUS_CONTENT_TYPE)], body)) }