arminius_lib_sync/
messages.rs1#![allow(
8 clippy::allow_attributes,
9 reason = "This source file contains enums which allow `clippy::missing_docs_in_private_items`. But an exception to this lint will mistakenly report that it's unfulfilled when used with expect, even though it is not."
10)]
11
12use arminius_lib_authentication::AuthenticatedClaims;
13use arminius_lib_component::{
14 MessageTokenParseError, MessagesToken,
15 error::{InternalServerError, MatrixApiError, RoomNotFound},
16 ruma_requests::{ArminiusResponse, RumaRequest},
17};
18use arminius_lib_db::{Database as _, DefaultDb};
19use arminius_lib_db_room::EventQueries as _;
20use arminius_lib_db_sync::SyncQueries as _;
21use arminius_lib_events::ContextualizedFields as _;
22use axum::extract::State;
23use ruma::{
24 api::{Direction, client::message::get_message_events},
25 serde::Raw,
26};
27
28use crate::sync_token::SyncTokenParseError;
29
30#[allow(
31 missing_docs,
32 clippy::missing_docs_in_private_items,
33 clippy::enum_variant_names,
34 reason = "TODO(#2003): This exception predates us enabling `clippy::allow_attributes_without_reason`, so we don't know why it was enabled"
35)]
36#[derive(thiserror::Error, Debug, MatrixApiError, arminius_lib_macros::FromDbError)]
37pub(crate) enum MessagesError {
38 #[error(transparent)]
39 InternalServerError(#[from] InternalServerError),
40 #[error(transparent)]
41 SyncTokenParseError(#[from] SyncTokenParseError),
42 #[error(transparent)]
43 MessagesTokenParseError(#[from] MessageTokenParseError),
44 #[error(transparent)]
45 RoomNotFound(#[from] RoomNotFound),
46}
47
48pub(crate) async fn get_message_events_handler(
53 mut database: State<DefaultDb>,
54 AuthenticatedClaims(claims): AuthenticatedClaims,
55 RumaRequest(request): RumaRequest<get_message_events::v3::Request>,
56) -> Result<ArminiusResponse<get_message_events::v3::Response>, MessagesError> {
57 tracing::info!(?request, "got /messages request");
58
59 let mut response = get_message_events::v3::Response::new();
60 let event_id = request
61 .from
62 .as_deref()
63 .map(MessagesToken::try_from)
64 .transpose()?
65 .map(|MessagesToken(event_id)| event_id);
66
67 let mut transaction = database.begin_transaction().await?;
68
69 let (events, there_are_more) = match request.dir {
70 Direction::Backward => {
71 transaction
72 .fetch_room_messages_backwards(
73 &claims.user_id,
74 &request.room_id,
75 event_id.as_deref(),
76 request.limit,
77 &request.filter,
78 )
79 .await?
80 }
81 Direction::Forward => {
82 transaction
83 .fetch_room_messages_forwards(
84 &claims.user_id,
85 &request.room_id,
86 event_id.as_deref(),
87 request.limit,
88 &request.filter,
89 )
90 .await?
91 }
92 };
93
94 tracing::info!("Got events from db {events:?}");
96
97 if there_are_more {
98 response.end =
99 events.last().map(|event| String::from(&MessagesToken(event.event_id().to_owned())));
100 }
101
102 for event in events {
103 let client_context = transaction
104 .fetch_client_context(
105 &request.room_id,
106 event.event_id(),
107 &claims.user_id,
108 &claims.device_id,
109 )
110 .await?;
111 let client_event = event.to_client_event(client_context);
112 response.chunk.push(Raw::from_json(client_event));
113 }
114
115 transaction.commit().await?;
116 Ok(ArminiusResponse(response))
117}