tuwunel_matrix/room/state/resolution/
fetch_state.rs1use std::{collections::BTreeMap, future::ready};
2
3use futures::{FutureExt, TryFutureExt};
4use ruma::{
5 UserId,
6 events::{StateEventType, room::member::MembershipState},
7};
8use tuwunel_core::{Error, Result, err, result::NotFound};
9
10use super::{
11 StateMap,
12 event_auth::auth_input_error,
13 events::{
14 JoinRule, RoomCreateEvent, RoomJoinRulesEvent, RoomMemberEvent, RoomPowerLevelsEvent,
15 RoomThirdPartyInviteEvent, member::RoomMemberEventResultExt,
16 },
17};
18use crate::{Event, PduEvent, StateKey, TypeStateKey};
19
20pub trait FetchState: Copy + Send + Sync {
24 type Pdu: Event;
28
29 fn get(
33 self,
34 ty: StateEventType,
35 key: StateKey,
36 ) -> impl Future<Output = Result<Self::Pdu>> + Send;
37
38 fn room_create_event(
42 self,
43 ) -> impl Future<Output = Result<RoomCreateEvent<Self::Pdu>>> + Send {
44 self.get(StateEventType::RoomCreate, "".into())
45 .map_err(auth_input_error)
46 .map_ok(RoomCreateEvent::new)
47 .map_err(required("m.room.create"))
48 }
49
50 fn user_membership(
54 self,
55 user_id: &UserId,
56 ) -> impl Future<Output = Result<MembershipState>> + Send {
57 self.get(StateEventType::RoomMember, user_id.as_str().into())
58 .map_err(auth_input_error)
59 .map_ok(RoomMemberEvent::new)
60 .map(RoomMemberEventResultExt::membership)
61 .map_err(auth_input_error)
62 }
63
64 fn room_power_levels_event(
68 self,
69 ) -> impl Future<Output = Result<Option<RoomPowerLevelsEvent<Self::Pdu>>>> + Send {
70 self.get(StateEventType::RoomPowerLevels, "".into())
71 .map_err(auth_input_error)
72 .map_ok(RoomPowerLevelsEvent::new)
73 .map(NotFound::optional)
74 }
75
76 fn join_rule(self) -> impl Future<Output = Result<JoinRule>> + Send {
80 self.get(StateEventType::RoomJoinRules, "".into())
81 .map_err(auth_input_error)
82 .map_ok(RoomJoinRulesEvent::new)
83 .map_err(required("m.room.join_rules"))
84 .and_then(|event| ready(event.join_rule().map_err(auth_input_error)))
85 }
86
87 fn room_third_party_invite_event(
91 self,
92 token: &str,
93 ) -> impl Future<Output = Result<Option<RoomThirdPartyInviteEvent<Self::Pdu>>>> + Send {
94 self.get(StateEventType::RoomThirdPartyInvite, token.into())
95 .map_err(auth_input_error)
96 .map_ok(RoomThirdPartyInviteEvent::new)
97 .map(NotFound::optional)
98 }
99}
100
101fn required(name: &'static str) -> impl Fn(Error) -> Error {
103 move |error| {
104 if error.is_not_found() {
105 err!("no `{name}` event in current state: {error}")
106 } else {
107 error
108 }
109 }
110}
111
112impl<'a> FetchState for &'a StateMap<PduEvent> {
113 type Pdu = &'a PduEvent;
114
115 fn get(
116 self,
117 ty: StateEventType,
118 key: StateKey,
119 ) -> impl Future<Output = Result<Self::Pdu>> + Send {
120 ready(
121 BTreeMap::get(self, &(ty, key))
122 .ok_or_else(|| err!(Request(NotFound("Missing state event")))),
123 )
124 }
125}
126
127impl<'a> FetchState for &'a [(TypeStateKey, PduEvent)] {
128 type Pdu = &'a PduEvent;
129
130 fn get(
131 self,
132 ty: StateEventType,
133 key: StateKey,
134 ) -> impl Future<Output = Result<Self::Pdu>> + Send {
135 ready(
136 self.iter()
137 .find(|((event_type, state_key), _)| *event_type == ty && *state_key == key)
138 .map(|(_, event)| event)
139 .ok_or_else(|| err!(Request(NotFound("Missing auth_event {ty:?},{key:?}")))),
140 )
141 }
142}