Having decrypted an event with a given megolm session, we need to check that
the owner of that session actually matches the sender of an event, otherwise
there is a danger of the sender being spoofed to make it look like it was sent
by another user.
Security-Impact: High
CVE: CVE-2025-48937
GitHub-Advisory: GHSA-x958-rvg6-956w
Internal Sentry reports tell us that enabling the busy_timeout seems to
have *increased* the number of "database is busy" errors, instead of
lowering those. As a result, we're going to disable the pragmas in all
the places where we enabled it before, and observe how the number of
"database is busy" errors evolves.
This correctly handles the reply fallback behavior:
- the behavior isn't changed for a live timeline,
- when a timeline is thread-focused, we will extract the `replied_to`
field if and only if the thread relation is *not* marked as behaving in
a fallback manner.
This makes it possible to distinguish actual in-thread replies.
In a "soon" future, threads have their own linked chunk. All our code
has been written with the fact that a linked chunk belong to *a room* in
mind, so it needs some biggish update. Fortunately, most of the changes
are mechanical, so they should be rather easy to review.
Part of #4869, namely #5122.
This patch renames `check_tombstone` to `check_room_upgrades`.
Then it rewrites it **entirely** to remove all false-positives and
false-negatives. More importantly, the room versions are no longer
involved: they can't be compared or ordered, they must be treated as
opaque values.
This new version of `check_room_upgrades` does a first path to check
predecessor-successor consistency. Then it does a second version to
detect loops. This new algorithm is robust to absent `m.room.create`
events. Making them mandatory is left to another patch.
More tests are added, especially to ensure that `m.room.create` cannot
be overwritten, and to ensure loops or inconsistent predecessors and
successors are correctly detected.
And add getters and setters. It makes it clear who are the external
readers/writers of the push actions, and it makes it impossible to
create a `TimelineEvent` out of thin air (since it now has a private
field).
There's been many segfaults happening in tests, while running the test
coverage for this specific crate. An issue has been opened on
cargo-tarpaulin's repository:
https://github.com/xd009642/tarpaulin/issues/1749
Until this is fixed or worked around, we'll disable coverage testing for
this specific crate.
This module only builds on non-wasm with the patched async-compat from
the workspace Cargo.toml's patch section, and it is only used by the ffi
crate. It is currently breaking the use of the SDK as a git dependency,
and would prevent the publishing of matrix-sdk-common (unless using
--no-verify, but then that would just break all users of the newly
published crates.io version).
This bug was introduced in
https://github.com/matrix-org/matrix-rust-sdk/pull/5089.
Signed-off-by: Jonas Platte <jplatte+matrix@posteo.de>
This helps in the case we want to observe the membership state changes - or some other info - for a room that's still not known so we can't just use `Client::get_room` to fetch it.
Addendum to https://github.com/matrix-org/matrix-rust-sdk/pull/5125 to
allow sending galleries from the FFI crate. This is the final PR for
galleries (apart from possible enhancements to report the upload status
in https://github.com/matrix-org/matrix-rust-sdk/pull/5008).
This is somewhat lengthy again, apologies. Most of the changes are just
wrappers and type mapping, however. So I was hoping that it's relatively
straightforward to review in bulk. Happy to try and elaborate on the
changes or break them up into smaller commits if that helps, however.
---------
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
This commit systematically replaces Send+Sync trait bounds throughout
the matrix-rust-sdk codebase to enable Wasm compatibility while
maintaining thread safety on native targets.
Key changes:
- Use SendOutsideWasm/SyncOutsideWasm traits instead of Send/Sync for
trait bounds
- Apply conditional compilation for error types and trait objects
- Update FFI trait definitions to use Wasm-compatible bounds
- Fix event handler and type alias definitions for cross-platform
compatibility
- Maintain existing functionality while enabling WebAssembly target
support
The SendOutsideWasm/SyncOutsideWasm traits are empty on Wasm (allowing
all types) and alias to Send/Sync on native targets, ensuring zero-cost
abstraction.
Files updated:
- All FFI bindings (30+ trait definitions)
- Core SDK error types and type aliases
- Event handler infrastructure
- Store and crypto abstractions
- UI service filters and sorters
- Timeline and authentication modules
<!-- description of the changes in this PR -->
- [ ] Public API changes documented in changelogs (optional)
<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by: Daniel Salinas
---------
Signed-off-by: Daniel Salinas <zzorba@users.noreply.github.com>
Co-authored-by: Daniel Salinas <danielsalinas@Daniels-MacBook-Pro-2.local>
Co-authored-by: Daniel Salinas <danielsalinas@daniels-mbp-2.myfiosgateway.com>
The `ProcessedToDeviceEvent::Decrypted` variant now also have an
`EncryptionInfo` field.
The enum variant changed from `Decrypted(Raw<AnyToDeviceEvent>)` to `Decrypted {
raw: Raw<AnyToDeviceEvent>, encryption_info: EncryptionInfo) }`
Mechanical move from tokio::spawn to matrix_sdk_common::executor::spawn
that has support for Wasm platforms. On non-Wasm, this shim defaults to
tokio::spawn.
The actual code useful in `with_events_mut` and used in that function
was to propagate the changes to the store and propagating diffs to
observers. It often striked me as hacky to use this method to do that,
so instead I'm proposing here to inline the useful bits. That way,
`with_events_mut` is now clearly called only in two cases: after a sync,
or after a successful network back-pagination.
This patch adds the `check_tombstone` response processor to
detect invalid state with room upgrades. One can check the new
`InconsistentTombstonedRooms` error to learn more about the detected
patterns.
If the vec of actions is defined (Some) but empty, then it means we
could determine there are no push actions. It is a slight optimization
to not serialize them, in this case; otherwise, this can result in many
serialized empty action vector, in the event cache's persistent storage.
When the user does an `/invite`, if the target user doesn't start with
an `@`, try expanding it as a user on the local server.
This makes it much easier when repeatedly testing inviting!
Rather than always writing the logs to `/tmp`, write them to the session
directory. The session directory defaults to `/tmp` so by default this
will do the same as before, but if you override the session path on the
commandline, the logs will get stored alongside the stores and caches.
This is particularly useful when running two instances of multiverse,
and you want them to put their logs in different places.
The .boxed() method requires a Send trait that makes it
unusable on Wasm platforms. This re-exports the existing StreamExt,
while providing a new extension for the wasm family of targets.
This is an implementation of an update to MSC2762 (https://github.com/matrix-org/matrix-spec-proposals/pull/4237). It changes the widget driver to split state updates out into an `update_state` action and use the `send_event` action exclusively for forwarding timeline events. Accordingly, `read_events` now always reads from /messages, never the state store.
It's >100 bytes large and often optional, so it makes sense to put it
on the heap to reduce the size of structs with such optional fields,
and the stack size of functions with such optional parameters.
It's also cloned in a couple places in the UI crate, so it probably
makes sense to just always refcount it.
This started as a clippy suggestion to box PendingEdit inside
AggregationKind::Edit.
Part of #3716
I did notice that the `sender` and `member` methods have some overlap in
what values get set for the "sender" and "state key", and I tried to
make sure that in my changes to use `EventFactory` the original event
configuration is being replicated, so please do double-check me on that
note in particular.
Signed-off-by: Yousef Moazzam <yousefmoazzam@hotmail.co.uk>
The test was ignored since the functionality was only implemented for
the memory and SQLite store. This caused a bug in the SQLite
implementation to go unnoticed.
Let's just disable it for WASM since this is the only place where we
didn't yet implement the necessary methods.
The status code is usually returned by Cloudflare to indicate an unknown server error, so we should cancel the upload and let the user retry if they want to.
This patch removes `RoomTombstoneInfo` and replaces it by
`SuccessorRoom`. This patch renames `RoomInfo::tombstone` to
`RoomInfo::success_room`.
This patch also implements `Room::successor_room()` and
`Room::predecessor_room()`, and adds documentation.
This allows applications to decide what they'd like to do if there isn't a value present. It allows the application to decide what the default should be.
This patch adds the new `deduplicate_versions`. This new filter will
filter out room versions that are outdated. Only the “active” versions
are kept.
A room version is considered active if and only if:
* the room is joined and has no successor,
* the room is joined and has a successor room that is invited or knocked,
* the room is left, invited, banned or knocked.
All other rooms are filtered out.
This patch extracts a bit of code from `dispatch` in a new response
processor: `dispatch_room_member`. The idea is to clarify the content of
`dispatch` itself.
This patch moves the insertion of `new_user_ids` in
`updated_members_in_room` after the use of `new_user_ids` by
`update_or_set_if_room_is_newly_encrypted`. By moving it after, it saves
the need to clone it entirely, thus saving memory allocations.
This patch renames `dispatch_and_get_new_users` to `dispatch`. This
response processor no longer returns the new user IDs, but they are
written in a mutable reference argument. This argument is
typed by a new private trait: `NewUsers`. This trait is implemented on
`BTreeSet<OwnedUserId>` and on `()`. It helps to avoid allocations when
the new users are not needed.
This reproduces the issue originally described, where it wasn't possible
to run a /members query in an event handler, because the sync lock was
taken at this point.
This is a dangerous operation, and requires that the sync service must
be stopped while we're touching this. Since this is an internal method,
that shouldn't be used in most clients anyways (as it usually papers
over actual issues happening elsewhere, on the server for instance), I
kept it simple with a scary doc comment explaining the preconditions,
but we could assert them at runtime, with a little bit more effort.
It's just a room, now! Since there were some users of the
`latest_event()` that returned an `EventTimelineItem`, I kept this
method as a method in the Room trait extension that's in the UI crate,
so it's still convenient to use.
This patch updates `Room::leave` to not early return when the server
returns a 403 error code on `/leave`. Indeed, if the user doesn't have
the permissions to leave a room, it's impossible for they to leave it.
Let's consider it's fine to ignore this particular error and continue
the process of leaving the room.
This patch adds the `predecessor` and `no_predecessor` methods on
`EventBuilder<RoomCreateEventContent>`. This is helpful to configure the
`predecessor` field.
This patch fixes `EventFactory::create` where the `m.room.create` wasn't
created as a state-event (the `state_key` field was missing).
Also, it uses the `creator_user_id` in the `sender` field if no sender
was given.
First off, this patch renames `Room::tombstone` to
`Room::tombstone_content` (to be consistent with other methods, such as
`Room::create_content`).
Second, this patch adds the `Room::successor_room` and
`Room::predecessor_room` methods, along with the `SuccessorRoom` and
`PredecessorRoom` types. This naming more or less comes from the Matrix
specification:
- the term _predecessor_ is part of the specification,
- the term _successor_ isn't present _per se_, the words _replacement
room_ are used instead, but I prefer _successor_ as it brings a nice
symmetry with _predecessor_.
The widget Driver should be able to send and receive to-device events.
This is useful for element call encryption keys.
This PR focusses on the widget driver and machine logic. To
send/communicate the events from the widget to the driver.
It skips any encryption logic. Some of the encryption logic will be part
of crypto crate and the code in the widget driver crate should be kept
minimal once the crypto crate is ready.
---------
Co-authored-by: Valere <bill.carson@valrsoft.com>
This behaviour was added only at the `RoomPreview::leave` method, but since we're slowly moving away from it we should move the forget action to the `Room::leave` method instead
On Android, we should use rustls instead of native-tls; this requires
unsetting the default features of the `sentry` crate, and specifying
them by hand instead.
For consistency, I've done the same for the non-android sentry
dependency.
This patch moves the `Room::get_member_hints` method inside the newly
created `display_name` module. That way it is isolated from the rest of
the codebase.
This patch moves the `Room::has_active_room_call` and
`Room::active_room_call_participants` methods into the new `call`
module. This patch also moves the associated tests in this new module.
This patch moves the `Room::*knock*` methods into the new `knock`
module.
The idea is to group API by “theme” to get smaller modules and more
organised code.
This patch moves the `Room::state` method, along with the ``RoomState`
and `RoomStateFilter` types into the new `state` module. This patch also
moves the tests in this new module.
The idea is to group API by “theme” to get smaller modules and more
organised code.
This patch merges the `rooms/normal.rs` file into `rooms/mod.rs`.
The name `normal` is present for historical reasons that no longer stand
today. This is no needed anymore. Let's simplify the modules.
This patch moves everything related to the `Room` latest event API
inside the new `latest_event` module. This patch also moves the tests.
The idea is to get a smaller `rooms::normal` module, and to clarify the
code by grouping `Room` APIs by “theme”.
This patch moves the Room::is_favourite` and `::is_low_priority`, along
with the `RoomNotableTags` into the new `tags` module. This patch also
moves the tests in this new module.
The idea is to group API by “theme” to get smaller modules and more
organised code.
This patch moves the `Room::encryption_state()` and
`Room::encryption_settings()` methods, and the sibling types, into a new
`encryption` module. This patch also moves the tests in this new module.
The idea is to group `Room` API by “theme” in modules, to clarify the
code.
This patch moves the `Room::display_name()` method, and all the
siblings, into a new `display_name` module. It includes types like
`RoomDisplayName`, `UpdatedRoomDisplayName`, `RoomSummary` etc. This
patch also moves the tests in this new module. The idea is to group
`Room` API by “theme” in modules, to clarify the code and to make the
big `rooms::normal` module smaller.
This patch moves the `Room::subscribe_info`, `::clone_info` and
`::set_room_info` methods from the `rooms::normal` module to the
`rooms::room_info` module. This patch also moves the tests related to
room info inside `room_info`.
This patch explains why having `m.room.create` is necessary. It's not
only about the room previews, but also about the room versions, and thus
the tombstoned rooms.
This patch renames the `RoomInfo::version` field to
`data_format_version` to avoid all possible confusion with the
`room_version` (from `m.room.create`).
If the replied-to event is an aggregation, the
`RepliedToEvent::try_from_timeline_event` will now return `Ok(None)`,
and the caller may handle this as they please.
In the FFI layer, this will be filled with an error message indicating
that the event is unsupported.
As per the plan defined in #4718:
```
the room_list_service::room::RoomInner shouldn't make use of its inner timeline;
it's only used in a direct getter, or to compute the latest room event, but it's not working
as intended, since local echoes aren't properly displayed in the room list.
This non-working feature can be removed, in favor of #4112
```
Updates the unread flag or the room in `Timeline::send_single_receipt()`
and `Timeline::send_multiple_receipts()` if the room is marked as unread
and the receipts are unthreaded.
Updates it also in `Timeline::mark_as_read()`, even if there is no
latest event ID.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Updates the unread flag or the room in `Room::send_single_receipt()` and
`Room::send_multiple_receipts()` if the room is marked as unread and the
receipts are unthreaded.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This makes it possible to handle reactions/redactions/edits/etc. on
non-live timelines. As a result, the pinned and focused timelines will
now get live reactions/redactions and so on. This makes it possible to
also have the thread timelines handle those live events, although it's
unclear how it will pane out in the end, when the event cache is also
involved.
This can be done by splitting the handling of the msgtype/mentions from
the handling of the `relates_to` field, requiring a few API changes here
and there.
We only need the edit_json if we're about to save the edit aggregation.
Likewise, if there's no current event id (i.e. the event being handled
is a local echo), then we don't need to even try to extract anything
from the bundle information.
The poll events's `related_to` field is a `RelationWithoutReplacement`,
while the two others are `Relation<C>`, where `C` is the event content
type (in case it was replacement). As a matter of fact, we try
converting the `Relation<C>` into a `RelationWithoutReplacement` (which
unfortunately requires cloning, which is wasteful if the relation was a
replacement indeed), and then we can use a single function to extract
the reply information and thread root info, for all three.
There are two reasons for this.
Firstly. we've already done a bunch of work to map `SenderData` into a
`VerificationState`, and the decision tree from `VerificationState` to
allow/reject is simpler than going from `SenderData`, even if we have to
fudge it a bit to get the "legacy" flag. (Note that it allows us to get
rid of an `unreachable!` panic.)
Secondly, `VerficationState` represents the state of an *event*, whereas
`SenderData` is about the session as a whole. A session can be fine,
whilst events (claiming to be) encrypted with it can be suspect. What we
want here is to check a specific message. Currently, this doesn't make
any functional difference, but conceptually it's cleaner to check the
`VerificationState`.
Note that there are a bunch of tests for this method in
`matrix-sdk-crypto/src/machine/tests/decryption_verification_state.rs`,
called `test_decryption_trust_requirement`.
This patch removes the `SlidingSync::rooms` field. A cascade of removal
happens, and many part of the code is simplified. The most notable is
`FrozenSlidingSync`.
This patch
- Updates Ruma to use the improved MediaPreviewConfig event type that
also supports a `Default` for the content type
- Implemented a way to observe the stable and unstable values of the
event and return the used one accordingly, if no one is present the
default will be used
- Set the value (will only use unstable type for now)
This patch removes the `RoomInfo::prev_room_state` field, along with the
`RoomInfo::prev_state` method.
This data was introduced during the knocking project but was never used,
and is not used nowadays. Let's remove it.
This is used to configure EC on devices that need to control media outputs on their own (android, ios).
If set, EC will display a list of devices provided by the app.
This patch adds the `m.room.tombstone` state event to the list of
events in `required_state` used by the `RoomListService`. The goal is to
offer the possibility for the consumers to know whether a room has been
tombstoned or not.
The `read_receipts::compute_unread_counts` function needs the _previous
events_ to compute the read receipt correctly. These previous events
were store in `SlidingSyncRoom::timeline_queue`. Since the removal of
`timeline_queue` in the previous patches, this patch uses the Event
Cache to fetch them. It only uses events that are loaded in memory.
This is as correct as the prior behaviour, even this is still incorrect
since it doesn't back-paginate to get a better view. This is for
later. The goal of this patch is to restore the same behaviour, without
`timeline_queue`.
The main problem is that read receipts are computed in
`matrix-sdk-base`, and that the Event Cache lives in `matrix-sdk`. Thus,
we change the `SlidingSyncResponseProcessor` to handle read receipt
in particular.
The
`matrix_sdk_base::response_processors::rooms::msc4186::extensions::dispa
tch_ephemeral_events` function has been split in
two methods `dispatch_typing_ephemeral_events`, and
`dispatch_receipt_ephemeral_event_for_room`. The workflow has been a
little bit redesigned to fit in the new `SlidingSyncResponseProcessor`
constraints.
This patch moves one test from `matrix-sdk-base` into `matrix-sdk`,
because to compute the read receipt, the Event Cache must be
enabled/listening to sync updates.
`RoomEventCache::subscribe` returns the set of events + the
`RoomEventCacheListener`. However, creating this listener isn't
cheap, especially dropping it. That's why this patch creates
`RoomEventCache::events` to replace `subscribe` when the listener is
not necessary.
This patch reduces the sizes of `Verification` from 376 bytes to
16 bytes, and `VerificationRequestState` from 424 bytes to 96 bytes.
It also reduces the size of a couple of other types in the same vain.
They have never been set and there was no way of telling if stickers and polls belong on a thread or come in reply of any other message.
This patch also exposes methods for setting these relations on the event factory level.
This moves the logic from `Room::join()` to these two methods. This is
isofunctional, because `Room::join()` does call into
`Client::join_room_by_id()` internally.
The then() function can be used with booleans and futures to execute a
piece of code if the boolean is true or once the future is completed.
In contrast, the then() function in the widget driver is not executed
immediately. Instead it only adds a callback that is later on executed
by the widget driver.
… that allows building a timeline instance specific to a particular
thread root.
Creating a timeline in this mode will start by backpaginating root event
relations with `num_events` and automatically insert the thread root
event when reaching the end. It will include
`RelationsOfType(RelationType::Thread)` but also recurse over the
retrieved events to fetch reactions.
It will not however react to new events received over sync or that the
user sends (for now).
This patch will also help incrementally deliver the upstream client
support for creating such a timeline.
Part of #4833 (meta #4869).
Under some very particular circumstances, the "database is locked" error
can still happen, even in WAL mode, even if the database connection is
not being upgraded from a read transaction to a write transaction.
We *think* this might be the reason behind errors like
github.com/element-hq/element-x-ios/issues/3582, so we're enabling the
sqlite busy_timeout, which will retry the operation after a short sleep,
until the busy timeout is being hit.
This variant will be used to cause side-effects to existing timeline
items, because the event they relate to is for an aggregation
(edit/reaction/etc.).
This is used here for reactions.
This patch updates `EventHandler` to use the correct regions where
appropriate, thus reducing the complexity of the code, and removing
classes of bugs.
In the case of `Flow::Remote { position: TimelineItemPosition::At { …
}}`, we no longer need to skip the local timeline items, and to handle
the presence of the `TimelineStart` timeline item. The code is less
complex.
In the case of `Flow::Remote { position: TimelineItemPosition::End { …
}}`, that's exactly the same at the previous case.
In the case of `recycle_local_or_create_item`, the `try_fold` approach
is replaced entirely with a simple `iter_locals_region`, reducing the
size of the comments explaining the code, reducing the complexity of the
code, and reducing the surface of bugs.
This patch updates `TimelineMetadata` to work on the _remotes_ region
only, excluding the _start_ and the _locals_ regions. It helps to reduce
the risk of inserting items in an incorrect regions.
This patch also removes on more `rfind_event_by_id` usage, which is
nice.
This patch updates `ReadReceiptTimelineUpdate` to work on the _remotes_
region only, excluding the _start_ and the _lcoals_ regions. It helps
to reduce the risk of inserting a `ReadMarker` inside the _start_ or the
_locals_ regions.
This patch updates `DateDividerAdjuster` to work on _remotes_ and
_locals_ regions only, excluding the _start_ region. It helps to reduce
the risk of inserting a `DateDivider` inside the _start_ region.
This patch also uses the new `push_date_divider` method, which provides
a couple of invariants.
This patch defines a new concept in the `Timeline`: Regions.
The `ObservableItems` holds all the invariants about the _position_ of the
items. It defines three regions where items can live:
1. the _start_ region, which can only contain a single `TimelineStart`,
2. the _remotes_ region, which can only contain many `Remote` timeline
items with their decorations (only `DateDivider`s and `ReadMarker`s),
3. the _locals_ region, which can only contain many `Local` timeline items
with their decorations (only `DateDivider`s).
The `iter_all_regions` method allows to iterate over all regions.
`iter_remotes_region` will restrict the iterator over the _remotes_
region, and so on. These iterators provide the absolute indices of the
items, so that it's harder to make mistakes when manipulating the indices of
items with operations like `insert`, `remove`, `replace` etc.
Other methods like `push_local` or `push_date_divider` insert the items
in the correct region, and check a couple of invariants.
This patch implements the `has_local` method on
`ObservableItemsTransaction`, which is way faster than the previous the
previous solution which was to iterate over all items to find at least
one local timeline item.
This patch adds the `push_local` method on `ObservableItemsTransaction`
to add semantics and hardcode the invariant in a single place for the
different timeline items.
This patch adds the `push_timeline_start_if_missing` method on
`ObservableItemsTransaction` to add semantics and hardcode the
invariant in a single place for the different timeline items.
This patch adds the `--generate-link-to-definition`
argument to `rustdoc` for `docs.rs`. This is using
https://github.com/rust-lang/rust/pull/84176 to add links in the source
code page.
If we already have cross-signing details for the owner of the device at the
point we receive the to-device message, we should store that rather than just
the device info.
create a new method `SenderData::from_device` which does the last few steps of
`SenderDataFinder`: turns out we want it elsewhere. Add some tests to test that
functionality in isolation.
- Doc comment for the SQLite-based state store incorrectly referred to
it as a "cryptostore".
- Consistent capitalisation of SQLite.
- Consistent use of indefinite article "an" before SQLite.
- Fix line length.
Imagine we have the following events:
| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0 | !r0 | 42 | 0 |
| $ev1 | !r0 | 42 | 1 |
| $ev2 | !r0 | 42 | 2 |
| $ev3 | !r0 | 42 | 3 |
| $ev4 | !r0 | 42 | 4 |
`$ev2` has been removed, then we end up in this state:
| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0 | !r0 | 42 | 0 |
| $ev1 | !r0 | 42 | 1 |
| | | | | <- no more `$ev2`
| $ev3 | !r0 | 42 | 3 |
| $ev4 | !r0 | 42 | 4 |
We need to shift the `position` of `$ev3` and `$ev4` to `position - 1`,
like so:
| event_id | room_id | chunk_id | position |
|----------|---------|----------|----------|
| $ev0 | !r0 | 42 | 0 |
| $ev1 | !r0 | 42 | 1 |
| $ev3 | !r0 | 42 | 2 |
| $ev4 | !r0 | 42 | 3 |
Usually, it boils down to run the following query:
```sql
UPDATE event_chunks
SET position = position - 1
WHERE position > 2 AND …
```
Okay. But `UPDATE` runs on rows in no particular order. It means that
it can update `$ev4` before `$ev3` for example. What happens in this
particular case? The `position` of `$ev4` becomes `3`, however `$ev3`
already has `position = 3`. Because there is a `UNIQUE` constraint
on `(room_id, chunk_id, position)`, it will result in a constraint
violation.
There is **no way** to control the execution order of `UPDATE` in
SQLite. To persuade yourself, try:
```sql
UPDATE event_chunks
SET position = position - 1
FROM (
SELECT event_id
FROM event_chunks
WHERE position > 2 AND …
ORDER BY position ASC
) as ordered
WHERE event_chunks.event_id = ordered.event_id
```
It will fail the same way.
Thus, we have 2 solutions:
1. Remove the `UNIQUE` constraint,
2. Be creative.
The `UNIQUE` constraint is a safe belt. Normally, we have
`event_cache::Deduplicator` that is responsible to ensure there is no
duplicated event. However, relying on this is “fragile” in the sense it
can contain bugs. Relying on the `UNIQUE` constraint from SQLite is more
robust. It's “braces and belt” as we say here.
So. We need to be creative.
Many solutions exist. Amongst the most popular, we see _dropping and
re-creating the index_, which is no-go for us, it's too expensive. I
(@hywan) have adopted the following one:
- Do `position = position - 1` but in the negative space, so
`position = -(position - 1)`. A position cannot be negative; we are
sure it is unique!
- Once all candidate rows are updated, do `position = -position` to move
back to the positive space.
'told you it's gonna be creative.
This solution is a hack, **but** it is a small number of operations, and
we can keep the `UNIQUE` constraint in place.
This patch updates the `test_linked_chunk_remove_item` to handle
6 events. On _my_ system, with _my_ SQLite version, it triggers the
`UNIQUE` constraint violation without the bug fix.
This is necessary because the `NotificationClient` runs a sliding sync loop and the retrieved data isn't pushed back into the parent client stores (because of cross process locking shenanigans).
This will be used with the previously introduced `org.matrix.msc3401.call.member` required state to check whether a room still has an ongoing call before showing the ringing screen.
This is apparently the right way to do it, both because some HS expect only this mimetype and also so we don't leak the mime type of the encrypted media.
This commit simplifies the filter public api.
Rethinking the public api we only need:
- to know if events can be sent based on the capabilities
- to know if events can be sent to the widget (read) based on the capabilities
- if it even makes sense to sent a cs api read request or if all possibly returned events
would not match the type.
To simplify the code in the machine it also made sense to add `From` implementation
to the FilterInputs instead of gathering the relevant data from all kinds of Raw events.
The new api is simpler:
All possible events we need to check can be converted into filter inputs (using `into()`).
`capabilites` has two allow_read/allow_send that consume filter inputs.
`capabilites` can be asked if there is any filter for specific event types
to allow not send unnecassary requests.
This is (sadly) required since we cannot do `as_str()` for `TimlineEventType` and other `ruma` event types.
So we need to use `String`. We also never used them more specifically than strings.
Previously, the `share_strategy` was breaking the abstraction provided
by `OutboundGroupSession` by accessing its internal fields in an
inconsistent and adhoc way. Now all fields are private and a proper
abstraction was added to access the required state in a consistent API.
This patch moves the `session_id` field from EncryptionInfo to
AlgorithmInfo::MegolmV1AesSha2 as it is specific to Megolm. We provide
transparent migration of the serialized data from one format to the other.
In the future we plan to reuse `EncryptionInfo` for to_device decryption
(using olm not megolm). So megolm session_id should move to algorithm
specific data.
This method had a confusing name: it didn't receive a key bundle, but
rather the data *about* a key bundle.
Remove the unused `sender_key` parameter while we are at it: we use the
embedded (and already-checked) `event.sender_device_keys` here.
This avoids conditions where a key may be shared with a device only
after we decided that it is fine to reuse (and not rotate) the session
based on the wrong assumption that that particular device does not have
the keys.
Signed-off-by: Niklas Baumstark
[niklas.baumstark@gmail.com](mailto:niklas.baumstark@gmail.com)
Previously, `is_session_overshared_for_user` did not take into account
that `shared_with_set` also contains withheld device IDs who explicitly
have never received the session keys. This would lead to it mistakenly
determining oversharing for those devices for every event being sent in
the presence of blacklisted/withheld devices in the room, and rotating
the group session accordingly.
The fix is to correctly exclude devices with `ShareInfo::Withheld` from
the enumeration.
Signed-off-by: Niklas Baumstark niklas.baumstark@gmail.com
This patch updates the sending side of the `sender_device_keys` field
introduced in MSC4147.
Since the MSC got merged, we're switching from the unstable identifier
to the stable one.
A couple of snapshot tests were added modified to make this happen.
This PR is a revived version of:
https://github.com/matrix-org/matrix-rust-sdk/pull/4707 since it is now
possible to easily add wasm support thanks to:
https://github.com/matrix-org/matrix-rust-sdk/pull/4572
Using the `executer::spawn` will select `tokio::spawn` or
`wasm_bindgen_futures::spawn_local` based on what platform we are on.
~~They behave differently in that `tokio` actually starts the async
block inside the spawn but the wasm `spawn` wrapper will only start the
part that is not inside the `async` block and the join handle needs to
be awaited for it to work.~~
This has now changed with:
https://github.com/matrix-org/matrix-rust-sdk/pull/4572.
Now they behave the same and this PR becomes a very simple change.
Rather than attempting to trigger Alice's encryption sync loop with an incoming
message from Bob, instead have Alice send a message once Bob has joined the
room.
Simplifies the `ProcessedToDeviceEvent` enum by converting its variants to tuple variants.
This change improves code readability and conciseness by removing the need for named fields within the variants.
This patch introduces a temporary hack.
So here is the thing. Ideally, we DO NOT want to emit this reason.
It does not makes sense. However, all notable update reasons
are not clearly identified so far. Why is it a problem? The
`matrix_sdk_ui::room_list_service::RoomList` is listening this stream
of [`RoomInfoNotableUpdate`], and emits an update on a room item if
it receives a notable reason. Because all reasons are not identified,
we are likely to miss particular updates, and it can feel broken.
Ultimately, we want to clearly identify all the notable update reasons,
and remove this one.
This patch creates the `room::display_name::update_for_rooms` response
processor. It also creates the `changes::save_only` response processor.
Finally, this patch uses both to compute the new display name for all
rooms and save them, for sliding sync only.
This patch extracts the “save” part of the `save_and_apply` response
processor into its own function. Thus we have `save_changes` (new) and
`apply_changes` that are used by `save_and_apply`.
This patch introduces a new enum: `UpdatedRoomDisplayName`, which
will be used to know if a room display name is different or not when
computing the room display name.
…that holds information on the thread the given item is the root of
- it holds the latest event content and sender at the moment but will
hold more information in the future e.g. number of replies, if it's
unread etc.
- the field is not currently being populate but is delivered earlier so
it can power shipping the UI side on the embedders
See #4891 that shows a case where we should have saved the
previous-batch token, and instead ditched it, in the previous version.
Changes include:
- moving the code deciding to keep or ditch the `previous-batch` token
into `append_events_locked`.
- tweak the condition to ditch, so that the `previous-batch` token is
ditched only if we didn't have events in the event cache in the first
place, in addition to having storage + the timeline not being marked as
limited explicitly.
Credits to @zecakeh for the test case.
This patch is twofold:
1. it transforms the `&mut` to a `&` for the room account data in the
sliding sync flow, which allows to remove one big clone!
2. it adds the `room_account_data` response processor.
This patch creates the new `room::msc4186::extensions::ephemeral_events`
response processor.
Ideally we would like to merge this with `ephemeral_events`, but they
are a bit different. Let's see how it evolves in the future.
This patch uses the `room::Room` structure in `room::sync_v2` to
reduce the number of arguments of the `update_joined_room` and the
`update_left_room` processors.
This patch uses the `room::Room` structure in
`room::msc4186::update_any_room` to reduce its number of arguments. It
results in the removal of te `allow(clippy::too_many_arguments)`.
This patch removes the `SessionMeta` argument of
`room::msc4186::update_any_room`. Tracking its usage, it reveals that
providing a `UserId` is sufficient. Happily, we already provide a
`UserId`, hence making `SessionMeta` useless here.
This patch renames the fields in `RoomUpdate`: `join` becomes `joined`,
`leave` becomes `left`, `invite` becomes `invited`, to match their
associate type.
This patch simplifies the flow of `membership` when the room is an
invited room.
Previously, we were creating the room as `Invited`. Then, later
overriding it to `Knocked` if we found it was such a room. Otherwise, we
were overriding it again to `Invited`. Well. Now the flow is simpler.
This patch extracts the `BaseClient::process_sliding_sync_room` method
into the new `msc4186::update_any_room` response processor. So far, this
is purely a code move, without any changes (modulo method-to-function
transformation).
With `BaseClient:process_sliding_sync_room` comes
`BaseClient::process_sliding_sync_room_membership`,
`BaseClient::handle_own_room_membership`, `process_room_properties` and
`cache_latest_events`.
This patch removes the re-exports of `Notification` and `E2EE` in
`timeline::builder`. Let's make things simple now that they are used
outside the `timeline` processors.
This patch groups arguments behind the `Notification` struct
if it makes sense. This patch also uses the new method
`Notification::push_notification_from_event_if` method to replace
duplicated code.
This patch moves the `timeline::builder::Notification` into
its own module, `notification`. This patch adds two methods:
`push_notification` and `push_notification_from_event_if`.
This patch adds two `From` implementations on
`RawAnySyncOrStrippedTimelineEvent` to create the correct variant of
this enum. This is useful when we get generic types and want to build
this type.
This patch creates the `update_left_room` processor, extracted from the
sync v2 flow.
I've noticed that `new_user_ids` is not used, so it has been put behind
a `_` variable for the moment, but some computations have been removed.
We need to clean this user ID flow.
This patch moves the `timeline::builder::E2EE` type into the `e2ee`
module. Gathering these 3 E2EE values in the same type was a good idea,
and is now applied to more places in the response processors.
This patch makes `Context` to derive `Default`. The `new` constructor
also no longer takes a `RoomInfoNotableUpdates`, since it was always
used with a default value, it generates this value by itself.
This patch removes all mentions of `include_heroes`. This field isn't
part of the MSC4186. We have the `test_compute_heroes_from_sliding_sync`
which continues to pass, everything fine on that side. There is no
mention of `include_heroes` in Synapse at the time of writing. It seems
to be an artifact from the sliding sync proxy experiment.
This patch moves the `state_events::dispatch_and_get_new_users`
processor inside the `state_events::sync` module. Why? Because a similar
processor for `state_events::stripped` is about to be created.
MSC4147 added a `sender_device_keys` property to olm-encrypted to-device
messages, with recommendations about checking the values in that propety. We do
(most of?) those checks for `m.room_key` messages today, but not other types of
to-device message.
MSC4147 added a `sender_device_keys` property to the plaintext of *all*
olm-encrypted events. 03d4a30eb added the field to `DecryptedOlmV1Event`, but
due to Reasons, there is an almost-parallel struct `ToDeviceCustomEvent` which
is used for event types other than the 4 we have content types for.
To complete the set, let's add the field to `ToDeviceCustomEvent`.
This patch tries to clarify the processors in `state_events` by
putting them in two modules: `sync` and `stripped`, along with a bit
of renaming:
- `collect_sync` becomes `sync::collect`,
- `collect_sync_from_timeline` becomes `sync::collect_from_timeline`,
- `collect_stripped` becomes `stripped::collect`.
I believe this is an improvement.
This patch does the following things:
1. moves the `BaseClient::handle_timeline` method as the
`timeline::build` response processor.
2. moves the `BaseClient::update_push_room_context` method as a private
function of the `timeline` response processor module,
3. moves the `BaseClient::get_push_room_context` method as a public
function of the `timeline` response processor module.
The scope of the `timeline::build` processor is a bit too broad, but at
least the number of methods on `BaseClient` are greatly reduced.
This patch creates a new `verification::process_if_candidate` response
process. The idea is the check whether a `AnySyncTimelineEvent` suits to
be a verification event that must be processed.
This piece of code was repeated in three different places in the code.
Now it's unique.
This patch removes the `ignore_state_events` argument from
`BaseClient::handle_timeline`. This method no longer handles state
events. Consequently, the `user_ids` and `ambiguity_cache` arguments are
also removed.
This patch updates the flow to use the new
`state_events::collect_sync_from_timeline` processor, and to re-use the
`state_events::dispatch_and_get_new_users` processor.
The positive impact of this patch is that it re-uses existing code
(hurray). However, the downside is that state events are deserialized
twice for the moment.
This patch extracts the `BaseClient::handle_state` method as a new
response processor named `state_events::dispatch_and_get_new_users`.
It appears that we can do something more elegant with the returned new
users. See the next patch.
This patch rewrites `e2e::decrypt::sync_timeline_event` to avoid calling
a `verification` twice with the same arguments, and to avoid a string
allocation (the `to_string`).
Also, I wasn't comfortable with the `starts_with` which wasn't included
a trailing `.`. At least now we rely on strongly typed event type.
This will hold the info for both the room member whose sender id was provided and the sender of the `m.room.member` event from which the `RoomMember` is built.
We don't need to list the `server_versions` every time we do an http
request. Further, `config` is listed under both `skip` and `fields`, which ends
up being a no-op. I don't think it's very useful (and is quite noisy), so
let's remove it.
In parallel to a sliding sync request, we also check for and send pending outgoing
requests from the crypto stack. Currently, these drop the tracing span, which
loses valuable data. We should propagate the span.
We also add an extra layer of instrumentation so that we can differentiate
between the results of the sliding sync itself, and the outgoing requests.
Currently, if you have two clients both syncing away inside the same process,
it's approximately impossible to see which logs belong to which client. It
would be much better if we could use a tracing span to distinguish the two
clients.
I expect this to be mostly useful in integration tests, but it might be useful
elsewhere too.
This reduces the framerate from ~62fps to 10fps.
This is a workaround for a problem in my terminal, so apologies for inflicting
it on everyone else, but here we are, and 10fps seems like it should be enough
for anyone.
The problem in question is specifically when I try to select some text by
dragging the mouse (eg, to copy a generated recovery key). If I start a drag,
but a redraw happens before the mouse has moved [a certain distance?], then the
drag doesn't work, and nothing gets selected. By reducing the framerate, I have
a much better chance of successfully starting a drag.
Currently, `h` and `l` are intercepted by the parent view to change tab,
meaning it's impossible to enter a recovery key which contains those
characters.
The fix here is very blunt: it just disables `h` and `l` for tab-changing. I
considered making it dependent on which tab is open, or what's going on in the
'Encryption' tab, but given you need to know about the alternatives (tab/cursor
keys) to switch away from the Encryption tab, I don't think that makes sense.
This patch moves the `handle_room_account_data` method as the new
`account_data::for_room` response processor.
Instead of taking the `BaseClient` to fetch the room in `on_room_info`,
it now takes a `BaseStateStore`, which is safer and more straight to
the point.
This patch changes `AccountDataProcessor` to
`processors::account_data::global`. The next patch will introduce a
per-room account data processor, hence the renaming to `Global` to make
the difference between the twos.
This patch renames a couple of variables because it's important
to understand that those stripped state events are coming from the
`invite_state` value of a sliding sync response. This is a pretty
important detail.
This patch creates the `state_events::collect_sync`
and `collect_stripped` response processors. It
removes the `BaseClient::deserialize_state_events` and
`deserialize_stripped_state_events` methods. It also removes a couple of
`Vec` allocations and a couple of clones.
This patch creates the `changes::save_and_apply` response
processor. It consists of moving `BaseClient::apply_changes` plus
the code that is always around. This patch helps to remove the
`BaseClient::load_previous_ignored_user_list` method.
This patch moves the `handle_room_member_event_for_profiles`
function inside the collection of response processors under the name
`profiles::upsert_or_delete`.
Reduce the size of the tuple that this thing returns by defining a new result
type.
I haven't put the `share_infos` in the struct, because I'm going to reuse the
same struct for another method where `share_infos` aren't needed.
This is needed to identify the event as being in a thread, and to reply
to it inside the thread instead of in the room's timeline.
<!-- description of the changes in this PR -->
- [ ] Public API changes documented in changelogs (optional)
<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by:
This allows us to view the debug screen at the same time as the
timeline. The details view can be to the right of the timeline or bellow
the timeline and we can switch using ALT-t.
This patch adds `ClientBuilder::system_is_memory_constrained`
so that the client can be built with that in mind.
Behind the scene, for the moment, it only calls
`SqliteStoreConfig::with_low_memory_config` instead of
`SqliteStoreConfig::new`, but this flag can be used for other use cases.
This patch adds a new constructor for `SqliteStoreConfig`, which sets
some defaults tailored for low memory usage.
This patch adds tests asserting the defaults for `new` and
`with_low_memory_config`.
This patch explores a way to simplify the call sites of the `e2ee`
response processor by creating one response processor for `/v3/sync` and
one for MSC4186. The idea is to:
- simplify the call site by having less code,
- isolating the “dispatch” of a the response values into the `e2ee`
response processor,
- make it easier to test this response processor based on a `Response`
structs directly.
This patch updates
`BaseClient::receive_sync_repsonse_with_requested_required_states` to
use the `response_processors`. This patch also removes duplicated code
with the processors.
This patch introduces a new `Context` type that holds the state changes
and the room info notable updates. Processors will exchange this
context. That's the only data that is mutable and exchangeable between
processors.
There were a lot of changes, and it was hard to follow, especially with
methods and types that changed and were then removed.
This groups everything under a single entry, with a short summary of
the changes, followed by a list of per-PR changes.
The detailed list is reorganized to put the biggest changes first, like
the renaming, and a few entries were cleaned up or removed, because
they mention a method or type that is removed in another entry.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch boxes `local_echo` in
`DependentQueuedRequestKind::FinishUpload`, this variant' size is 512
bytes, compared to the second largest variant which is 104 bytes. To
reduce the global size of this enum, `local_echo` is now a `Box<_>`.
This patch reduces the size of `anySyncOrStrippedState`. The `Sync`
variant is 528 bytes, the `Stripped` variant is 232. First off, there is
a non-negligible difference in size between the two, but still, we can
reduce the size of the enum by boxing all values.
It simplifies code for users, and avoids to have to match on
`AuthApi`, which is a non-exhaustive enum.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It is actually unused, and now that we only need homeserver URLs for
static registrations, users don't need to access it easily.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
MSC2966 was updated, clients should re-register for every log in, so we
don't need to store the client IDs between logins.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This makes it possible to reply with a media, as part of a thread or not.
Fixes#4835.
---------
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Clearing only the store backend, while not emptying the in-memory linked
chunks, will lead to out-of-sync state across the in-memory caches and
the database. As a result, it's safer to call the existing
`EventCacheInner::clear_all_rooms`, which will clear all the rooms
manually.
A redaction event would be either applied a priori (by the server, when
returning the sync response), or the event cache would handle it, and
redact it in the database; in any case, we'd never see the original
event in its non-redacted form, so there's no point in returning the
redaction event itself.
It's unclear whether it's useful, especially in the case where it would
return an entire reply chain. It's not possible to filter in replies
only, using the function either, which is a sign that replies shouldn't
be indexed, IMO. In any case, that's something we can add back in the
future, if we want to.
Getting the position when reading an event is no longer required:
- the only use case for reading the position out of the event cache was
when we wanted to replace a redacted item into the linked chunk; now
with save_event(), we can replace it without having to know its
position.
As an extra measure of caution, I've also included the room_id in the
`events` table, next to the event_id, so that looking for an event is
still restricted to a single room.
This is necessary to save out-of-band items into the relational linked
chunk. I'm not quite sure of the value to keep it generic, at this
point, but at least it makes testing easy.
This patch adds 3 methods on `ClientBuilder`:
1. `session_pool_max_size`,
2. `session_cache_size`,
3. `session_journal_size_limit`.
Respective fields are also added.
These values control the `SqliteStoreConfig`, used to control the
stores, especially their memory consumption.
This patch removes the `path` and `passphrase` fields from
`BuilderStoreConfig::Sqlite`, and replaces them by `SqliteStoreConfig`.
This patch then opens the stores with `open_with_config` instead of
`open`.
At the default `INFO` log level, the log gets inundated with thousands
of emitted statements, primarily related to
`is_display_name_ambiguous()`. The execution of this tiny function
certainly doesn't need to be traced every time, at least not at the info
log level.
Note: some of these could be debatably reduced to debug level rather
than trace level, but I went with "trace" because they all seem to be
trace statements rather than actual debug dump outputs (there is no
actual program state dumped out).
Signed-off-by: Kevin Boos
[kevinaboos@gmail.com](mailto:kevinaboos@gmail.com)
---------
Signed-off-by: Kevin Boos <1139460+kevinaboos@users.noreply.github.com>
This patch updates `BaseStateStore` and the `StateStore` trait along
with its implementors, to return all rooms or a single room from
`StateStore::get_room_infos`.
See the previous patch for more context.
This patch introduces the `RoomLoadSettings` enum. It is helpful to load
either all rooms or one room when activating a `BaseClient`, i.e. when a
session is initialized or restored.
It addresses a broader problem where, for large accounts with large
caches, creating a `BaseClient` takes many resources. In a resource
constrainted context, like a push notification process, it can eat all
resources up to the point the process is killed (then notifications can
be missed).
The idea is then to force the `BaseClient` to load a single room.
This patch installs the `RoomLoadSettings` argument everywhere it needs
to be. The next patch will use `RoomLoadSettings` to load either all
rooms or a single one.
Since we don't depend on mas anymore, we don't depend on RSA either.
Let's remove the exception, lest we reintroduce the dependency and
security issue.
This patch splits `BaseStateStore::set_or_reload_session` into 3
distinct methods:
1. `set_session_meta` (hello again!),
2. `load_rooms`,
3. `load_sync_token`.
This patch also renames
`BaseStateStore::set_or_reload_session_from_other` into
`derive_from_other` to clarify its semantics. It calls these 3 methods
above as a combo.
Finally, this patch also updates `BaseClient::activate` to call these 3
methods above individually.
This patch renames `BaseClient::set_or_reload_session`
to `BaseClient::activate`, and `BaseClient::logged_in` to
`BaseClient::is_activated`.
The idea behind these renamings is to introduce a “state” for the
`BaseClient`: it is activated when is has a `SessionMeta`, has loaded
its data from the storages, and has an `OlmMachine`. Consequently, the
`logged_in` method is renamed `is_activated` for the symmetry. If one
wants to know if the client is logged in, it can use `is_activated`, or
also `MatrixAuth::logged_in`.
This patch renames the various `set_session_meta` methods to
`set_or_reload_session`. The idea is to highlight that the method is not
a simple setter: it sets but it _also_ updates the store' state.
The private shortcut method in `matrix_sdk::Client::set_session_meta`
is removed, and caller uses `client.base_client().set_or_reload_session`
instead. Why removing this `Client::set_session_meta` shortcut
method? Because it was creating confusion with another method:
`Client::restoring_session`. This private shortcut method wasn't used in
a lot of places, then I believe it's a nice improvement.
This patch updates `StoreOpenConfig` to hold a new type: `RuntimeConfig`.
This `RuntimeConfig` type is passed to a new `SqliteAsyncConnExt`
method, named `apply_runtime_config`. Depending on the values passed
here, the `optimize`, `cache_size` (new!) and `journal_size_limit`
methods will be called automatically.
The goal of this type is to automate a flow we keep repeating in
all the stores. This is error-prone. This type brings uniformity and
consistency.
This patch also makes all `open_with_pool` methods on the stores private
(they were public before):
1. they were never used as far as I know because getting a `SqlitePool`
isn't possible since the `pool` attribute is private…
2. it's better to keep control of this flow.
This patch pursues the same goal as the previous one: `Store` has
been renamed `BaseStateStore`, so the `store` field holding this
`BaseStateStore` is renamed `state_store`.
This patch renames `Store` to `BaseStateStore`. Ideally, I would
like to rename to `StateStore` but that's already a trait name
(`traits::StateStore`).
Why this renaming? To clarify what store it is.
In preparation for threads we have realised that the `reactions`,
`thread_root` and `in_reply_to` were only available on `Message` types,
which doesn't play well with Stickers and Polls.
This PR introduces a new `Aggregated` `TimelineItemContent` variant
which holds the message `kind` (Message, Sticker, Poll) as well as well
as any related aggregated data. it will help treat them all in a similar
fashion as well as account for future changes.
There are no functional changes, it's mostly about moving code around
and the FFI interfaces haven't changed.
Part of #4833.
If we have a device whose Curve25519 key we don't know, then
self-evidently we can't have any active Olm sessions with that device.
Currently, we return an `EventError::MissingSenderKey` in this case, but
(a) the definition of that error doesn't match this situation, and (b)
it complicates handling in methods that call `DeviceData::encrypt`
(currently only `DeviceData::maybe_encrypt_room_key`, but I want to add
a second).
Other than `DeviceData::encrypt`, the only place where
`get_most_recent_session` is called is `mark_device_as_wedged`. In that
case, we have just looked up the device by its Curve25519 key, so we
know it must have one.
We can therefore be reasonably certain that this change is a no-op.
This renames the `BaseClient::with_store_config` constructor to `new`:
1. there is no alternative constructor, it's the only one,
2. the `with_` prefix is usually reserved to (i) builders or (ii)
alternative constructors,
3. I believe it clarifies the code.
This patch:
* fixes the mention of “no IO”, it lacks the “network” part,
* adds an example of how to build a `BaseClient`,
* mentions that it is better be used via `matrix_sdk`.
It allows to reuse the URL for different actions more easily than having
to call `OAuth::account_management_url` every time for a different
action.
It also adds a method with fallback if we want to ignore action
serialization errors, to always present a URL.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch adds a new `StoreOpenConfing` type to configure the store
when opening it and when creating the pool of connections to SQLite via
`deadpool_sqlite`.
This patch also adds a new `open_with_config` constructor on all
stores, namely `SqliteCryptoStore`, `SqliteEventCacheStore` and
`SqliteStateStore`.
The previous code in `LinkedChunk::drop()` would call `clear()`, which
would reset the chunk to an empty events chunk; preinitializing a vector
of 128 items. But this item chunk would never be dropped, so this would
cause a leak.
The solution is to split the semantics of *resetting* a linked chunk
(what was called `clear` before), from *clearing* it: clearing will put
it in an dangling state, and it's the caller's responsibility to do
something about it; as such, it's marked unsafe. `LinkedChunk::drop()`
may now call `clear()` (which is fine; last use of the linked chunk);
and `LinkedChunk::reset()` will call `clear()` and reset the first
chunk, which is fine too.
This is a nice simplification, because this means that:
1. we use a single way to get the event (event-cache-or-network)
2. we don't have to reconstruct a `RoomMessageEventContent` from a
timeline's message, which seems a bit error prone
3. there's a single way to get the replied-to info for an event,
4. and that's actually independent of the timeline, so we can improve
the code for #4835
`send_reply` is geared towards clients that don't render threads themselves. It sends a reply and optionally forwards it onto any existing thread.
This PR adds `send_thread_reply` for clients that do render threads themselves. This sends a message onto a thread, regardless of whether a thread existed before, and includes the fallback for non-threaded clients only if the message is not itself a reply on the thread.
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Accept a URL or a query string for simplicity.
That way we don't need to expose AuthorizationResponse.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Since they perform blocking I/O we probably don't want to block a thread on that.
We use spawn_blocking, the alternative would be to use tokio::fs functions, which do the same thing and would require to load the whole file content in memory before (de)serialization.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Use the same prefix as the other types in the OAuth 2.0 API, and use the
same suffix as other data-persisting APIs for consistency.
It also avoids to have two modules with very similar names, the only
difference being a trailing `s`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Since we are the ones generating the device ID, we have a way to avoid this error. Even if in practice, it's probably always included in the server's response.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Can be useful with soft logouts, without requiring the user to recreate a new Client to log in again.
Returns an error if the new session is different from the current one.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
That way users only need to call finish_login, since there is no other
reason to call finish_authorization currently.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Fixes: #4793
There was a previous PR https://github.com/matrix-org/matrix-rust-sdk/pull/4802 which attempted to implement this, but missed some backwards compatibility needs.
This updated PR has the original commit and then additional commits to add the compatibility (along with tests for the new intent param generally).
This patch updates `RoomEventCacheState::remove_events` to check whether
the set of events are not empty before removing them. When removing
`in_memory_events`, it avoids taking a write lock on the `RoomEvents`
for nothing for example.
This patch adds a new check when inserting a new first chunk. It makes
some tests to fail but because they were not realistic. This patch then
updates these tests.
Because yes, some weeks, we are very productive!
This patch adds `--limit 100` to `gh pr list` so that we are sure to not
miss pull requests if there are many.
This patch fixes a bug where events coming from the event cache might be
encrypted, see https://github.com/matrix-org/matrix-rust-sdk/issues/4762
to learn more.
This patch updates the `room_event_cache_updates_task` to call
`TimelineController::retry_event_decryption` if the origin is `Cache`.
This patch removes the room `&Room` argument of
`TimelineController::retry_event_decryption`. The `TimelineController`
already has the room with its `room(&self) -> &Room` method. This method
was always used to fetch the room, let's expect `retry_event_decryption`
to do that by itself.
It also prevents passing the “wrong” room. This is more robust this way.
When `BaseClient` is created, the rooms aren't loaded yet. Then,
calculating the size of the channel for `RoomInfoNotableUpdate` is
useless, as it will always be zero, and we will fallback to 500 every
time. By the way, 500 is a nice default. This patch uses this value as
the only channel's size.
Allow use of a server url (eg `http://localhost:8008`), enabling connection to
a local server rather than one which supports well-known, TLS, and the rest.
This patch updates `replace_all_events_by` to take an `EventsOrigin`.
It is called in two places: by `add_initial_events`, in which case it
is `EventsOrigin::Cache`, and by `handle_timeline`, in which case it is
`EventsOrigin::Sync`.
This patch updates the `EventsOrigin` value sent by `Room::clear` to be
`Cache` instead of `Sync`. No events are added, but the `VectorDiff`s
are generated from the event cache itself, not from a sync.
This patch changes the log message. A `TimelineItemPosition::UpdateAt`
can only happen for remote event, not local event. The log message
was talking about _decryption_ but an `UpdateAt` can also happen for
redaction. This was misleading.
This patch updates the `RemoteEventOrigin` value passed to
`TimelineController::replace_with_initial_remote_events` when there is
a lag with the event cache. The previous value was `Sync`, but it should
be `Cache` since these events come from the event _cache_ (it was in the
name, easy).
This patch updates the sync code to include the
`RequestedRequiredStates` type.
This patch also adds `RoomInfo::handle_encryption_state` which
is able to mark an encryption state as synced depending of
`RequestedRequiredStates` (read the comment in the code).
This patch also updates the documentation of
`RoomInfo::handle_state_event` to clarify the impact of a
`m.room.encryption` state event.
This patch introduces a new type: `RequestedRequiredStates`, which keeps
track of all `required_states` passed to a sync request. So far, there
is only a `From` implementation for MSC4186.
These prompts were used in the Element X app, probably in some other clients too.
Since Ruma removed these cases, we're just passing them as `_Custom(value)` ones, which do work.
And make it take a boolean indicating whether we want to set up a
lightweight tokio runtime or not, instead of having
`setup_lightweight_tokio_runtime` as a public function + another
function, both of which would have to be called anyways.
cc @stefanceriu @jmartinesp
Creating many threads may use a bit of memory: on a machine with N
devices, exactly N*2 MB of memory may be consumed.
That might be a lot for a NSE process on iOS, which can only have up to
16 MB of RAM allocated for it. For this case, we introduce a new FFI
method `setup_lightweight_tokio_runtime` which will spawn at most 4
worker threads and 1 blocking thread. This should be sufficient for most
use cases.
As opposed to WAL mode, foreign keys must be enabled for each database
connection, according to
https://www.sqlite.org/foreignkeys.html#fk_enable
Unfortunately, we can't track which connection objects have already
executed the pragma, so the safer we can do is enable it everytime we
try to acquire a connection from the pool.
Fixes#4785.
A linked chunk never wants to be empty. However, after a limited gap
that doesn't contain events, it may be shrunk to the latest chunk that's
a gap.
If later we decide to remove the gap (because it's been resolved with no
events), then we would try to remove the last chunk, which is not
correct.
Ideally, we'd keep an events chunk around; but if we have an events
chunk *before* a gap, that may look like missing events to the user, at
least until the gap has been resolved.
The fix to this problem is to *not* optimize / remove the gap, if it's
the only chunk kept in memory. This was only a memory optimization, but
it's not absolutely required per se.
This patch reduces the memory usage of the broadcast channel used by
`BaseClient::room_info_notable_update_sender`. So far, its size was
`u16::MAX`. Considering `RoomInfoNotableUpdate` is 24 bytes, the channel
was allocating 1.5Mb of memory, which is way too much. It is creating
problems on systems where the process has limited resources, like the
Notification Service Extension on iOS.
For a regular users with 200 rooms, the memory usage becomes 24Kb, which
is 65'536 times less.
Being able to always use the first redirect URI in the client metadata
seems to be very specific to the FFI bindings.
For example clients that need to bind a port on localhost need to
provide a custom redirect URI each time.
So we ask for the redirect URI, and keep the current behavior only for
the bindings.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch introduces the new `EncryptionState` to represent the 3
possible states: `Encrypted`, `NotEncrypted` or `Unknown`. All the
`is_encrypted` methods have been replaced by `encryption_state`.
The most noticable change is in `matrix_sdk::Room` where `async fn
is_encrypted(&self) -> Result<bool>` has been replaced by `fn fn
encryption_state(&self) -> EncryptionState`. However, a new `async
fn latest_encryption_state(&self) -> Result<EncryptionState>` method
“restores” the previous behaviour by calling `request_encryption_state`
if necessary.
The idea is that the caller is now responsible to call
`request_encryption_state` if desired, or use `latest_encryption_state`
to automate the call if necessary. `encryption_state` is now non-async
and infallible everywhere.
`matrix-sdk-ffi` has been updated but no methods have been added for
the moment.
It's unusual to have the method on the parent type when the field type
could also hold the method. In fact, this was the only bool getter
inspecting the timeline's content, so let's move the method next to as
its siblings, for consistency, and let's spell it out fully for clarity.
Instead of MockBuilder::respond_with. This reduces duplcation and will
allow to add some common logic when building the endpoints.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The SyncService::stop method guarantees that the sync service will be
stopped after it has completed so there's no need to wait for state
changes.
The state change might not even come, if you pressed `S` to stop the
sync service manually.
This is done to fix an issue with these events being received and processed twice when `NotificationProcessSetup` is `SingleProcess`, causing issues with user verification.
This can be used to ignore verification requests in this sliding sync instance, preventing issues found where several sliding sync instances with the same client process events simultaneously and re-process the same verification request events during their initial syncs.
Many fields here are not argument of the `send` method, but are set
later with `Span::record`. Grepping all these fields reveal they are all
set except `request_body` apparently.
This patch is twofold. First off, it provides a new schema allowing to
improve the performance of `SqliteEventCacheStore` for 100_000 events
from 6.7k events/sec to 284k events/sec on my machine.
Second, it now assumes that `EventCacheStore` does NOT store invalid
events. It was already the case, but the SQLite schema was not rejecting
invalid event in case some were handled. It's now explicitely forbidden.
This patch removes the `EventsPostProcessing` type, it assumes
`with_events_muts` will always return events that will be post-process.
The case where `EventsPostProcessing::None` becomes a `vec![]`.
This patch updates `maybe_apply_new_redaction` to remove the first
`&RoomVersionId` argument. Indeed, due to the refactoring, it's now
possible for `maybe_apply_new_redaction` to read this value directly
from `Self::room_version`.
This patch updates `maybe_apply_new_redaction` to use `find_event`, so
that the target event is looked up in memory or in the store.
The case where it is in the store is a simple `todo!()` for the moment.
I wanted to separate the update of the `maybe_apply_new_redaction`
signature from the `InStore` implementation. The method is now async and
returns a `Result`.
This patch introduces `EventLocation` to know if an event has been found
in the memory (in `RoomEvents`) or in the store (in `EventCacheStore`).
This is used by the `RoomEventCacheState::find_event`.
This patch moves the `maybe_apply_new_redaction` method from
`RoomEvents` inside `RoomEventCacheState` so that it has an access
to the store (necessary for the next patch). This patch creates a new
`RoomEvents::replace_event_at` method, which is a thin wrapper around
`LinkedChunk::replace_item_at`.
This patch renames `sync_timeline_events` into `timeline_events`.
Moreover, this change has spotted a possible improvement
in `AllEventsCache` where it now receives events from
`collect_valid_and_duplicated_events`, which allows to only store valid
events in it.
This patch updates the callback passed to `with_events_mut`. It now
returns an `EventsPostProcessing` which can automatically run the, now
inlined, `on_new_events`.
This patch updates where the `RoomVersionId` is also stored. It's not
held by `RoomEventCacheState` instead of `RoomEventCacheInner`.
I have to disable LTO every time I'm building any final binary using the
SDK, because otherwise, the builds can take easily more than 10 minutes
to complete, killing iteration times, and making it almost impractical
to use the programs (benchmarks, or multiverse).
I think it should be the decision of the final embedder to enable or
disable LTO, and that for the purpose of our own binaries hosted in the
SDK repository, we don't need the absolute best performance (or, for the
sake of benchmarking, we can tweak the profiling profile).
The linked chunk always starts with an empty events chunk. If we receive
a gap from sync, then we will immediately push a gap chunk; in this
case, it might be better to replace the events chunk with a gap chunk.
This is equivalent to removing the empty events chunk, after pushing
back the first one (we can't do it before, otherwise we might get rid of
the only chunk in the linked chunk, which breaks the invariant that a
linked chunk is never empty).
And don'y rely on the `Paginator`. This simplifies the code a bit,
avoids a few methods on the `Paginator`, and makes it more
straightforward the pagination happens.
We keep the mock backend for endpoints that require an ID token for now,
as it would involve generating them on the fly.
And since support for ID tokens is going to be removed, it is not worth
it to implement that.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Instead of keeping state for the `Paginator` instance, we create one
when needs be, in the `run_backwards_impl` method, and initialize it
with a previous-batch token. This is simpler than keeping one alive, and
making sure that we reset it in the right places.
The event cache doesn't use the paginator for forwards pagination, so it
doesn't make sense to expose this method. Moreover, the event cache
always listens to sync in real-time, so technically it's always hit the
timeline end.
As a proof of this, this method wasn't even tested.
This patch adds support for the `shared_history` flag from MSC3061 to
the `m.room_key` content, exported room keys, and backed-up room keys.
The flag is now persisted in our `InboundGroupSession`. Additionally,
when creating a new `InboundGroupSession`, we ensure the
`shared_history` flag is set appropriately.
MSC3061: https://github.com/matrix-org/matrix-spec-proposals/pull/3061
In several places, we access almost all the fields of a struct to
create an `InboundGroupSession` from a pure data struct.
When new fields are added to these data structs, it's easy to
overlook updating the `InboundGroupSession` accordingly.
By using struct destructuring, we ensure that newly added fields are
explicitly considered, making it harder to forget one of the newly added
fields.
`prompt=create` is defined in MSC2964, and
`login_hint=mxid:@user:server.name` is defined in MSC4198.
The other parameters came from OpenID Connect.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It is a small optimization which makes the URL smaller, but it is not
part of the next-gen auth MSCs and is not supported by the oauth2 crate,
so let's drop it.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch fixes `RoomEventCache::event` to look inside `RoomEvents` but
also inside the `EventCacheStore` to look for an event. It ultimately
fallbacks to `AllEventsCache` because we can't get rid of it for the
moment.
This patch makes the code more robust around event removals. Sorting
events by their position is no longer done in the `Deduplicator` but in
a new `RoomEventCacheState::remove_events` method, which removes events
in the store and in the `RoomEvents`. This method is responsible to sort
events, this stuff is less fragile like so.
This patch adds a test for `sort_events_by_position_descending`. It
also updates this function so that events are sorted by their chunk
identifier from newest to oldest, it makes no difference but it matches
the order of the position indices too. Everything “dimension” is
descending.
This patch uses `DeduplicationOutcome` to remove events either in
memory, or in the store, when required. The `remove_events_by_id` method
has been renamed `remove_events_by_position`.
This patch redesigns `Deduplicator::filter_duplicate_events`.
First off, `filter_duplicate_events` does remove events with no valid
ID. At the same time, it removes duplicate events within the new events
(`events`). This check was done in the `BloomFilterDeduplicator` but
not in the `StoreDeduplicator`. Now it's done at the front of these
implementations, directly inside `Deduplicator`.
Second, this patch introduces `DeduplicationOutcome` to replace the
return type `(Vec<Event>, Vec<OwnedEventId>)`, especially because
now it would have become `(Vec<Event>, Vec<(OwnedEventId, Position)>,
Vec<(OwnedEventId, Position)>)`. Why?
1. Because the positions of the duplicated events are returned,
2. We differentiate between in-memory vs. in-store duplicated events.
Third, now there are positions associated to duplicated events, events
must be sorted. It's the role of `sort_events_by_position_descending`.
This way, `DeduplicatorOutcome` brings guarantees and less checks are
required.
It could be that we have a mismatch between network and disk, after
running a back-pagination:
- network indicates start of the timeline, aka there's no previous-batch
token
- but in the persisted storage, we do have an initial empty events chunk
Because of this, we could have weird transitions from "I've reached the
start of the room" to "I haven't actually reached it", if calling the
`run_backwards()` method manually.
This patch rewrites the logic when returning `reached_start`, so that
it's more precise:
- when reloading an events chunk from disk, rely on the previous chunk
property to indicate whether we've reached the start of the timeline,
thus avoiding unnecessary calls to back-paginations.
- after resolving a gap via the network, override the result of
`reached_start` with a boolean that indicates 1. there are no more gaps
and 2. there's no previous chunk (actual previous or lazily-loaded).
In the future, we should consider NOT having empty events chunks, if we
can.
Token revocation was split out from MSC2964 to MSC4254, and RP-Initiated
logout is now mentioned only as an alternative.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Will allow to share code when the backend is switched to the oauth2 crate too.
It will also allow to expose the device authorization grant directly in Oidc, if necessary.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The `.from()`, `.with_delay()` and `.limit()` functions are not very
explicit about what they did, and the `with_delay` one in particular led
me to think that it would introduce a delay *in the response*, while it
indicated a delay was expected as part of the matched URL.
Instead, this patch proposes to prefix all matchers with `match_`, to
make it clearer that… they will match the incoming query: match_from,
match_delay, match_limit.
Thanks to this change, the `RoomMessagesResponseTemplate` can be renamed
from `delayed` to `with_delay`, which was my original intent, before I
noticed another `with_delay` with totally different semantics.
This patch adds the new `from_all_chunks` function in the
`linked_chunk::lazy_loader` module. It is only used for testing
purposes. It aims at replacing `LinkedChunkBuilderTest` (see next
patches). Why? Because `from_all_chunks` uses `from_last_chunk` and
`insert_new_first_chunk`: if `from_all_chunks` is able to find all
errors that `LinkedChunkBuilderTest` finds, it's a bingo. Transitively,
it proves that `from_last_chunk` and `insert_new_first_chunk` are
correct!
This patch updates `Update::RemoveChunk` to emit `VectorDiff::Remove`.
Until now, `RemoveChunk` was expecting the chunk to be
empty, because it is how it is used so far. However, with
https://github.com/matrix-org/matrix-rust-sdk/pull/4694, it can change
rapidly.
The code before this patch was doing this:
- look if there's any prev-batch token available right now, aka look if
there's a gap in the in-memory linked chunk
- look at the first chunk; if it's a gap, return to the caller so it
resolves it
The check is done twice at two different levels, which is confusing.
Instead, this patch rewrites it so that the chunk is done only in
`load_more_event_backwards()`.
Note this is also correct for the case storage is disabled; in this
case, we early return and always try to resolve the gap anyways.
This patch renames the `builder` module to `lazy_loader`.
The `LinkedChunkBuilder`'s methods are now functions.
The `LinkedChunkBuilder` struct is removed. Finally,
`LinkedChunkBuilderError` is renamed `LazyLoaderError`.
The `LinkedChunkBuilderTest` struct is kept for the moment. It's going
to be replaced soon.
This patch adds an index on `events.event_id` and on `events.room_id`
so that queries on this column are faster. It mostly happens for the
`Deduplicator`, which runs for every backwards pagination or sync.
This patch also updates the query in `filter_duplicated_events` to
sort event by their `chunk_id` and `position` so that the results are
constant, it helps when testing.
This is the method to get the server metadata in the latest draft of
[MSC2965](https://github.com/matrix-org/matrix-spec-proposals/pull/2965).
We still keep the old behavior with `GET /auth_issuer` as fallback for
now because it has wider server support.
There are some pre-main commit cleanups to simplify the main commit.
This can be reviewed commit by commit.
The changes were tested with the oidc_cli example on beta.matrix.org.
Closes#4550.
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch moves `chunk_debug_string` from `rooms/mod.rs` to
`rooms/event.rs`. In addition, it restores (and rewrites) a test,
initially for `chunk_debug_string`, now for `RoomEvents::debug_string`
whichh is the public API.
This patch changes the semantics regarding what to do in case of
duplicated events received during a backwards pagination.
Previously, the strategy for both sync and backwards pagination was
the same: With the new received events, when duplicated events are
detected, the old events are removed and the new ones are kept.
The strategy is reversed for backwards pagination: the old events are
always kept, and the duplicated events are removed from the new events.
The rest of the patch is about removing dead code because of this
change.
This patch updates `Pagination::run_backwards_impl` to paginate in the
event cache. The flow is now as follow:
- backwards pagination tries to load and to insert a new previous chunk
from the store
- if the new chunk contains events, they are returned, pagination done
- if the new chunk is a gap, the flow continues
- (as previously) check for a prev batch token (it exists in the newly
inserted gap)
- (as previously) run a network request, replace the gap by the new
events
- etc.
The new part is to load and to insert a new previous chunk. The rest
is stays the same. The code has been moved in code to keep the lock
releases happy and to clarify the code.
This patch adds the `RoomEventCacheState::load_more_events_backwards`
method to load a new chunk and to insert it at the beginning of the
`LinkedChunk`.
It uses the new `EventCacheStore::load_previous_chunk` method, along
with the new `LinkedChunkBuilder::insert_new_first_chunk` method.
This patch updates `RoomEventCacheState::new` to load a single chunks
of events instead of all events. It solves bugs where all events were
loaded, while removing the gaps in between, thus the `Timeline` wasn't
able to load the missing events to fill the gaps.
This patch removes a `TODO` in `BackPaginationOutcome`.
Events it contains are deduplicated by the `EventCache` (see
`event_cache::Deduplicator`) when inserted inside `RoomEventCache`.
This patch adds a test for all event cache store
implementations that tests a linked chunk incremental
loading, i.e. the `EventCacheStore::load_last_chunk` and
`EventCacheStore::load_previous_chunk` methods.
Most of the methods on `LinkedChunkBuilder` are now only used
for testing. This patch splits `LinkedChunkBuilder` and creates
`LinkedChunkBuilderTest`. This new type is part of the public
API because it's used in other crates, but it's hidden from the
documentation.
This patch adds two methods on `LinkedChunkBuilder`: `from_last_chunk`
to build a new `LinkedChunk` with a single provided chunk, and
`insert_new_first_chunk` to insert a new chunk at the beginning of the
provided `LinkedChunk`.
This patch renames `RoomEvents::with_initial_chunks` to
`with_initial_linked_chunk`. It avoids a confusion between several
chunks, like `RawChunk`s, and `LinkedChunk` which represents several
`Chunk`s.
This patch update the `EventCacheStore` trait to:
1. rename `reload_linked_chunk` into `load_all_chunks` and put this
method behind `#[cfg(test)]` so that it is removed from the public API,
2. add `load_last_chunk`,
3. add `load_previous_chunk`.
These 2 new methods are implemented inside the `MemoryStore` (with its
real implementation in the `RelationalLinkedChunk`), but `todo!()` are
added for the SQLite implementation.
The format changed 10 months ago and since it contains the tokens, it should have be reserialized already in that time.
Afaict EX clients do not serialize that type, the bindings have their own `Session` type for that.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch introduces `Chunk::lazy_previous` which is a key feature to
support lazy-loading of a `LinkedChunk`. When a chunk is loaded, if it
is the first, it keeps in memory whether it has a previous chunk or not.
Thus, it is possible to insert new chunk in front of the `LinkedChunk`,
and `Update`s will correctly continue to link chunks between them (with
`NewItemsChunk` and `NewGapChunk`).
Example, imagine the following chunks: [0] <-> [1] <-> [2]. If [2] is
the only one being loaded. Then its previous chunk, [1], is loaded from
the store (because [2]'s previous is [1] in the store). Then [1] is
replaced by [3] and [4]. We get this: [4] <-> [3] <-> [1] <-> [2]. If
the `Update::New*Chunk` for [4] doesn't contain a `previous`, the store
is out of sync: in the store, [4] has no previous, but [0] still has [1]
for its `next`.
With this `lazy_previous`, the links are correctly computed.
While implementing user verification on Element X I realized that the
`IdentityStatusChanges` stream does not notify us when an user becomes
`Verified`, which is a shame as it's perfect for powering app updates
after verifying users (i.e. all the decorations we show throughout the
app: room header, room details, room member list, room member profile
etc.)
Had a look at the existing code and, while that seems completely
intentional, there is no reason why we can't expand its purview.
This adds a task to compile the benchmarks in CI, without running them,
and with the lowest level of optimization that's available (the `dev`
profile).
As recommended by BCP 195.
It shouldn't be a problem with rustls that only supports TLS 1.2 and 1.3, but with native-tls it depends on the implementation.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This should be the most common case, and is already the only case
supported by the higher level APIs like `url_for_oidc` and
`login_with_qr_code`. It simplifies the API because we can call
`restore_registered_client` directly from `register_client`, which was a
TODO.
- [x] Public API changes documented in changelogs (optional)
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch adds and implements the
`EventCacheStore::filter_duplicated_events` method. It is implemented on
the `MemoryStore` and the `SqliteEventCacheStore`.
This method remove the unique events and reutrn the duplicated events.
This patch updates `RoomEventCache::subscribe` to be infallible. This
method wasn't able to return something else than an `Ok`. The return
type has been updated from `Result<T>` to `T`.
The `RoomEvents` doesn't hold the `Deduplicator` instance now, it's the
role of the `RoomEventCacheState`. This slightly simplifies the code, in
a few cases.
This patch removes the invariant stating that a `LinkedChunk` must start
by a chunk of type items. This has never been really useful but it's now
annoying to have this (with iterative loading of a `LinkedChunk` via the
`EventCache`, it's now possible to get a gap as the first chunk). Let's
remove this invariant.
We encountered this warning a lot in the logs after upgrading the SDK today.
My understanding is that this path is expected if the event is not yet in the timeline, so it's nothing to warn about.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
A room can be associated to a lot of data, depending on the number of members in the room.
So freeing space on the filesystem should be worth it in some cases.
An (extreme) example: I have a test account that is in ~60 rooms, a few of those big public rooms, including Matrix HQ. The size of the matrix-sdk-state.sqlite3 file is 542 MB. Using this PR and leaving, then forgetting Matrix HQ brings the DB down to 255 MB.
The `EventTimelineItem` would get from a bool to an `Option<bool>`. If
the metadata's `is_room_encrypted` was set to `None`, then it would use
`false` as the value, before wrapping it again into an `Option`.
Since the only reader of `EventTimelineItem::is_room_encrypted()`
doesn't really care about the difference between `Some(false)` and
`None`, in `EventTimelineItem::get_shield()`, we can use a plain `bool`
instead of an `Option`, and not distinguish `Some(false)` from `None`.
At worst, it means that sometimes we don't know the room encryption
status yet, and consider the room unencrypted; as soon as we'll get an
update about encryption state, all the items will be marked as encrypted
anyways, if needs be.
## Some context
An aggregation is an event that relates to another event: for instance,
a
reaction, a poll response, and so on and so forth.
## Some requirements
Because of the sync mechanisms and federation, it can happen that a
related
event is received *before* receiving the event it relates to. Those
events
must be accounted for, stashed somewhere, and reapplied later, if/when
the
related-to event shows up.
In addition to that, a room's event cache can also decide to move events
around, in its own internal representation (likely because it ran into
some
duplicate events, or it managed to decrypt a previously UTD event).
When that happens, a timeline opened on the given room
will see a removal then re-insertion of the given event. If that event
was
the target of aggregations, then those aggregations must be re-applied
when
the given event is reinserted.
## Some solution
To satisfy both requirements, the [`Aggregations`] "manager" object
provided
by this PR will take care of memoizing aggregations, **for the entire
lifetime of the timeline** (or until it's clear'd by some
caller). Aggregations are saved in memory, and have the same lifetime as
that of a timeline. This makes it possible to apply pending aggregations
to cater for the first use case, and to never lose any aggregations in
the
second use case.
## Some points for the reviewer
- I think the most controversial point is that all aggregations are
memoized for the entire lifetime of the timeline. Would that become an
issue, we can get back to some incremental scheme, in the future:
instead of memoizing aggregations for the entire lifetime of the
timeline, we'd attach them to a single timeline item. When that item is
removed, we'd put the aggregations back into a "pending" stash of
aggregations. If the item is reinserted later, we could peek at the
pending stash of aggregations, remove any that's in there, and reapply
them to the reinserted event. This is what the [first version of this
patch](https://github.com/matrix-org/matrix-rust-sdk/pull/4576/commits/ec64b9e0bcc9a2d05dd8c910a8710b72466ef51c)
did, in a much more adhoc way, for reactions only; based on the current
PR, we could do the same in a simpler manner
- while the PR has small commits, they don't quite make sense to review
individually, I'm afraid, as I was trying to find a way to make a
general system that would work not only for reactions, poll responses
and ends. As a matter of fact, the first commits may have introduced
code that is changed in subsequent commits, making the review a bit
hazardous. Happy to have a live reviewing party over Element Call, if
that helps, considering the size of the patch.
- future work may include using the aggregations manager for edits too,
leading to more code removal.
The test ends up with checking that the redact endpoint has been hit
once. It's actually the send queue doing the redaction as a dependent
send request, and it doesn't provide any notification mechanism in this
case, so we can't really know when it's done doing it.
One solution would be to not check the number of calls to the redact/
endpoint, but that means checking for fewer things. Instead, I made it
so that when hit, the endpoint will signal it to the main task using a
oneshot channel; then the main task waits with a long timeout for the
receiving end to get the notification it's been sent, which should be
sufficient.
This would help find test failures specific to experimental-oidc, as
well as doctests failing (which would have prevented the failures fixed
in https://github.com/matrix-org/matrix-rust-sdk/pull/4614 to happen in
the first place).
This patch removes the `Clear` variant of the `RoomEventCacheUpdate`
enum. This one is not needed anymore since we have
`UpdateTimelineEvents` which contains updates as `Vec<VectorDiff<_>>`.
`VectorDiff` _has_ a `Clear` variant. It resulted in a double clear
every time.
This patch updates `RoomEventCacheInner::reset` and
`RoomEventCacheInner::with_events_mut` to annotate them with a
`#[must_use]`. Since they return the updates as `VectorDiff`s,
they **must** be broadcasted/propagated somewhere, likely with
`RoomEventCacheUpdate`. This mechanism ensures to not miss updates.
This patch fixes an issue where 0 was used as the initial value for
the `Skip` higher-order stream in the `TimelineSubscriber`. This is
wrong, as the `SkipCount` value may have been modified before the
`TimelineSubscriber` is created.
This patch provides a test to reproduce the problem.
This patch gathers the logic of the `Timeline::subscribe` into a single
type: `TimelineSubscriber`.
The `TimelineController::subscribe_batched_and_limited` method is
renamed `subscribe` to match `Timeline::subscribe`. Things are simpler
to apprehend.
The `TimelineSubscriber` type configures the subscriber/stream in a
single place. It takes an `&ObservableItems` and a `&SkipCount`, and
configures everything. It also provides a single place to document the
behaviour of the subscriber, with the `Skip` higher-order stream.
This patch updates the pagination mechanism of the `Timeline` to support
lazy backwards pagination.
`Timeline::paginate_backwards` already does different things whether the
timeline focus is live or focused. When it's live, the method will first
try to paginate backwards lazily, by adjusting the `count` value of the
`Skip` stream used by the `Timeline::subscribe` method. If there is not
enough items to provide, the greedy pagination will run.
This patch updates `TimelineStateTransaction::commit` to adjust the
count value of the `Skip` higher-order stream.
This patch also creates `TimelineStateTransaction::new` to simplify the
creation of a state transaction.
This patch applies the `Skip` higher-order stream on the `Timeline`
subscriber. The method `TimelineController::subscribe_batched` is
renamed `subscribe_batched_and_limited` at the same time.
The `Skip` stream uses the `TimelineMetadata::subscriber_skip_count`
observable value as the `count_stream`. The initial count value is 0.
No test needs to be changed so far.
This patch adds the `subscriber_skip_count` field to `TimelineMetadata`.
It's going to be used to define the `count` value of the `Skip`
higher-order stream that is going to be applied to the `Timeline`
subscriber.
This patch adds functions like `compute_next`,
`compute_next_when_paginating_backwards` and
`compute_next_when_paginating_forwards`, which are necessary to
correctly compute the `count` value for the `Skip` higher-order stream.
This patch adds the associated test suite.
This patch renames `TimelineStream` to `TimelineWithDropHandle`, as the
former name was too vague and was not clarify what the type was doing.
The new name makes it clear that it attaches a `TimelineDropHandle` to a
subscriber (since it is part of the `subscriber` module!).
This patch updates `TimelineController::subscribe` to use
`VectorSubscriber::into_values_and_batched_stream`. It returns
the cloned items along with the stream. It saves the need to call
`ObservableItems::clone_items`, thus saving the clone of all items.
tl;dr: `clone_items()` clones… items… and `subscribe()` also clones the
items. There is 2 clones. With `into_values_and_batched_stream()`, there
is 1 clone.
This patch improves the performance of
`ReadReceiptTimelineUpdate::apply`, which does 2 things: it calls
`remove_old_receipt` and `add_new_receipt`. Both of them need an
timeline item position. Until this patch, `rfind_event_by_id` was used
and was the bottleneck. The improvement is twofold as is as follows.
First off, when collecting data to create `ReadReceiptTimelineUpdate`,
the timeline item position can be known ahead of time by using
`EventMeta::timeline_item_index`. This data is not always available, for
example if the timeline item isn't created yet. But let's try to collect
these data if there are some.
Second, inside `ReadReceiptTimelineUpdate::remove_old_receipt`, we use
the timeline item position collected from `EventMeta` if it exists.
Otherwise, let's fallback to a similar `rfind_event_by_id` pattern,
without using intermediate types. It's more straightforward here: we
don't need an `EventTimelineItemWithId`, we only need the position.
Once the position is known, it is stored in `Self` (!), this is the
biggest improvement here. Le't see why.
Finally, inside `ReadReceiptTimelineUpdate::add_new_receipt`, we use
the timeline item position collected from `EventMeta` if it exists,
similarly to what `remove_old_receipt` does. Otherwise, let's fallback
to an iterator to find the position. However, instead of iterating over
**all** items, we can skip the first ones, up to the position of the
timeline item holding the old receipt, so up to the position found by
`remove_old_receipt`.
I'm testing this patch with the `test_lazy_back_pagination` test in
https://github.com/matrix-org/matrix-rust-sdk/pull/4594. With 10_000
events in the sync, the `ReadReceipts::maybe_update_read_receipt` method
was taking 52% of the whole execution time. With this patch, it takes
8.1%.
This patch improves the performance of
`RoomEvents::maybe_apply_new_redaction`. This method deserialises
all the events it receives, entirely. If the event is not an
`m.room.redaction`, then the method returns early. Most of the time,
the event is deserialised for nothing because most events aren't of kind
`m.room.redaction`!
This patch first uses `Raw::get_field("type")` to detect the type of
the event. If it's a `m.room.redaction`, then the event is entirely
deserialized, otherwise the method returns.
When running the `test_lazy_back_pagination` from
https://github.com/matrix-org/matrix-rust-sdk/pull/4594 with 10'000
events, prior to this patch, this method takes 11% of the execution
time. With this patch, this method takes 2.5%.
This patch fixes the performance of
`AllRemoteEvents::increment_all_timeline_item_index_after` and
`decrment_all_timeline_item_index_after`.
It appears that the code was previously iterating over all items. This
is a waste of time. This patch updates the code to iterate over all
items in reverse order:
- if `new_timeline_item_index` is 0, we need to shift all items anyways,
so all items must be traversed, the iterator direction doesn't matter,
- otherwise, it's unlikely we want to traverse all items: the item has
been either inserted or pushed back, so there is no need to traverse
the first items; we can also break the iteration as soon as all
timeline item index after `new_timeline_item_index` has been updated.
I'm testing this patch with the `test_lazy_back_pagination` test in
https://github.com/matrix-org/matrix-rust-sdk/pull/4594. With 10_000
events in the sync, the `ObservableItems::push_back` method (that uses
`AllRemoteEvents::increment_all_timeline_item_index_after`) was taking
7% of the whole execution time. With this patch, it takes 0.7%.
The WAL file can grow depending on the transactions that are run. A
critical case is VACUUM which basically writes the content of the DB
file to the WAL file before writing it back to the DB file.
SQLite doesn't try to reduce the size of the file after that unless we
set an explicit limit,
so we could end up taking twice the size of the database on the
filesystem.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It should have been done in the migration of version 7, to reduce the
size of the database on the filesystem after the media cache was moved
to the SqliteEventCacheStore. Better late than never.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Fixes#4517.
It turns out that the bugs found in that test were due to 2 causes:
- First commit: `TestRoomDataProvider` didn't use `initial_user_receipts` but returned hardcoded values.
- Second commit: Our own read receipts were ignored in `TimelineStateTransaction::load_read_receipts_for_event`, although we need to process all read receipts via `ReadReceipts::maybe_update_read_receipt` because it knows how to filter out our own read receipts were needed.
This patch drastically improves the performance of
`TimelineEventHandler::deduplicate_local_timeline_item`.
Before this patch, `rfind_event_item` was used to iterate over all
timeline items: for each item in reverse order, if it was an event
timeline item, and if it was a local event timeline item, and if it was
matching the event ID or transaction ID, then a duplicate was found.
The problem is the following: all items are traversed.
However, local event timeline items are always at the back of the items.
Even virtual timeline items are before local event timeline items. Thus,
it is not necessary to traverse all items. It is possible to stop the
iteration as soon as (i) a non event timeline item is met, or (ii) a non
local event timeline item is met.
This patch updates
`TimelineEventHandler::deduplicate_local_timeline_item` to replace to
use of `rfind_event_item` by a custom iterator that stops as soon as a
non event timeline item, or a non local event timeline item, is met, or
—of course— when a local event timeline item is a duplicate.
To do so, [`Iterator::try_fold`] is probably the best companion.
[`Iterator::try_find`] would have been nice, but it is available on
nightlies, not on stable versions of Rust. However, many methods in
`Iterator` are using `try_fold`, like `find` or any other methods that
need to do a “short-circuit”. Anyway, `try_fold` works pretty nice here,
and does exactly what we need.
Our use of `try_fold` is to return a `ControlFlow<Option<(usize,
TimelineItem)>, ()>`. After `try_fold`, we call
`ControlFlow::break_value`, which returns an `Option`. Hence the need
to call `Option::flatten` at the end to get a single `Option` instead of
having an `Option<Option<(usize, TimelineItem)>>`.
I'm testing this patch with the `test_lazy_back_pagination` test in
https://github.com/matrix-org/matrix-rust-sdk/pull/4594. With 10_000
events in the sync, the test was taking 13s to run on my machine. With
this patch, it takes 10s to run. It's a 23% improvement. This
`deduplicate_local_timeline_item` method was taking a large part of the
computation according to the profiler. With this patch, this method is
barely visible in the profiler it is so small.
[`Iterator::try_fold`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_fold
[`Iterator::try_find`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_find
This patch uses `next_back()` instead of `last()`, which is equivalent
but `last()` requires to iterate over the entire iterator, while
`next_back()` is a single operation.
This patch removes a useless type conversion. The `Room::event()` method
returns a `TimelineEvent`, so calling `Into::into` is useless: we map
`TimelineEvent` to `TimelineEvent`.
This patch removes a useless type conversion. The iterator produces
`TimelineEvent`, so mapping to `TimelineEvent::from` is useless: we map
`TimelineEvent` to `TimelineEvent`.
This test helper is the same as the assert_next_eq helper, but it waits
for the stream to be ready for a certain amount of time instead of
expecting it to be ready right away.
The `SyncService::stop()` method could fail for the following reasons:
1. The supervisor was not properly started up, this is a programmer error.
2. The supervisor task wouldn't shut down and instead it returns a JoinError.
3. We couldn't notify the supervisor task that it should shutdown due the channel being closed.
All of those cases shouldn't ever happen and the supervisor task will be
stopped in all of them.
1. Since there is no supervisor to be stopped, we can safely just log an
error, our tests ensure that a `SyncService::start()` does create a
supervisor.
2. A JoinError can be returned if the task has been cancelled or if the
supervisor task has panicked. Since we never cancel the task, nor
have any panics in the supervisor task, we can assume that this won't
happen.
3. The supervisor task holds on to a reference to the receiving end of
the channel, as long as the task is alive the channel can not be
closed.
In conclusion, it doesn't seem to be useful to forward these error cases
to the user.
This patch moves the creations of the child tasks of the SyncService
into the supervisor tasks itself. This should make it easier to let the
supervisor recreate tasks.
This will become useful once we introduce a offline mode where the
supervisor task becomes responsible to restart syncing once we notice
that the server is back online.
This patch moves `TimelineMetadata`, its implementation and companion
types (like `RelativePosition`) into its own module. The idea is to
reduce the size of the `state.rs` module.
This patch replaces all uses of `TimelineController::add_events_at` by
`TimelineController::handle_remote_events_with_diffs` in the `Timeline`
itself.
The idea is to remove `add_events_at`, as we currently have 2 ways to
add or to handle remote events in the `Timeline`. We want a single one,
because it's simpler!
This patch replaces all uses of `TimelineController::add_events_at` by
`TimelineController::handle_remote_events_with_diffs` in the tests.
The idea is to remove `add_events_at`, as we currently have 2 ways to
add or to handle remote events in the `Timeline`. We want a single one,
because it's simpler!
It is already a 3-tuple and we want to add more data so it will be clearer to use a stuct with named fields.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This will be used as a configuration to decide whether or not to keep
media in the cache, allowing to do periodic cleanups to avoid to have
the size of the media cache grow indefinitely.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Now that the various match branches in the start and stop method of the
SyncService are minimized we can remove the early returns.
This should allow us to more easily add new branches.
The supervisor is defined as two optional fields that are set and
removed at the same time.
This patch converts the two optional fields into a single optional
struct. The fields inside the struct now aren't anymore optional. This
ensures that they are always set and destroyed at the same time.
From cambridge a scheduler is defined as:
> someone whose job is to create or work with schedules
While supervisor is defined as:
> a person whose job is to supervise someone or something
Well ok, that doesn't tell us much, supervise is defined as:
> to watch a person or activity to make certain that everything is done correctly, safely, etc.:
In conclusion, supervising a task is the more common and better
understood terminology here I would say.
Previously we had a lock protecting an empty value, but the logic wants
to protect a bunch of data in the SyncService.
Let's do the usual thing and create a SyncServiceInner which holds the
data and protect that with a lock.
This patch renames `Timeline::subscribe_batched` to
`Timeline::subscribe`. Since the `Timeline::subscribe` method has been
removed because unused, it no longer makes sense to have a “batched”
variant here. Let's simplify things!
This patch simplifies the `Timeline` pagination API as follows:
- a unique `paginate_backwards` method (no more
`focused_paginate_backwards` and `live_paginate_backwards`),
- a unique `paginate_forwards` method (no more
`focused_paginate_forwards`, the `live` variant was absent).
The idea is to unify pagination by hiding the `live` and `focused` mode.
It was already partially the case with `paginate_backards`, but the
`live` and `focused` variants were also present. I believe it creates
an unnecessary confusion.
Firstly, build a `CollectRecipientsResult` as we go, rather than building its
components separately and then assembling it at the end.
Then, factor the common code between the two code paths into a method to update
the `CollectRecipientsResult`.
- supports only text room message types
- enumerates through their body's grapheme clusters and check that every
single one of them is an emoji
- part of the `LazyTimelineItemProvider` so that it can be opt in
`split_devices_for_user` returns a superset of the results of
`split_recipients_withhelds_for_user_based_on_identity`: let's reflect that in
the return types so we can start to share code.
Also, rename `split_recipients_withhelds_for_user_based_on_identity` to
`split_devices_for_user_for_identity_based_strategy` while we are here.
A bounds check was recently relaxed in `imbl`'s `Focus::narrow()`
function: https://github.com/jneem/imbl/pull/89,
which fixed a bug that would cause a panic if the downstream user
of `matrix-sdk-ui` attempted to narrow a focus of Timeline items
using a range that included the last item in the Timeline.
Example: https://github.com/project-robius/robrix/issues/330
This fix has been incorporated in `eyeball-im` and `eyeball-im-util`
and has been tested by me to no longer trigger upon the aforementioned
conditions.
As the comment noted, they're essentially doing the same thing. A
`TimelineEvent` may not have computed push actions, and in that regard
it seemed more correct than `SyncTimelineEvent`, so another commit will
make the field optional.
This patch removes `Timeline::subscribe`. There is
`Timeline::subscribe_batched`, which is the only useful API.
`subscribe` was only used by our tests, and `matrix-sdk-ffi` uses
`subscribe_batched` only.
This patch changes all calls to `Timeline::subscribe` to replace them by
`Timeline::subscribe_batched`. Most of them are in tests. It's the first
step of a plan to remove `Timeline::subscribe`.
The rest of the patch updates all the tests to use
`Timeline::subscribe_batched`.
It became an optional default feature in reqwest 0.12, and we disable
the default features,
so I don't think it was meant to be disabled when the crate was
upgraded.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It was used in places where we could make use of other helpers, in some
cases. Also introduces the `room_avatar` helper to create the room
avatar state event.
This was a regression introduced in
f0d98602a9.
`latest_edit_json` was first set by the call to
`EventTimelineItem::with_content()`.
It was overwritten in the next section because of the
`if let EventTimelineItemKind::Remote(remote_event)`
that uses `item` instead of `new_item`.
It means that the updated `RemoteEventTimelineItem`
inside`new_item` was replaced by the outdated one inside `item`,
so `latest_edit_json` goes back to its previous value.
I believe that part of why that went unnoticed is that the code looks
more
complicated due to the need to set an inner field, so I decided to
change the API and
move `with_encryption_info` to `EventTimelineItem`, which makes the code
look cleaner.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This change ensures that the user's own live location events are
excluded from the location sharing stream. Since the user's location is
already represented on the map by the blue dot, processing their own
events is redundant and unnecessary.
The others should likely be copied at some point as well, but including
the readme as crate documentation is not currently useful since the
readme for the ui crate is empty, and warning about missing docs or
debug implementations would make CI fail without substantial extra work.
This patch removes a `XXX` (which I believe is a TODO) in the
documentation of `RoomEventCache::subscribe`. We are not going to change
this API anytime soon.
Setting the default log level to `debug` results in logs like:
```
log: log_event
log: latest_event
log: log_event
log: log_event
log: room_info
log: latest_event
log: log_event
log: room_info
```
Presumably they're coming out of the custom tracing configuration and we definitely don't need them.
This is unlikely that it will affect us, so not worth adding a test IMO,
but for the sake of completeness: this handles redacted redactions in
the `AllEventsCache` too.
This is intended to prevent the test
`test_when_user_in_verification_violation_becomes_verified_we_report_it`
flaking. I found that sometimes when it called `Room::members` the
result was empty due to it trying to fetch the answer from the server.
This change prevents that behaviour. I don't know why the behaviour was
inconsistent before.
Regenerate Dan's data with new cross-signing and device keys, for which I know
the private keys.
The signatures are manually calculated for now; this will be improved in a
later commit.
This removes one sync that happens in the background, because it's
likely spurious and may be confusing the server about what's been seen
by the current client.
Add a new created_at to the send_queue_events and
dependent_send_queue_events stored records. This will allow clients to
understand how stale a pending message might be in the event that the
queue encounters and error and becomes wedged.
This change is exposed through the FFI on the `EventTimelineItem` struct
as a new optional field named `local_created_at`. It will be `None` for
any Remote event, and `Some` for Local events (except for those that
were enqueued before the migrations were run).
Signed-off-by: Daniel Salinas
---------
Signed-off-by: Daniel Salinas <zzorba@users.noreply.github.com>
Co-authored-by: Daniel Salinas <danielsalinas@daniels-mbp-2.myfiosgateway.com>
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
Co-authored-by: Daniel Salinas <danielsalinas@Daniels-MBP-2.attlocal.net>
This can be accessed through `fn Room::privacy_settings` and will wrap the functionality related to a room's access and privacy settings.
This commit includes the `fn RoomPrivacySettings::update_canonical_alias` to modify the canonical alias of a room.
As an outsider, I am mostly interested in features and new developments
that have happened, not those that *may* happen. An open-but-not-merged
PR may not get merged in the end, or it may not get merged any time
soon, creating false expectations. Merged PRs, on the other hand, have
definitely happened (even if they get undone, that happens via other PRs
that will get merged later). As such, I think it brings more value to
outsiders.
This fixes the deserialization of the SenderData since it switched to
the base64 encoding for serialization of the master key in one of its
variants.
The issue was introduced in 5ff556f6c3.
Having the final clients define the tracing filters / log levels proved
to be tricky to keep in check resulting missing logs (e.g. recently
introduced modules like the event cache) or unexpected behaviors (e.g.
missing panics because we don't set a global filter). As such we decided
to move the tracing setup and default definitions over to the rust side
and let rust developers have full control over them.
We will now take a general log level and optional extra targets and
apply them on top of the rust side defined defaults. Targets that log
more than the requested by default will remain unchanged while the
others will increase their log levels to match. Certain targets like
`hyper` will be ignored in this step as they're too verbose others
like `matrix_sdk` because they're too generic.
This patch fixes a bug where the code assumes a gap has been inserted,
and thus, is always present. But this isn't the case. If `prev_batch`
is `None`, a gap is not inserted, and so we cannot remove it. This patch
checks that `prev_batch` is `Some(_)`, which means the invariant is
correct, and the code can remove the gap.
This patch removes `SlidingSyncRoomInner::client` because, first
off, it's not `Send`, and second, it's useless. Nobody uses it, it's
basically dead code… annoying dead code… bad dead code!
Sliding sync is no longer experimental. It has a solid MSC4186, along
with a solid implementation inside Synapse. It's time to consider it
mature.
The SDK continues to support the old MSC3575 in addition to MSC4186.
This patch only removes the `experimental-sliding-sync` feature flag.
From now on, this patch considers that `VectorDiff`s are the official
input type for the `Timeline`, via `RoomEventCacheUpdate` (notably
`::UpdateTimelineEvents`).
This patch removes `TimelineSettings::vectordiffs_as_inputs`. It thus
removes all deduplication logics, as it is supposed to be managed by the
`EventCache` itself.
This patch removes the `AddTimelineEvents` variant from
`RoomEventCacheUpdate` since it is replaced by `UpdateTimelineEvents`
which shares `VectorDiff`.
This patch also tests all uses of `UpdateTimelineEvents` in existing
tests.
If it's present, we just let it untouched. Otherwise, we set it to
`error` if it's missing. See code comment explaining why we need this.
This makes sure we log panics at the FFI layer, since the `log-panics`
crate will use the `panic` target at the error level.
Some errors can be handled immediately and don't need a request to be
spawned, e.g. invalid mimetype and so on. The returned task handle still
deals about "late" errors about the upload failing (for sync uploads) or
the send queue failing to push the media upload (for async uploads).
This patch renames `RoomEvents::filter_duplicated_events` to
`collect_valid_and_duplicated_events` as I believe it improves the
understanding of the code. The variables named `unique_events` are
renamed `events` as all (valid) events are returned, not only the unique
ones.
This patch adds the `Pagination` variant to the `EventsOrigin` enum.
Not something really mandatory and that is likely to fix a bug, but it's
now correct.
Since 8205da898e it has been possible to
attach (intentional) mentions to _edited_ media captions, but the
send_$mediatype() timeline APIs provided no way to send them with the
initial event. This fixes that.
Signed-off-by: Joe Groocock <me@frebib.net>
We have quite a few `allow(dead_code)` annotations. While it's OK to use
in situations where the Cargo-feature combination explodes and makes it
hard to reason about when something is actually used or not, in other
situations it can be avoided, and show actual, dead code.
With experimental-sliding-sync enabled and e2e-encryption disabled,
there were a bunch of warnings about unused imports. This fixes them
(but a few warnings about other unused items remain).
I was investigating a potential deadlock with the event cache storage,
and only found a few places where to make the code a bit more idiomatic
and more readable.
`compute_display_name` is made private again, and used only within the
base crate. A new public counterpart `Room::display_name` is introduced,
which returns a cached value for, or computes (and fills in cache) the
display name. This is simpler to use, and likely what most users expect
anyways.
It claimed that it would immediately return when the cached display name
value was computed, but that's absolutely not the case.
Spotted while reviewing a PR updating `iamb` to the latest version of
the SDK.
Instead of keeping on handling unwedged events from the sending queue,
it's now required to re-enable the send queue manually for the room that
encountered the sending error, all the time. This is more consistent,
and avoids weird behavior when a user would 1. send an event for which
sending fails, in an unrecoverable manner, 2. send an event that's
actually sendable.
web-time's Instant type is already used elsewhere in the project. It is
an alias for std's Instant type on most targets, but tries to call into
JavaScript on wasm32-unknown-unknown (assuming that the wasm blob is
used in from a browser context). Its Duration type is a plain re-export
of std's Duration, even on wasm32-unknown-unknown.
Sometimes we can get the bytes directly, e.g. in Fractal we can get an
image from the clipboard. It avoids to have to write the data to a
temporary file only to have the data loaded back in memory by the SDK
right after.
The first commit to accept any type that implements `Into<String>` for
the filename is grouped here because it simplifies slightly the second
commit.
Note that we could also use `AttachmentSource` in the other
`send_attachment` APIs, on `Room` and `RoomSendQueue`, for consistency.
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Every caller to `with_events_mut` must propagate the vector diff
updates, otherwise updates would be missing to the room event cache's
observers. This slightly tweaks the signature to make this a bit
clearer, and adjusts the code comment as well.
`AttachmentConfig::with_thumbnail()` is replaced by
`AttachmentConfig::new().thumbnail()`.
Simplifies the use of `AttachmentConfig`, by avoiding code like:
```rust
let config = if let Some(thumbnail) = thumbnail {
AttachmentConfig::with_thumbnail(thumbnail)
} else {
AttachmentConfig::new()
};
```
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
A previous patch deduplicates the remote events conditionnally. This
patch does the same but for timeline items.
The `Timeline` has its own deduplication algorithm (for remote
events, and for timeline items). The `Timeline` is about to receive
its updates via the `EventCache` which has its own deduplication
mechanism (`matrix_sdk::event_cache::Deduplicator`). To avoid conflicts
between the two, we conditionnally deduplicate timeline items based on
`TimelineSettings::vectordiffs_as_inputs`.
This patch takes the liberty to refactor the deduplication mechanism of
the timeline items to make it explicit with its own methods, so
that it can be re-used for `TimelineItemPosition::At`. A specific
short-circuit was present before, which is no more possible with the
rewrite to a generic mechanism. Consequently, when a local timeline
item becomes a remote timeline item, it was previously updated (via
`ObservableItems::replace`), but now the local timeline item is removed
(via `ObservableItems::remove`), and then the remote timeline item is
inserted (via `ObservableItems::insert`). Depending of whether a virtual
timeline item like a date divider is around, the position of the removal
and the insertion might not be the same (!), which is perfectly fine as
the date divider will be re-computed anyway. The result is exactly the
same, but the `VectorDiff` updates emitted by the `Timeline` are a bit
different (different paths, same result).
This is why this patch needs to update a couple of tests.
This patch adds a trick around `SyncTimelineEvent` to avoid reaching the
`recursion_limit` too quickly. Read the documentation in this patch to
learn more.
The `Timeline` has its own remote event deduplication mechanism. But
we are transitioning to receive updates from the `EventCache` via
`VectorDiff`, which are emitted via `RoomEvents`, which already runs its
own deduplication mechanism (`matrix_sdk::event_cache::Deduplicator`).
Deduplication from the `EventCache` will generate `VectorDiff::Remove`
for example. It can create a conflict with the `Timeline` deduplication
mechanism.
This patch updates the deduplication mechanism from the `Timeline`
when adding or updating remote events to be conditionnal: when
`TimelineSettings::vectordiffs_as_inputs` is enabled, the deduplication
mechanism of the `Timeline` is silent, it does nothing, otherwise it
runs.
This patch adds the `AllRemoteEvents::range` method. This
is going to be useful to support `VectorDiff::Insert` inside
`TimelineStateTransaction::handle_remote_events_with_diffs`.
This patch adds the `ObservavbleItems::insert_remote_event` method.
This is going to be useful to implement `VectorDiff::Insert` inside
`TimelineStateTransaction::handle_remote_events_with_diffs`.
This patch adds a new variant to `RoomEventCacheUpdate`, namely
`UpdateTimelineEvents. It's going to replace `AddTimelineEvents` soon
once it's stable enough. This is a transition. They are read by the
`Timeline` if and only if `TimelineSettings::vectordiffs_as_inputs` is
turned on.
This patch adds `with_vectordiffs_as_inputs` on `TimelineBuilder` and
`vectordiffs_as_inputs` on `TimelineSettings`. This new flag allows to
transition from one system to another for the `Timeline`, when enabled,
the `Timeline` will accept `VectorDiff<SyncTimelineEvent>` for the
inputs instead of `Vec<SyncTimelineEvent>`.
Recently we started to differentiate between rooms we've been banned
from from rooms we have left on our own.
Sadly the non-left rooms matcher only checked if the room state is not
equal to the Left state. This then accidentally moved all the banned
rooms to be considered as non-left.
We replace the single if expression with a match and list all the
states, this way we're going to be notified by the compiler that we need
to consider any new states we add in the future.
When starting to back-paginate, in this test, we:
- either have a previous-batch token, that points to the first event
*before* the message was sent,
- or have no previous-batch token, because we stopped sync before
receiving the first sync result.
Because of the behavior introduced in 944a9220, we don't restart
back-paginating from the end, if we've reached the start. Now, if we are
in the case described by the first bullet item, then we may backpaginate
until the start of the room, and stop then, because we've back-paginated
all events. And so we'll never see the message sent by Alice after we
stopped sync'ing.
One solution to get to the desired state is to clear the internal state
of the room event cache, thus deleting the previous-batch token, thus
causing the situation described in the second bullet item. This achieves
what we want, that is, back-paginating from the end of the timeline.
This cleanup task will run while the knock request subscription runs and will use the `Room::room_member_updates_sender` notification to call `Room::remove_outdated_seen_knock_requests_ids` and remove outdated seen knock request ids automatically.
This will check the current seen knock request ids against the room members related to them and will remove those seen ids for members which are no longer in knock state or come from an outdated knock member event.
This sender will notify receivers when new room members are received: this can happen either when reloading the full room member list from the HS or when new member events arrive during a sync.
The sender will emit a `RoomMembersUpdate`, which can be either a full reload or a partial one, including the user ids of the members that changed.
The code would use a chunk iterator that moves forward, but call
`push_front()` repetitively on each chunk, semantically storing the
lengths in *reverse* order.
This could result in subsequent panics, when a new chunk was added,
because the links would not match what's expected (e.g. the last chunk
must have no successor, etc.).
This is a rough migration guide to help you upgrade your code using matrix-sdk 0.5 to the newly released matrix-sdk 0.6 . While it won't cover all edge cases and problems, we are trying to get the most common issues covered. If you experience any other difficulties in upgrade or need support with using the matrix-sdk in general, please approach us in our [matrix-sdk channel on matrix.org][matrix-channel].
## Minimum Supported Rust Version Update: `1.60`
We have updated the minimal rust version you need in order to build `matrix-sdk`, as we require some new dependency resolving features from it:
> These crates are built with the Rust language version 2021 and require a minimum compiler version of 1.60
## Dependencies
Many dependencies have been upgraded. Most notably, we are using `ruma` at version `0.7.0` now. It has seen some renamings and restructurings since our last release, so you might find that some Types have new names now.
## Repo Structure Updates
If you are looking at the repository itself, you will find we've rearranged the code quite a bit: we have split out any bindings-specific and testing related crates (and other things) into respective folders, and we've moved all `examples` into its own top-level-folder with each example as their own crate (rendering them easier to find and copy as starting points), all in all slimming down the `crates` folder to the core aspects.
## Architecture Changes / API overall
### Builder Pattern
We are moving to the [builder pattern][] (familiar from e.g. `std::io:process:Command`) as the main configurable path for many aspects of the API, including to construct Matrix-Requests and workflows. This has been and is an on-going effort, and this release sees a lot of APIs transitioning to this pattern, you should already be familiar with from the `matrix_sdk::Client::builder()` in `0.5`. This pattern been extended onto:
- the [login configuration][login builder] and [login with sso][ssologin builder],
Most have fallback (though maybe with deprecation warning) support for an existing code path, but these are likely to be removed in upcoming releases.
### Splitting of concerns: Media
In an effort to declutter the `Client` API dedicated types have been created dealing with specific concerns in one place. In `0.5` we introduced `client.account()`, and `client.encryption()`, we are doing the same with `client.media()` to manage media and attachments in one place with the [`media::Media` type][media typ] now.
The signatures of media uploads, have also changed slightly: rather than expecting a reader `R: Read + Seek`, it now is a simple `&[u8]`. Which also means no more unnecessary `seek(0)` to reset the cursor, as we are just taking an immutable reference now.
### Event Handling & sync updaes
If you are using the `client.register_event_handler` function to receive updates on incoming sync events, you'll find yourself with a deprecation warning now. That is because we've refactored and redesigned the event handler logic to allowing `removing` of event handlers on the fly, too. For that the new `add_event_handler()` (and `add_room_event_handler`) will hand you an `EventHandlerHandle` (pardon the pun), which you can pass to `remove_event_handler`, or by using the convenient `client.event_handler_drop_guard` to create a `DropGuard` that will remove the handler when the guard is dropped. While the code still works, we recommend you switch to the new one, as we will be removing the `register_event_handler` and `register_event_handler_context` in a coming release.
Secondly, you will find a new [`sync_with_result_callback` sync function][sync with result]. Other than the previous sync functions, this will pass the entire `Result` to your callback, allowing you to handle errors or even raise some yourself to stop the loop. Further more, it will propagate any unhandled errors (it still handles retries as before) to the outer caller, allowing the higher level to decide how to handle that (e.g. in case of a network failure). This result-returning-behavior also punshes through the existing `sync` and `sync_with_callback`-API, allowing you to handle them on a higher level now (rather than the futures just resolving). If you find that warning, just adding a `?` to the `.await` of the call is probably the quickest way to move forward.
### Refresh Tokens
This release now [supports `refresh_token`s][refresh tokens PR] as part of the [`Session`][session]. It is implemented with a default-flag in serde so deserializing a previously serialized Session (e.g. in a store) will work as before. As part of `refresh_token` support, you can now configure the client via `ClientBuilder.request_refresh_token()` to refresh the access token automagically on certain failures or do it manually by calling `client.refresh_access_token()` yourself. Auto-refresh is _off_ by default.
You can stay informed about updates on the access token by listening to `client.session_tokens_signal()`.
### Further changes
- [`MessageOptions`][message options] has been updated to Matrix 1.3 by making the `from` parameter optional (and function signatures have been updated, too). You can now request the server sends you messages from the first one you are allowed to have received.
-`client.user_id()` is not a `future` anymore. Remove any `.await` you had behind it.
-`verified()`, `blacklisted()` and `deleted()` on `matrix_sdk::encryption::identities::Device` have been renamed with a `is_` prefix.
-`verified()` on `matrix_sdk::encryption::identities::UserIdentity`, too has been prefixed with `is_` and thus is now called `is_verified()`.
- The top-level crypto and state-store types of Indexeddb and Sled have been renamed to unique types>
-`state_store` and `crypto_store` do not need to be boxed anymore when passed to the [`StoreConfig`][store config]
- Indexeddb's `SerializationError` is now `IndexedDBStoreError`
- Javascript specific features are now behind the `js` feature-gate
- The new experimental next generation of sync ("sliding sync"), with a totally revamped api, can be found behind the optional `sliding-sync`-feature-gate
## Quick Troubleshooting
You find yourself focused with any of these, here are the steps to follow to upgrade your code accordingly:
### warning: use of deprecated associated function `matrix_sdk::Client::register_event_handler`: Use [`Client::add_event_handler`](#method.add_event_handler) instead
As it says on the tin: we have deprecated this function in favor of the newer removable handler approach (see above). You can still continue to use this `fn` for now, but it will be removed in a future release.
### warning: use of deprecated associated function `matrix_sdk::Client::login`: Replaced by [`Client::login_username`](#method.login_username)
We have replaced the login facilities with a `LoginBuilder` and recommend you use that from now on. This isn't an error yet, but the function will be removed in a future release.
### expected slice `[u8]`, found struct ...
We've updated the `send_attachment` and `Media` signatures to use `&[u8]` rather than `reader: Read + Seek` as it is more convenient and common place for most architectures anyways. If you are using `File::open(path)?` to get that handler, you can just replace that with `std::fs::read(path)?`
### no method named `verified` found for struct `matrix_sdk::encryption::identities::Device` in the current scope
Boolean flags like `verified`, `deleted`, `blacklisted`, etc have been renamed with a `is_` prefix. So, just follow the cargo suggestion:
```
|
69 | device.verified()
| ^^^^^^^^ help: there is an associated function with a similar name: `is_verified`
Ruma has been updated to `0.7.0`, you will find some ruma Events names have changed, most notably, the `AnySyncRoomEvent` is now named `AnySyncTimelineEvent` (and not `AnySyncStateEvent`, which cargo wrongly suggests). Just rename the import and usage of it.
### `std::option::Option<&matrix_sdk::ruma::UserId>` is not a future
You are seeing something along the lines of:
```
19 | if room_member.state_key != client.user_id().await.unwrap() {
| ^^^^^^ `std::option::Option<&matrix_sdk::ruma::UserId>` is not a future
|
= help: the trait `Future` is not implemented for `std::option::Option<&matrix_sdk::ruma::UserId>`
= note: std::option::Option<&matrix_sdk::ruma::UserId> must be a future or must implement `IntoFuture` to be awaited
= note: required because of the requirements on the impl of `IntoFuture` for `std::option::Option<&matrix_sdk::ruma::UserId>`
help: remove the `.await`
|
19 - if room_member.state_key != client.user_id().await.unwrap() {
19 + if room_member.state_key != client.user_id().unwrap() {
```
You are using `client.user_id().await` but `user_id()` is no longer `async`. Just follow the cargo suggestion and remove the `.await`, it is not necessary any longer.
-`Client::subscribe_to_room_info` allows clients to subscribe to room info updates in rooms which may not be known yet.
This is useful when displaying a room preview for an unknown room, so when we receive any membership change for it,
we can automatically update the UI.
-`Client::get_max_media_upload_size` to get the max size of a request sent to the homeserver so we can tweak our media
uploads by compressing/transcoding the media.
- Add `ClientBuilder::enable_share_history_on_invite` to enable experimental support for sharing encrypted room history on invite, per [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268).
- The `dynamic_registrations_file` field of `OidcConfiguration` was removed.
Clients are supposed to re-register with the homeserver for every login.
- `RoomPreview::own_membership_details` is now `RoomPreview::member_with_sender_info`, takes any user id and returns an `Option<RoomMemberWithSenderInfo>`.
Additions:
- Add `Encryption::get_user_identity` which returns `UserIdentity`
- Add `ClientBuilder::session_pool_max_size`, `::session_cache_size` and `::session_journal_size_limit` to control the stores configuration, especially their memory consumption
- Add `Room::member_with_sender_info` to get both a room member's info and for the user who sent the `m.room.member` event the `RoomMember` is based on.
returnErr(ClientError::Generic{msg: "Failed creating timeline because the configuration is set to report UTDs but no hook manager is set".to_owned(),details: None});
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.