Skip to main content

tuwunel_service/rooms/event_handler/
fetch_state.rs

1use std::collections::{HashMap, hash_map};
2
3use futures::FutureExt;
4use ruma::{
5	EventId, OwnedEventId, RoomId, RoomVersionId, ServerName,
6	api::federation::event::get_room_state_ids, events::StateEventType,
7};
8use tuwunel_core::{Err, Result, debug, debug_warn, err, implement, matrix::Event};
9
10use crate::rooms::short::ShortStateKey;
11
12/// Call /state_ids to find out what the state at this pdu is. We trust the
13/// server's response to some extend (sic), but we still do a lot of checks
14/// on the events
15#[implement(super::Service)]
16#[tracing::instrument(
17	level = "debug",
18	skip_all,
19	fields(%origin),
20)]
21pub(super) async fn fetch_state(
22	&self,
23	origin: &ServerName,
24	room_id: &RoomId,
25	event_id: &EventId,
26	room_version: &RoomVersionId,
27	recursion_level: usize,
28	create_event_id: &EventId,
29) -> Result<Option<HashMap<u64, OwnedEventId>>> {
30	let res = self
31		.services
32		.federation
33		.execute(origin, get_room_state_ids::v1::Request {
34			room_id: room_id.to_owned(),
35			event_id: event_id.to_owned(),
36		})
37		.await
38		.inspect_err(|e| debug_warn!("Fetching state for event failed: {e}"))?;
39
40	debug!("Fetching state events");
41	let state_ids = res.pdu_ids.iter().map(AsRef::as_ref);
42	let state_vec = self
43		.fetch_auth(origin, room_id, state_ids, room_version, recursion_level)
44		.boxed()
45		.await;
46
47	let mut state: HashMap<ShortStateKey, OwnedEventId> = HashMap::with_capacity(state_vec.len());
48	for (pdu, _) in state_vec {
49		let state_key = pdu
50			.state_key()
51			.ok_or_else(|| err!(Database("Found non-state pdu in state events.")))?;
52
53		let shortstatekey = self
54			.services
55			.short
56			.get_or_create_shortstatekey(&pdu.kind().to_string().into(), state_key)
57			.await;
58
59		match state.entry(shortstatekey) {
60			| hash_map::Entry::Vacant(v) => {
61				v.insert(pdu.event_id().to_owned());
62			},
63			| hash_map::Entry::Occupied(_) => {
64				return Err!(Request(InvalidParam(
65					"State event's type and state_key ({:?},{:?}) exists multiple times.",
66					pdu.event_type(),
67					pdu.state_key()
68						.expect("all state events have state_key"),
69				)));
70			},
71		}
72	}
73
74	// The original create event must still be in the state
75	let create_shortstatekey = self
76		.services
77		.short
78		.get_shortstatekey(&StateEventType::RoomCreate, "")
79		.await?;
80
81	if state
82		.get(&create_shortstatekey)
83		.map(AsRef::as_ref)
84		!= Some(create_event_id)
85	{
86		return Err!(Database("Incoming event refers to wrong create event."));
87	}
88
89	Ok(Some(state))
90}