tuwunel_service/rooms/state_res/
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::{
9 Error, Result, err,
10 matrix::{Event, PduEvent, StateKey, TypeStateKey},
11 result::NotFound,
12};
13
14use super::{
15 StateMap,
16 event_auth::auth_input_error,
17 events::{
18 JoinRule, RoomCreateEvent, RoomJoinRulesEvent, RoomMemberEvent, RoomPowerLevelsEvent,
19 RoomThirdPartyInviteEvent, member::RoomMemberEventResultExt,
20 },
21};
22
23pub trait FetchState: Copy + Send + Sync {
27 type Pdu: Event;
31
32 fn get(
36 self,
37 ty: StateEventType,
38 key: StateKey,
39 ) -> impl Future<Output = Result<Self::Pdu>> + Send;
40
41 fn room_create_event(
45 self,
46 ) -> impl Future<Output = Result<RoomCreateEvent<Self::Pdu>>> + Send {
47 self.get(StateEventType::RoomCreate, "".into())
48 .map_err(auth_input_error)
49 .map_ok(RoomCreateEvent::new)
50 .map_err(required("m.room.create"))
51 }
52
53 fn user_membership(
57 self,
58 user_id: &UserId,
59 ) -> impl Future<Output = Result<MembershipState>> + Send {
60 self.get(StateEventType::RoomMember, user_id.as_str().into())
61 .map_err(auth_input_error)
62 .map_ok(RoomMemberEvent::new)
63 .map(RoomMemberEventResultExt::membership)
64 .map_err(auth_input_error)
65 }
66
67 fn room_power_levels_event(
71 self,
72 ) -> impl Future<Output = Result<Option<RoomPowerLevelsEvent<Self::Pdu>>>> + Send {
73 self.get(StateEventType::RoomPowerLevels, "".into())
74 .map_err(auth_input_error)
75 .map_ok(RoomPowerLevelsEvent::new)
76 .map(NotFound::optional)
77 }
78
79 fn join_rule(self) -> impl Future<Output = Result<JoinRule>> + Send {
83 self.get(StateEventType::RoomJoinRules, "".into())
84 .map_err(auth_input_error)
85 .map_ok(RoomJoinRulesEvent::new)
86 .map_err(required("m.room.join_rules"))
87 .and_then(|event| ready(event.join_rule().map_err(auth_input_error)))
88 }
89
90 fn room_third_party_invite_event(
94 self,
95 token: &str,
96 ) -> impl Future<Output = Result<Option<RoomThirdPartyInviteEvent<Self::Pdu>>>> + Send {
97 self.get(StateEventType::RoomThirdPartyInvite, token.into())
98 .map_err(auth_input_error)
99 .map_ok(RoomThirdPartyInviteEvent::new)
100 .map(NotFound::optional)
101 }
102}
103
104fn required(name: &'static str) -> impl Fn(Error) -> Error {
106 move |error| {
107 if error.is_not_found() {
108 err!("no `{name}` event in current state: {error}")
109 } else {
110 error
111 }
112 }
113}
114
115impl<'a> FetchState for &'a StateMap<PduEvent> {
116 type Pdu = &'a PduEvent;
117
118 fn get(
119 self,
120 ty: StateEventType,
121 key: StateKey,
122 ) -> impl Future<Output = Result<Self::Pdu>> + Send {
123 ready(
124 BTreeMap::get(self, &(ty, key))
125 .ok_or_else(|| err!(Request(NotFound("Missing state event")))),
126 )
127 }
128}
129
130impl<'a> FetchState for &'a [(TypeStateKey, PduEvent)] {
131 type Pdu = &'a PduEvent;
132
133 fn get(
134 self,
135 ty: StateEventType,
136 key: StateKey,
137 ) -> impl Future<Output = Result<Self::Pdu>> + Send {
138 ready(
139 self.iter()
140 .find(|((event_type, state_key), _)| *event_type == ty && *state_key == key)
141 .map(|(_, event)| event)
142 .ok_or_else(|| err!(Request(NotFound("Missing auth_event {ty:?},{key:?}")))),
143 )
144 }
145}