tuwunel_service/rooms/event_handler/
fetch_state.rs1use 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#[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 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}