|
1 |
| -use std::{ops::Deref, sync::Arc}; |
| 1 | +use std::{cmp::min, convert::TryFrom, ops::Deref, sync::Arc}; |
2 | 2 |
|
3 |
| -use matrix_sdk_base::deserialized_responses::MembersResponse; |
| 3 | +use matrix_sdk_base::deserialized_responses::{MembersResponse, SyncRoomEvent}; |
4 | 4 | use matrix_sdk_common::locks::Mutex;
|
5 | 5 | use ruma::{
|
6 | 6 | api::client::r0::{
|
| 7 | + context::get_context, |
7 | 8 | media::{get_content, get_content_thumbnail},
|
8 | 9 | membership::{get_member_events, join_room_by_id, leave_room},
|
9 |
| - message::get_message_events, |
| 10 | + message::{get_message_events, get_message_events::Direction}, |
10 | 11 | },
|
11 |
| - UserId, |
| 12 | + events::AnyRoomEvent, |
| 13 | + serde::Raw, |
| 14 | + EventId, UserId, |
12 | 15 | };
|
13 | 16 |
|
14 |
| -use crate::{BaseRoom, Client, Result, RoomMember}; |
| 17 | +use crate::{BaseRoom, Client, Result, RoomMember, UInt}; |
15 | 18 |
|
16 | 19 | /// A struct containing methods that are common for Joined, Invited and Left
|
17 | 20 | /// Rooms
|
@@ -110,43 +113,160 @@ impl Common {
|
110 | 113 | }
|
111 | 114 | }
|
112 | 115 |
|
113 |
| - /// Sends a request to `/_matrix/client/r0/rooms/{room_id}/messages` and |
114 |
| - /// returns a `get_message_events::Response` that contains a chunk of |
115 |
| - /// room and state events (`AnyRoomEvent` and `AnyStateEvent`). |
| 116 | + /// Gets a slice of the timeline of this room |
| 117 | + /// |
| 118 | + /// Returns a slice of the timeline between `start` and `end`, no longer |
| 119 | + /// then `limit`. If the number of events is fewer then `limit` it means |
| 120 | + /// that in the given direction no more events exist. |
| 121 | + /// If the timeline doesn't contain an event with the given `start` `None` |
| 122 | + /// is returned. |
116 | 123 | ///
|
117 | 124 | /// # Arguments
|
118 | 125 | ///
|
119 |
| - /// * `request` - The easiest way to create this request is using the |
120 |
| - /// `get_message_events::Request` itself. |
| 126 | + /// * `start` - An `EventId` that indicates the start of the slice. |
| 127 | + /// |
| 128 | + /// * `end` - An `EventId` that indicates the end of the slice. |
| 129 | + /// |
| 130 | + /// * `limit` - The maximum number of events that should be returned. |
| 131 | + /// |
| 132 | + /// * `direction` - The direction of the search and returned events. |
121 | 133 | ///
|
122 | 134 | /// # Examples
|
123 | 135 | /// ```no_run
|
124 | 136 | /// # use std::convert::TryFrom;
|
125 | 137 | /// use matrix_sdk::Client;
|
126 |
| - /// # use matrix_sdk::identifiers::room_id; |
127 |
| - /// # use matrix_sdk::api::r0::filter::RoomEventFilter; |
128 |
| - /// # use matrix_sdk::api::r0::message::get_message_events::Request as MessagesRequest; |
| 138 | + /// # use matrix_sdk::identifiers::{event_id, room_id}; |
| 139 | + /// # use matrix_sdk::api::r0::message::get_message_events::Direction; |
129 | 140 | /// # use url::Url;
|
130 | 141 | ///
|
131 | 142 | /// # let homeserver = Url::parse("http://example.com").unwrap();
|
132 | 143 | /// let room_id = room_id!("!roomid:example.com");
|
133 |
| - /// let request = MessagesRequest::backward(&room_id, "t47429-4392820_219380_26003_2265"); |
134 | 144 | ///
|
135 | 145 | /// let mut client = Client::new(homeserver).unwrap();
|
136 | 146 | /// # let room = client
|
137 | 147 | /// # .get_joined_room(&room_id)
|
138 | 148 | /// # .unwrap();
|
139 | 149 | /// # use futures::executor::block_on;
|
140 | 150 | /// # block_on(async {
|
141 |
| - /// assert!(room.messages(request).await.is_ok()); |
| 151 | + /// assert!(room.messages(&event_id!("$xxxxxx:example.org"), None, 10, Direction::Backward).await.is_ok()); |
142 | 152 | /// # });
|
143 | 153 | /// ```
|
144 | 154 | pub async fn messages(
|
145 | 155 | &self,
|
146 |
| - request: impl Into<get_message_events::Request<'_>>, |
147 |
| - ) -> Result<get_message_events::Response> { |
148 |
| - let request = request.into(); |
149 |
| - self.client.send(request, None).await |
| 156 | + start: &EventId, |
| 157 | + end: Option<&EventId>, |
| 158 | + limit: usize, |
| 159 | + direction: Direction, |
| 160 | + ) -> Result<Option<Vec<SyncRoomEvent>>> { |
| 161 | + let room_id = self.inner.room_id(); |
| 162 | + let events = if let Some(mut stored) = self |
| 163 | + .client |
| 164 | + .store() |
| 165 | + .get_timeline(room_id, Some(start), end, Some(limit), direction.clone()) |
| 166 | + .await? |
| 167 | + { |
| 168 | + // We found a gab or the end of the stored timeline. |
| 169 | + if let Some(token) = stored.token { |
| 170 | + let mut request = get_message_events::Request::new( |
| 171 | + self.inner.room_id(), |
| 172 | + &token, |
| 173 | + direction.clone(), |
| 174 | + ); |
| 175 | + request.limit = |
| 176 | + UInt::try_from((limit - stored.events.len()) as u64).unwrap_or(UInt::MAX); |
| 177 | + |
| 178 | + let response = self.client.send(request, None).await?; |
| 179 | + |
| 180 | + // FIXME: we may recevied an invalied server response that ruma considers valid |
| 181 | + // See https://github.com/ruma/ruma/issues/644 |
| 182 | + if response.end.is_none() && response.start.is_none() { |
| 183 | + return Ok(Some(stored.events)); |
| 184 | + } |
| 185 | + |
| 186 | + let response_events = self |
| 187 | + .client |
| 188 | + .base_client |
| 189 | + .receive_messages(room_id, &direction, &response) |
| 190 | + .await?; |
| 191 | + |
| 192 | + let mut response_events = if let Some(end) = end { |
| 193 | + if let Some(position) = |
| 194 | + response_events.iter().position(|event| &event.event_id() == end) |
| 195 | + { |
| 196 | + response_events.into_iter().take(position + 1).collect() |
| 197 | + } else { |
| 198 | + response_events |
| 199 | + } |
| 200 | + } else { |
| 201 | + response_events |
| 202 | + }; |
| 203 | + |
| 204 | + match direction { |
| 205 | + Direction::Forward => { |
| 206 | + response_events.append(&mut stored.events); |
| 207 | + stored.events = response_events; |
| 208 | + } |
| 209 | + Direction::Backward => stored.events.append(&mut response_events), |
| 210 | + } |
| 211 | + } |
| 212 | + stored.events |
| 213 | + } else { |
| 214 | + // Fallback to context API because we don't know the start event |
| 215 | + let mut request = get_context::Request::new(room_id, start); |
| 216 | + |
| 217 | + // We need to take limit twice because the context api returns events before |
| 218 | + // and after the given event |
| 219 | + request.limit = UInt::try_from((limit * 2) as u64).unwrap_or(UInt::MAX); |
| 220 | + |
| 221 | + let mut context = self.client.send(request, None).await?; |
| 222 | + |
| 223 | + let event = if let Some(event) = context.event { |
| 224 | + event |
| 225 | + } else { |
| 226 | + return Ok(None); |
| 227 | + }; |
| 228 | + |
| 229 | + let mut response = get_message_events::Response::new(); |
| 230 | + response.start = context.start; |
| 231 | + response.end = context.end; |
| 232 | + let before_length = context.events_before.len(); |
| 233 | + let after_length = context.events_after.len(); |
| 234 | + let mut events: Vec<Raw<AnyRoomEvent>> = |
| 235 | + context.events_after.into_iter().rev().collect(); |
| 236 | + events.push(event); |
| 237 | + events.append(&mut context.events_before); |
| 238 | + response.chunk = events; |
| 239 | + response.state = context.state; |
| 240 | + let response_events = self |
| 241 | + .client |
| 242 | + .base_client |
| 243 | + .receive_messages(room_id, &Direction::Backward, &response) |
| 244 | + .await?; |
| 245 | + |
| 246 | + let response_events: Vec<SyncRoomEvent> = match direction { |
| 247 | + Direction::Forward => { |
| 248 | + let lower_bound = if before_length > limit { before_length - limit } else { 0 }; |
| 249 | + response_events[lower_bound..=before_length].to_vec() |
| 250 | + } |
| 251 | + Direction::Backward => response_events |
| 252 | + [after_length..min(response_events.len(), after_length + limit)] |
| 253 | + .to_vec(), |
| 254 | + }; |
| 255 | + |
| 256 | + if let Some(end) = end { |
| 257 | + if let Some(position) = |
| 258 | + response_events.iter().position(|event| &event.event_id() == end) |
| 259 | + { |
| 260 | + response_events.into_iter().take(position + 1).collect() |
| 261 | + } else { |
| 262 | + response_events |
| 263 | + } |
| 264 | + } else { |
| 265 | + response_events |
| 266 | + } |
| 267 | + }; |
| 268 | + |
| 269 | + Ok(Some(events)) |
150 | 270 | }
|
151 | 271 |
|
152 | 272 | pub(crate) async fn request_members(&self) -> Result<Option<MembersResponse>> {
|
|
0 commit comments