tuwunel_api/client/room/
initial_sync.rs1use axum::extract::State;
2use futures::{FutureExt, StreamExt, TryFutureExt, TryStreamExt, future::try_join5};
3use ruma::{
4 api::client::room::initial_sync::v3::{PaginationChunk, Request, Response},
5 events::AnyRawAccountDataEvent,
6};
7use tuwunel_core::{
8 Err, Event, Result, at, extract_variant,
9 matrix::PduCount,
10 utils::stream::{ReadyExt, TryTools},
11};
12
13use crate::Ruma;
14
15const LIMIT_MAX: usize = 50;
16
17pub(crate) async fn room_initial_sync_route(
19 State(services): State<crate::State>,
20 body: Ruma<Request>,
21) -> Result<Response> {
22 let room_id = &body.room_id;
23
24 if !services
25 .state_accessor
26 .user_can_see_state_events(body.sender_user(), room_id)
27 .await
28 {
29 return Err!(Request(Forbidden("No room preview available.")));
30 }
31
32 let next_batch = services.globals.current_count();
33
34 let visibility = services.directory.visibility(room_id).map(Ok);
35
36 let membership = services
37 .state_cache
38 .user_membership(body.sender_user(), room_id)
39 .map(Ok);
40
41 let state = services
42 .state_accessor
43 .room_state_full_pdus(room_id)
44 .map_ok(Event::into_format)
45 .try_collect::<Vec<_>>();
46
47 let limit = LIMIT_MAX;
48 let events = services
49 .timeline
50 .pdus_rev(None, room_id, Some(PduCount::Normal(next_batch).saturating_add(1)))
51 .try_take(limit)
52 .try_collect()
53 .map_ok(|mut vec: Vec<_>| {
54 vec.reverse();
55 vec
56 });
57
58 let account_data = services
59 .account_data
60 .changes_since(Some(room_id), body.sender_user(), 0, Some(next_batch))
61 .ready_filter_map(|e| extract_variant!(e, AnyRawAccountDataEvent::Room))
62 .collect::<Vec<_>>()
63 .map(Ok);
64
65 let (membership, visibility, state, events, account_data) =
66 try_join5(membership, visibility, state, events, account_data)
67 .boxed()
68 .await?;
69
70 Ok(Response {
71 room_id: room_id.to_owned(),
72 membership,
73 visibility: visibility.into(),
74 account_data: Some(account_data),
75 state: state.into(),
76 messages: PaginationChunk {
77 start: events
78 .first()
79 .map(at!(0))
80 .as_ref()
81 .map(ToString::to_string),
82
83 end: events
84 .last()
85 .map(at!(0))
86 .as_ref()
87 .map(ToString::to_string)
88 .unwrap_or_default(),
89
90 chunk: events
91 .into_iter()
92 .map(at!(1))
93 .map(Event::into_format)
94 .collect(),
95 }
96 .into(),
97 })
98}