Files
tuwunel/src/api/server/state.rs
2025-10-02 05:27:48 +00:00

89 lines
1.9 KiB
Rust

use std::{borrow::Borrow, iter::once};
use axum::extract::State;
use futures::{
FutureExt, StreamExt, TryFutureExt, TryStreamExt,
future::{join, try_join},
};
use ruma::{OwnedEventId, api::federation::event::get_room_state};
use tuwunel_core::{
Result, at, err,
utils::{
future::TryExtExt,
stream::{IterStream, TryBroadbandExt},
},
};
use super::AccessCheck;
use crate::Ruma;
/// # `GET /_matrix/federation/v1/state/{roomId}`
///
/// Retrieves a snapshot of a room's state at a given event.
pub(crate) async fn get_room_state_route(
State(services): State<crate::State>,
body: Ruma<get_room_state::v1::Request>,
) -> Result<get_room_state::v1::Response> {
AccessCheck {
services: &services,
origin: body.origin(),
room_id: &body.room_id,
event_id: None,
}
.check()
.await?;
let shortstatehash = services
.state
.pdu_shortstatehash(&body.event_id)
.await
.map_err(|_| err!(Request(NotFound("PDU state not found."))))?;
let state_ids = services
.state_accessor
.state_full_ids(shortstatehash)
.map(at!(1))
.collect::<Vec<OwnedEventId>>();
let room_version = services
.state
.get_room_version(&body.room_id)
.ok();
let (room_version, state_ids) = join(room_version, state_ids).await;
let into_federation_format = |pdu| {
services
.federation
.format_pdu_into(pdu, room_version.as_ref())
.map(Ok)
};
let auth_chain = services
.auth_chain
.event_ids_iter(&body.room_id, once(body.event_id.borrow()))
.broad_and_then(async |id| {
services
.timeline
.get_pdu_json(&id)
.and_then(into_federation_format)
.await
})
.try_collect();
let pdus = state_ids
.iter()
.try_stream()
.broad_and_then(|id| {
services
.timeline
.get_pdu_json(id)
.and_then(into_federation_format)
})
.try_collect();
let (auth_chain, pdus) = try_join(auth_chain, pdus).await?;
Ok(get_room_state::v1::Response { auth_chain, pdus })
}