feat(spaces): hierarchy over federation
Signed-off-by: strawberry <strawberry@puppygock.gay>
This commit is contained in:
parent
8972487691
commit
c14b28b408
8 changed files with 1138 additions and 315 deletions
|
@ -1,6 +1,11 @@
|
||||||
use ruma::api::client::space::get_hierarchy;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::{services, Result, Ruma};
|
use ruma::{
|
||||||
|
api::client::{error::ErrorKind, space::get_hierarchy},
|
||||||
|
UInt,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{service::rooms::spaces::PagnationToken, services, Error, Result, Ruma};
|
||||||
|
|
||||||
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy``
|
/// # `GET /_matrix/client/v1/rooms/{room_id}/hierarchy``
|
||||||
///
|
///
|
||||||
|
@ -9,11 +14,32 @@ use crate::{services, Result, Ruma};
|
||||||
pub async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
|
pub async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
|
||||||
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
|
||||||
|
|
||||||
let skip = body.from.as_ref().and_then(|s| s.parse::<usize>().ok()).unwrap_or(0);
|
let limit = body.limit.unwrap_or_else(|| UInt::from(10_u32)).min(UInt::from(100_u32));
|
||||||
|
|
||||||
let limit = body.limit.map_or(10, u64::from).min(100) as usize;
|
let max_depth = body.max_depth.unwrap_or_else(|| UInt::from(3_u32)).min(UInt::from(10_u32));
|
||||||
|
|
||||||
let max_depth = body.max_depth.map_or(3, u64::from).min(10) as usize + 1; // +1 to skip the space room itself
|
let key = body.from.as_ref().and_then(|s| PagnationToken::from_str(s).ok());
|
||||||
|
|
||||||
services().rooms.spaces.get_hierarchy(sender_user, &body.room_id, limit, skip, max_depth, body.suggested_only).await
|
// Should prevent unexpeded behaviour in (bad) clients
|
||||||
|
if let Some(ref token) = key {
|
||||||
|
if token.suggested_only != body.suggested_only || token.max_depth != max_depth {
|
||||||
|
return Err(Error::BadRequest(
|
||||||
|
ErrorKind::InvalidParam,
|
||||||
|
"suggested_only and max_depth cannot change on paginated requests",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
services()
|
||||||
|
.rooms
|
||||||
|
.spaces
|
||||||
|
.get_client_hierarchy(
|
||||||
|
sender_user,
|
||||||
|
&body.room_id,
|
||||||
|
u64::from(limit) as usize,
|
||||||
|
key.map_or(0, |token| u64::from(token.skip) as usize),
|
||||||
|
u64::from(max_depth) as usize,
|
||||||
|
body.suggested_only,
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ use ruma::{
|
||||||
keys::{claim_keys, get_keys},
|
keys::{claim_keys, get_keys},
|
||||||
membership::{create_invite, create_join_event, prepare_join_event},
|
membership::{create_invite, create_join_event, prepare_join_event},
|
||||||
query::{get_profile_information, get_room_information},
|
query::{get_profile_information, get_room_information},
|
||||||
|
space::get_hierarchy,
|
||||||
transactions::{
|
transactions::{
|
||||||
edu::{DeviceListUpdateContent, DirectDeviceContent, Edu, SigningKeyUpdateContent},
|
edu::{DeviceListUpdateContent, DirectDeviceContent, Edu, SigningKeyUpdateContent},
|
||||||
send_transaction_message,
|
send_transaction_message,
|
||||||
|
@ -1734,6 +1735,20 @@ pub async fn well_known_server_route() -> Result<impl IntoResponse> {
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # `GET /_matrix/federation/v1/hierarchy/{roomId}`
|
||||||
|
///
|
||||||
|
/// Gets the space tree in a depth-first manner to locate child rooms of a given
|
||||||
|
/// space.
|
||||||
|
pub async fn get_hierarchy_route(body: Ruma<get_hierarchy::v1::Request>) -> Result<get_hierarchy::v1::Response> {
|
||||||
|
let sender_servername = body.sender_servername.as_ref().expect("server is authenticated");
|
||||||
|
|
||||||
|
if services().rooms.metadata.exists(&body.room_id)? {
|
||||||
|
services().rooms.spaces.get_federation_hierarchy(&body.room_id, sender_servername, body.suggested_only).await
|
||||||
|
} else {
|
||||||
|
Err(Error::BadRequest(ErrorKind::NotFound, "Room does not exist."))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{add_port_to_hostname, get_ip_with_port, FedDest};
|
use super::{add_port_to_hostname, get_ip_with_port, FedDest};
|
||||||
|
|
|
@ -268,6 +268,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of users which are currently in a room
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
|
fn room_joined_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
|
||||||
self.roomid_joinedcount
|
self.roomid_joinedcount
|
||||||
|
@ -276,6 +277,7 @@ impl service::rooms::state_cache::Data for KeyValueDatabase {
|
||||||
.transpose()
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the number of users which are currently invited to a room
|
||||||
#[tracing::instrument(skip(self))]
|
#[tracing::instrument(skip(self))]
|
||||||
fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
|
fn room_invited_count(&self, room_id: &RoomId) -> Result<Option<u64>> {
|
||||||
self.roomid_invitedcount
|
self.roomid_invitedcount
|
||||||
|
|
|
@ -739,6 +739,7 @@ fn routes() -> Router {
|
||||||
.ruma_route(server_server::get_profile_information_route)
|
.ruma_route(server_server::get_profile_information_route)
|
||||||
.ruma_route(server_server::get_keys_route)
|
.ruma_route(server_server::get_keys_route)
|
||||||
.ruma_route(server_server::claim_keys_route)
|
.ruma_route(server_server::claim_keys_route)
|
||||||
|
.ruma_route(server_server::get_hierarchy_route)
|
||||||
.route("/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync))
|
.route("/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync))
|
||||||
.route("/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync))
|
.route("/_matrix/client/v3/rooms/:room_id/initialSync", get(initial_sync))
|
||||||
.route("/client/server.json", get(client_server::syncv3_client_server_json))
|
.route("/client/server.json", get(client_server::syncv3_client_server_json))
|
||||||
|
|
|
@ -134,7 +134,7 @@ impl Services<'_> {
|
||||||
db,
|
db,
|
||||||
},
|
},
|
||||||
spaces: rooms::spaces::Service {
|
spaces: rooms::spaces::Service {
|
||||||
roomid_spacechunk_cache: Mutex::new(LruCache::new(
|
roomid_spacehierarchy_cache: Mutex::new(LruCache::new(
|
||||||
(100.0 * config.conduit_cache_capacity_modifier) as usize,
|
(100.0 * config.conduit_cache_capacity_modifier) as usize,
|
||||||
)),
|
)),
|
||||||
},
|
},
|
||||||
|
@ -175,7 +175,7 @@ impl Services<'_> {
|
||||||
let user_visibility_cache = self.rooms.state_accessor.user_visibility_cache.lock().unwrap().len();
|
let user_visibility_cache = self.rooms.state_accessor.user_visibility_cache.lock().unwrap().len();
|
||||||
let stateinfo_cache = self.rooms.state_compressor.stateinfo_cache.lock().unwrap().len();
|
let stateinfo_cache = self.rooms.state_compressor.stateinfo_cache.lock().unwrap().len();
|
||||||
let lasttimelinecount_cache = self.rooms.timeline.lasttimelinecount_cache.lock().await.len();
|
let lasttimelinecount_cache = self.rooms.timeline.lasttimelinecount_cache.lock().await.len();
|
||||||
let roomid_spacechunk_cache = self.rooms.spaces.roomid_spacechunk_cache.lock().await.len();
|
let roomid_spacehierarchy_cache = self.rooms.spaces.roomid_spacehierarchy_cache.lock().await.len();
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"\
|
"\
|
||||||
|
@ -184,7 +184,7 @@ server_visibility_cache: {server_visibility_cache}
|
||||||
user_visibility_cache: {user_visibility_cache}
|
user_visibility_cache: {user_visibility_cache}
|
||||||
stateinfo_cache: {stateinfo_cache}
|
stateinfo_cache: {stateinfo_cache}
|
||||||
lasttimelinecount_cache: {lasttimelinecount_cache}
|
lasttimelinecount_cache: {lasttimelinecount_cache}
|
||||||
roomid_spacechunk_cache: {roomid_spacechunk_cache}"
|
roomid_spacehierarchy_cache: {roomid_spacehierarchy_cache}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +205,7 @@ roomid_spacechunk_cache: {roomid_spacechunk_cache}"
|
||||||
self.rooms.timeline.lasttimelinecount_cache.lock().await.clear();
|
self.rooms.timeline.lasttimelinecount_cache.lock().await.clear();
|
||||||
}
|
}
|
||||||
if amount > 5 {
|
if amount > 5 {
|
||||||
self.rooms.spaces.roomid_spacechunk_cache.lock().await.clear();
|
self.rooms.spaces.roomid_spacehierarchy_cache.lock().await.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -74,7 +74,7 @@ impl Service {
|
||||||
.await?;
|
.await?;
|
||||||
},
|
},
|
||||||
TimelineEventType::SpaceChild => {
|
TimelineEventType::SpaceChild => {
|
||||||
services().rooms.spaces.roomid_spacechunk_cache.lock().await.remove(&pdu.room_id);
|
services().rooms.spaces.roomid_spacehierarchy_cache.lock().await.remove(&pdu.room_id);
|
||||||
},
|
},
|
||||||
_ => continue,
|
_ => continue,
|
||||||
}
|
}
|
||||||
|
|
|
@ -418,7 +418,7 @@ impl Service {
|
||||||
},
|
},
|
||||||
TimelineEventType::SpaceChild => {
|
TimelineEventType::SpaceChild => {
|
||||||
if let Some(_state_key) = &pdu.state_key {
|
if let Some(_state_key) = &pdu.state_key {
|
||||||
services().rooms.spaces.roomid_spacechunk_cache.lock().await.remove(&pdu.room_id);
|
services().rooms.spaces.roomid_spacehierarchy_cache.lock().await.remove(&pdu.room_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TimelineEventType::RoomMember => {
|
TimelineEventType::RoomMember => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue