This patch is trying to resolve the following issue:
When a local event is sent to the server, in case of an error, the
`Timeline::send` method just returned the error but it wasn't reflected inside
the `LocalEventTimelineItem` type itself. It's easy to loss this information.
So now, there is a new enum: `LocalEventTimelineItemSendState` with 3 states:
1. `NotSentYet`, when the local event has not been sent yet, it's theorically
the initial state,
2. `SendingFailed`, when the local event has been sent but it's failed!
3. `Sent`, when the local event has been sent successfully.
Therefore, the `LocalEventTimelineItem` struct has a new field: `send_state`.
The send state is managed by its `with_event_id` method which now receives an
`Option<OwnedEventId>` (prev. `OwnedEventId` directly):
* If it's `Some(_)`, then it means we got a successful response from the server
after the sending, so the send state is set to `Sent`,
* If it's `None`, then it means we got an error response from the server, so
the send state is set to `SentFailed`.
(A small change: The method `TimelineInner::add_event_id` has been renamed
`TimelineInner::update_event_id_of_local_event`.)
The `Timeline::send` still returns a `Result`, but the server's response is
passed to a new method: `TimelinerInner::handle_local_event_send_response`
(it's logically named after the `handle_local_event` method), which is
responsible to call `TimelineInner:update_event_id_of_local_event` (which was
previously called directly by `Timeline::send`).
And `TimelineInner::update_event_id_of_local_event` was already calling
`LocalEventTimelineItem::with_event_id`. So everything works like a charm here.
The local send state is closely managed by `LocalEventTimelineItem`, I hope it
will avoid state breakage as much as possible.
The sliding sync logic has another room type called `SlidingSyncRoom`.
This room type stores a limited amount of events in something called
`AliveRoomTimeline` in a in-memory cache. This room also gets persisted
to the store via another room type called `FrozenSyncRoom`.
These types are used when clients restore their view of the room, i.e.
when the user enters the room to look at messages.
When the client enters a room, a `Timeline` object will be created, but
it will be initially populated with events coming from
`AliveRoomTimeline`.
In a hot potato contest of who should be responsible to decrypt injected
events, everybody claims to be allergic to potatoes.
This patch modifies the `Timeline` constructor that populates the
timeline with events from the `AliveTimeline` to retry decryption on the
events that the `AliveTimeline` pushes into the `Timeline`.
Note that, because the `AliveRoomTimeline` never replaces encrypted
events with decrypted ones, every time the client enters/exits the room
events well get re-decrypted.
This is an omission from the spec where the subkeys are supposed to be
signed by the master key, but signing the master key wasn't mentioned.
This is still fine, since we always treated the master key and their
subkeys as a whole and never accepted one without the others.
To create an event next to the server, the event must be accompanied by
a transaction ID. When the server receives the event creation request, it
responds with a new event ID (which we will name `event_id_1`). Later on, when
a sync is done to the server, the server may respond with the transaction ID
and a new event ID (which we will name `event_id_2`).
The transaction ID is used to update the state of the local event. The event
ID received from the sync may ideally be the same as the one received by the
creation request's response.
Knowing that…
`EventTimelineItem` had a field: `event_id: Option<OwnedEventId>`. It was
`Some(event_id)` where `event_id` is the event ID responded by the server when
an event was created, i.e. it's `event_id_1`; otherwise it was `None`. This is
never `event_id_2`. Why?
Because `EventTimelineItem` has an other field: `key: TimelineKey`, which
represents the following states:
* `TimelineKey::TransactionId(OwnedTransactionId)`,
* `TimelineKey::EventId(OwnedEventId)`, where the event ID is `event_id_2`!
So it becomes obvious that `event_id_1` should be part of `TimelineKey`, not
`EventTimelineItem`. `TimelineKey` is where this transaction ID and event ID
logic is managed.
This patch updates `TimelineyKey::TransactionId` to be defined as:
* `TimelineKey::TransactionId { txn_id: OwnedTransactionId, event_id: Option<OwnedEventId> }`.
Why an `Option`? Because before receiving `event_id_1`, we may still want to
create a `TimelineKey`, the API must reflect that state.
So basically, `EventTimelineItem.event_id` is moved inside
`TimelineyKey::TransactionId`.
… rather than prepended, or added at a specific point as replacement for
an existing timeline item.
Previously, we would log lots of useless tracing events when retrying to
decrypt UTD items.