Skip to content

Commit 38dfa90

Browse files
authored
feat(sdk): LocalEventTimelineItem has a new send_state field
feat(sdk): `LocalEventTimelineItem` has a new `send_state` field
2 parents 4086492 + 274bc20 commit 38dfa90

File tree

7 files changed

+191
-50
lines changed

7 files changed

+191
-50
lines changed

bindings/matrix-sdk-ffi/src/lib.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,12 @@ mod uniffi_types {
9191
},
9292
timeline::{
9393
EmoteMessageContent, EncryptedMessage, EventTimelineItem, FileInfo, FileMessageContent,
94-
FormattedBody, ImageInfo, ImageMessageContent, InsertAtData, MembershipChange, Message,
95-
MessageFormat, MessageType, NoticeMessageContent, OtherState, Profile, Reaction,
96-
TextMessageContent, ThumbnailInfo, TimelineChange, TimelineDiff, TimelineItem,
97-
TimelineItemContent, TimelineItemContentKind, UpdateAtData, VideoInfo,
98-
VideoMessageContent, VirtualTimelineItem,
94+
FormattedBody, ImageInfo, ImageMessageContent, InsertAtData,
95+
LocalEventTimelineItemSendState, MembershipChange, Message, MessageFormat, MessageType,
96+
NoticeMessageContent, OtherState, Profile, Reaction, TextMessageContent, ThumbnailInfo,
97+
TimelineChange, TimelineDiff, TimelineItem, TimelineItemContent,
98+
TimelineItemContentKind, UpdateAtData, VideoInfo, VideoMessageContent,
99+
VirtualTimelineItem,
99100
},
100101
};
101102
}

bindings/matrix-sdk-ffi/src/timeline.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,32 @@ impl TimelineItem {
170170
}
171171
}
172172

173+
/// This type represents the “send state” of a local event timeline item.
174+
#[derive(Clone, uniffi::Enum)]
175+
pub enum LocalEventTimelineItemSendState {
176+
/// The local event has not been sent yet.
177+
NotSendYet,
178+
/// The local event has been sent to the server, but unsuccessfully: The
179+
/// sending has failed.
180+
SendingFailed,
181+
/// The local event has been sent successfully to the server.
182+
Sent,
183+
}
184+
185+
impl From<matrix_sdk::room::timeline::LocalEventTimelineItemSendState>
186+
for LocalEventTimelineItemSendState
187+
{
188+
fn from(value: matrix_sdk::room::timeline::LocalEventTimelineItemSendState) -> Self {
189+
use matrix_sdk::room::timeline::LocalEventTimelineItemSendState::*;
190+
191+
match value {
192+
NotSentYet => Self::NotSendYet,
193+
SendingFailed => Self::SendingFailed,
194+
Sent => Self::Sent,
195+
}
196+
}
197+
}
198+
173199
#[derive(uniffi::Object)]
174200
pub struct EventTimelineItem(pub(crate) matrix_sdk::room::timeline::EventTimelineItem);
175201

@@ -234,6 +260,15 @@ impl EventTimelineItem {
234260
self.0.raw().map(|r| r.json().get().to_owned())
235261
}
236262

263+
pub fn local_send_state(&self) -> Option<LocalEventTimelineItemSendState> {
264+
use matrix_sdk::room::timeline::EventTimelineItem::*;
265+
266+
match &self.0 {
267+
Local(local_event) => Some(local_event.send_state.into()),
268+
Remote(_) => None,
269+
}
270+
}
271+
237272
pub fn fmt_debug(&self) -> String {
238273
format!("{:#?}", self.0)
239274
}

crates/matrix-sdk/src/room/timeline/event_handler.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ use tracing::{debug, error, field::debug, info, instrument, trace, warn};
4343
use super::{
4444
event_item::{
4545
AnyOtherFullStateEventContent, BundledReactions, LocalEventTimelineItem,
46-
MemberProfileChange, OtherState, Profile, RemoteEventTimelineItem, RoomMembershipChange,
47-
Sticker, TimelineDetails,
46+
LocalEventTimelineItemSendState, MemberProfileChange, OtherState, Profile,
47+
RemoteEventTimelineItem, RoomMembershipChange, Sticker, TimelineDetails,
4848
},
4949
find_event_by_id, find_event_by_txn_id, find_read_marker, EventTimelineItem, Message,
5050
TimelineInnerMetadata, TimelineItem, TimelineItemContent, VirtualTimelineItem,
@@ -240,13 +240,16 @@ impl<'a, 'i> TimelineEventHandler<'a, 'i> {
240240
#[instrument(skip_all, fields(txn_id, event_id, position))]
241241
pub(super) fn handle_event(mut self, event_kind: TimelineEventKind) -> HandleEventResult {
242242
let span = tracing::Span::current();
243+
243244
match &self.flow {
244245
Flow::Local { txn_id, .. } => {
245246
span.record("txn_id", debug(txn_id));
246247
}
248+
247249
Flow::Remote { event_id, txn_id, position, .. } => {
248250
span.record("event_id", debug(event_id));
249251
span.record("position", debug(position));
252+
250253
if let Some(txn_id) = txn_id {
251254
span.record("txn_id", debug(txn_id));
252255
}
@@ -279,21 +282,27 @@ impl<'a, 'i> TimelineEventHandler<'a, 'i> {
279282
);
280283
}
281284
},
285+
282286
TimelineEventKind::RedactedMessage => {
283287
self.add(NewEventTimelineItem::redacted_message());
284288
}
289+
285290
TimelineEventKind::Redaction { redacts, content } => {
286291
self.handle_redaction(redacts, content);
287292
}
293+
288294
TimelineEventKind::RoomMember { user_id, content, sender } => {
289295
self.add(NewEventTimelineItem::room_member(user_id, content, sender));
290296
}
297+
291298
TimelineEventKind::OtherState { state_key, content } => {
292299
self.add(NewEventTimelineItem::other_state(state_key, content));
293300
}
301+
294302
TimelineEventKind::FailedToParseMessageLike { event_type, error } => {
295303
self.add(NewEventTimelineItem::failed_to_parse_message_like(event_type, error));
296304
}
305+
297306
TimelineEventKind::FailedToParseState { event_type, state_key, error } => {
298307
self.add(NewEventTimelineItem::failed_to_parse_state(event_type, state_key, error));
299308
}
@@ -488,6 +497,7 @@ impl<'a, 'i> TimelineEventHandler<'a, 'i> {
488497
}
489498
}
490499

500+
/// Add a new event item in the timeline.
491501
fn add(&mut self, item: NewEventTimelineItem) {
492502
self.result.item_added = true;
493503

@@ -500,6 +510,7 @@ impl<'a, 'i> TimelineEventHandler<'a, 'i> {
500510
match &self.flow {
501511
Flow::Local { txn_id, timestamp } => {
502512
EventTimelineItem::Local(LocalEventTimelineItem {
513+
send_state: LocalEventTimelineItemSendState::NotSentYet,
503514
transaction_id: txn_id.to_owned(),
504515
event_id: None,
505516
sender,

crates/matrix-sdk/src/room/timeline/event_item.rs

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,22 @@ impl EventTimelineItem {
180180
}
181181
}
182182

183-
#[derive(Clone, Debug)]
183+
/// This type represents the “send state” of a local event timeline item.
184+
#[derive(Debug, Copy, Clone, PartialEq)]
185+
pub enum LocalEventTimelineItemSendState {
186+
/// The local event has not been sent yet.
187+
NotSentYet,
188+
/// The local event has been sent to the server, but unsuccessfully: The
189+
/// sending has failed.
190+
SendingFailed,
191+
/// The local event has been sent successfully to the server.
192+
Sent,
193+
}
194+
195+
#[derive(Debug, Clone)]
184196
pub struct LocalEventTimelineItem {
197+
/// The send state of this local event.
198+
pub send_state: LocalEventTimelineItemSendState,
185199
/// The transaction ID.
186200
pub transaction_id: OwnedTransactionId,
187201
/// The event ID received from the server in the event-sending response.
@@ -198,8 +212,23 @@ pub struct LocalEventTimelineItem {
198212

199213
impl LocalEventTimelineItem {
200214
/// Clone the current event item, and update its `event_id`.
201-
pub(super) fn with_event_id(&self, event_id: OwnedEventId) -> Self {
202-
Self { event_id: Some(event_id), ..self.clone() }
215+
///
216+
/// `event_id` is optional:
217+
/// * `Some(_)` means the local event has been sent successfully to the
218+
/// server, its send state will be moved to
219+
/// [`LocalEventTimelineItemSendState::Sent`].
220+
/// * `None` means the local event has been failed to be sent to the
221+
/// server, its send state will be moved to
222+
/// [`LocalEventTimelineItemSendState::SendingFailed`].
223+
pub(super) fn with_event_id(&self, event_id: Option<OwnedEventId>) -> Self {
224+
Self {
225+
send_state: match &event_id {
226+
Some(_) => LocalEventTimelineItemSendState::Sent,
227+
None => LocalEventTimelineItemSendState::SendingFailed,
228+
},
229+
event_id,
230+
..self.clone()
231+
}
203232
}
204233
}
205234

crates/matrix-sdk/src/room/timeline/inner.rs

Lines changed: 64 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use matrix_sdk_base::{
1313
locks::Mutex,
1414
};
1515
use ruma::{
16+
api::client::message::send_message_event::v3::Response as SendMessageEventResponse,
1617
events::{
1718
fully_read::FullyReadEvent, relation::Annotation, AnyMessageLikeEventContent,
1819
AnySyncTimelineEvent,
@@ -109,6 +110,7 @@ impl<P: ProfileProvider> TimelineInner<P> {
109110
.await;
110111
}
111112

113+
/// Handle the creation of a new local event.
112114
pub(super) async fn handle_local_event(
113115
&self,
114116
txn_id: OwnedTransactionId,
@@ -134,29 +136,45 @@ impl<P: ProfileProvider> TimelineInner<P> {
134136
.handle_event(kind);
135137
}
136138

137-
/// Handle a back-paginated event.
138-
///
139-
/// Returns the number of timeline updates that were made.
140-
pub(super) async fn handle_back_paginated_event(
139+
/// Handle the response returned by the server when a local event has been
140+
/// sent.
141+
pub(super) fn handle_local_event_send_response(
141142
&self,
142-
event: TimelineEvent,
143-
) -> HandleEventResult {
144-
let mut metadata_lock = self.metadata.lock().await;
145-
handle_remote_event(
146-
event.event.cast(),
147-
event.encryption_info,
148-
TimelineItemPosition::Start,
149-
&self.items,
150-
&mut metadata_lock,
151-
&self.profile_provider,
152-
)
153-
.await
143+
txn_id: &TransactionId,
144+
response: crate::error::Result<SendMessageEventResponse>,
145+
) -> crate::error::Result<()> {
146+
match response {
147+
Ok(response) => {
148+
self.update_event_id_of_local_event(txn_id, Some(response.event_id));
149+
150+
Ok(())
151+
}
152+
Err(error) => {
153+
self.update_event_id_of_local_event(txn_id, None);
154+
155+
Err(error)
156+
}
157+
}
154158
}
155159

156-
/// Update the transaction ID by an event ID.
157-
pub(super) fn add_event_id(&self, txn_id: &TransactionId, event_id: OwnedEventId) {
160+
/// Update the event ID of a local event represented by a transaction ID.
161+
///
162+
/// If the event ID is `None`, it means there is no event ID returned by the
163+
/// server, so the sending has failed. If the event ID is `Some(_)`, it
164+
/// means the sending has been successful.
165+
///
166+
/// If no local event is found, a warning is raised.
167+
pub(super) fn update_event_id_of_local_event(
168+
&self,
169+
txn_id: &TransactionId,
170+
event_id: Option<OwnedEventId>,
171+
) {
158172
let mut lock = self.items.lock_mut();
173+
174+
// Look for the local event by the transaction ID.
159175
if let Some((idx, local_event_item)) = find_event_by_txn_id(&lock, txn_id) {
176+
// An event ID already exists, that's a broken state, let's emit an error but
177+
// also override to the given event ID.
160178
if let Some(existing_event_id) = &local_event_item.event_id {
161179
error!(
162180
?existing_event_id, new_event_id = ?event_id, ?txn_id,
@@ -168,12 +186,35 @@ impl<P: ProfileProvider> TimelineInner<P> {
168186
idx,
169187
Arc::new(TimelineItem::Event(local_event_item.with_event_id(event_id).into())),
170188
);
171-
} else if find_event_by_id(&lock, &event_id).is_none() {
172-
// Event isn't found by transaction ID, and also not by event ID
173-
// (which it would if the remote echo comes in before the send-event
174-
// response)
175-
warn!(?txn_id, "Timeline item not found, can't add event ID");
176189
}
190+
// No local event has been found.
191+
else if let Some(event_id) = event_id {
192+
if find_event_by_id(&lock, &event_id).is_none() {
193+
// Event isn't found by transaction ID, and also not by event ID
194+
// (which it would if the remote echo comes in before the send-event
195+
// response)
196+
warn!(?txn_id, "Timeline item not found, can't add event ID");
197+
}
198+
}
199+
}
200+
201+
/// Handle a back-paginated event.
202+
///
203+
/// Returns the number of timeline updates that were made.
204+
pub(super) async fn handle_back_paginated_event(
205+
&self,
206+
event: TimelineEvent,
207+
) -> HandleEventResult {
208+
let mut metadata_lock = self.metadata.lock().await;
209+
handle_remote_event(
210+
event.event.cast(),
211+
event.encryption_info,
212+
TimelineItemPosition::Start,
213+
&self.items,
214+
&mut metadata_lock,
215+
&self.profile_provider,
216+
)
217+
.await
177218
}
178219

179220
#[instrument(skip_all)]

crates/matrix-sdk/src/room/timeline/mod.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ use self::{
5454
};
5555
pub use self::{
5656
event_item::{
57-
AnyOtherFullStateEventContent, EncryptedMessage, EventTimelineItem, MemberProfileChange,
58-
MembershipChange, Message, OtherState, Profile, ReactionDetails, RoomMembershipChange,
59-
Sticker, TimelineDetails, TimelineItemContent,
57+
AnyOtherFullStateEventContent, EncryptedMessage, EventTimelineItem,
58+
LocalEventTimelineItemSendState, MemberProfileChange, MembershipChange, Message,
59+
OtherState, Profile, ReactionDetails, RoomMembershipChange, Sticker, TimelineDetails,
60+
TimelineItemContent,
6061
},
6162
pagination::{PaginationOptions, PaginationOutcome},
6263
virtual_item::VirtualTimelineItem,
@@ -371,10 +372,8 @@ impl Timeline {
371372
// Not ideal, but works for now.
372373
let room = Joined { inner: self.room().clone() };
373374

374-
let response = room.send(content, Some(&txn_id)).await?;
375-
self.inner.add_event_id(&txn_id, response.event_id);
376-
377-
Ok(())
375+
let response = room.send(content, Some(&txn_id)).await;
376+
self.inner.handle_local_event_send_response(&txn_id, response)
378377
}
379378
}
380379

0 commit comments

Comments
 (0)