This function returns an iterator with all the available rooms that match the behaviour previously in `Client::get_dm`. `Client::get_dm` now just calls this function and returns the first item.
I believe that it is a footgun to cache the data indefinitely by default
so this copies the same behavior as for the supported versions in the
ClientCaches: it sets an expiry duration of 1 day and refreshes the data
in the background when it has expired.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This API is no longer in use so we can remove it. We also rename
`into_data_unchecked()` to `into_data()`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The previous behavior was making the data unavailable as soon as it is
expired, forcing the user to make a request to access fresh data. This
change keeps the data after it is expired, allowing the function to
return quickly, and triggers a background task to refresh it so that
later calls will be able to use the updated data.
This is a step towards #6090. While it's not clear in the issue what
should be the trigger for the background refreshes, this implements at
least the background refresh while keeping the expiry time as a trigger.
The next steps are to apply this to other cached values and shorten the
expiry time to something like 1 day, which should be more helpful.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Its is now available as `matrix_sdk_common::ttl_cache::TtlValue`,
allowing to use it outside of a store.
It also supports deserializing data without a timestamp, to allow to
add an expiration time to data that was already persisted.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Since the boolean is read only once when subscribing the event cache,
let's make it clear when the FFI function should be called (based on
most prominent types used at the FFI layer).
This patch fixes a critical infinite loop when loading pinned events
from the storage if and only if there is more than one chunk for the
pinned events.
The previous implementation was broken in two ways:
1. if there was no previous chunk, then `prev` was set to `None`, but
`previous` was never updated, so it was loop forever,
2. `load_previous_chunk` was called with the `last_chunk.previous` chunk
identifier, which is incorrect: it must be called with the last chunk
identifier, not the previous': otherwise it skips one chunk every time.
This patch adds a test to ensure everything works as expected.
Fixes#5902
## What this PR does
Keeps the existing `Client::send()` demo but extends it with:
- A doc comment on `get_profile` explaining the spec behaviour and the 401
condition on (Synapse's `require_auth_for_profile_requests`)
- A `get_profile_authenticated()` fallback using `account().fetch_user_profile()`
which internally uses `force_auth()`
The current implementation assumes that if the `m.profile_fields`
capability is missing, it means that the capability is not enabled, but
this is not what the spec says. However the spec says that it depends on
the Matrix versions advertised by the homeserver. So this adds a method
that properly computes the capability depending on the supported
versions too.
Similarly, for the display name and avatar URL fields the implementation
assumes that if the `m.profile_fields` capability is present but
disabled, we should fallback to the legacy capabilities. This behavior
is not present in the spec, so the code is changed to always use the new
capability when it is present, whether it is enabled or not. The
legacy capabilities are only used if the new capability is missing and
the homeserver doesn't advertise support for extended profile fields.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This test forgot to subscribe to the Event Cache, hence the result
was partially okay. It was working by luck before. With the previous
commits, it was not possible to work without the Event Cache being
listening to the sync.
This patch adjust tests since the Event Cache ignores events from the
Send Queue if the cache is empty. It mostly impacts the tests as this
scenario is pretty rare in real world use cases.
This patch fixes a bug where inserting an event from the Send Queue in
an empty Event Cache will break the back-pagination logic. Indeed, the
detection of the start of the timeline during the back-pagination is
conditioned to the emptiness of the cache:
- if there is no gap, and if the cache is not empty, then we consider
the start of the timeline has been reached.
However, if an event from the Send Queue has been inserted, with no
previous batch token (because none can be computed at this step), no gap
is present and the cache won't be empty, so… this is wrongly assumed to
be the start of the timeline.
The solution to this problem is to insert the event from the Send Queue
if the cache is not empty.
This patch updates the logic to update a `LatestEventValue`. We still
can't compare two `LatestEventValue` because the type doesn't implement
`PartialEq`. However, we can use the `EventId` in some case.
It fixes https://github.com/matrix-org/matrix-rust-sdk/issues/6381.
This patch fixes the SpaceRoom::compare_rooms method to be transitive
(If A ≤ B and B ≤ C then A ≤ C). The transitive property of a comparison
function is required by the sorting functions we are using.
If the property doesn't hold, sorting will panic.
The previous logic violated strict weak ordering by falling back towards
room ID comparison as soon as one of the values doesn't have a
SpaceRoomChildState.
This introduced inconsistent ordering paths where:
- A and B would be compared using the SpaceRoomChildState
- B and C would be compared using only the room ID
- A and C would be compared using only the room ID
Leading to the case where:
- A < B due to the state
- B < C due to the room ID
- and finally A > C due to the room ID.
As a result, transitivity could be broken (A < B, B < C, but C < A),
leading to a panic during the sorting.
Several new functions implicitly rely on the sqlite config.
sqlite might not be present if you are using the indexedb store, in which case
these functions are likely irrelevant.
This change conditionalizes their compilation.
matrix_sdk_ffi::ruma::TagName and matrix_sdk_ffi::event::TimelineEventType enums
that are used as HashMap keys by matrix_sdk_ffi::ruma::Tag and
matrix_sdk_ffi::room::power_levels::RoomPowerLevels respectively should probably
export Eq and Hash traits, so that we can generate bindings for languages that
implement uniffi's record/HashMap type using a hash table (e.g.
std::unordered_map in C++)
Signed-off-by: Stanislav Skobelkin <stanislav@skobelk.in>
This allows people to get a secrets bundle out of band or out of a database and import it
after logging in a new client.
Mainly targeted to support the Element Classic -> Element X migration.
Signed-off-by: Damir Jelić <poljar@termina.org.uk>
Co-authored-by: Benoit Marty <benoitm@matrix.org>
Previously there wasn't a way to determine whether a given sub-space or
room within a given space had been marked as "suggested".
This was one of the things missing in support for spaces (#227) even
though it wasn't explicitly mentioned.
I tested that this fix does work properly in
[Robrix](https://github.com/project-robius/robrix).
Signed-off-by: Kevin Boos kevinaboos@gmail.com
This is a first step towards
https://github.com/matrix-org/matrix-rust-sdk/issues/4162 and adds a way
to send redactions (including their local echoes) via the send queue.
I had to introduce new variants for `SentRequestKey` and
`LocalEchoContent` because in some room versions the redacted event ID
sits at the top-level of the event rather than in `content`.
At the timeline level redactions are handled via a new boolean flag in
`AggregationKind::Redaction`. Local echoes of redactions merely set a
flag on the timeline event whereas remote echoes of redactions lead to
actual redactions as before.
The FFI bindings will be updated in a follow-up PR.
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Note that the rustls-tls feature flag is temporarily left in place
to keep other crates from breaking, but it becomes a trivial flag.
It will be removed altogether in a later commit.
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
This allows for notifications to use the intent for deciding how to
render the message (e.g. whether to call it a "call" or a "video call").
Signed-off-by: Bryant Mairs <bryant@mai.rs>
The previous warning could trigger with abnormal numbers, since there
could be related events applying to a pinned event, the `loaded_events`
list could be bigger than the list of `pinned_event_ids`, due to the
eager flattening. This patch makes it display the correct number, by
postponing the flattening after the warning.
For non-live timelines, the recurring pattern was the following:
- first, fill the timeline with initial events, with a first call to
some form of subscribe() method,
- then, subscribe to updates in a second time later, using a second call
to the same subscribe() method.
Unfortunately, this is wrong, and opens a window for a very small race:
- first call to subscribe() to get the initial events
- new updates are emitted in the receiver, that lead to new events
- second call to subscribe() to get the receiver, and subscribe to it
In this case, the new updates would be lost by an observer.
The patch consists in refactoring timeline initialization, such that the
initial events and receiver are created at the same time; if there are
some updates happening after the now single subscribe() call, the
updates are accumulated and will be observable by external users.
This also has the nice benefit of tidying up the number of background
task handles for non-live timelines: there should be at most one such
focus task, which is now cleanly reflected in the timeline drop handles.
The issue is that when the most recent message was an live location event that started as live and later transitioned to a stopped state, the room list summary would ignore it entirely, even though the timeline still showed it as the latest item.
That behaviour feels incorrect. At most, the client should update the displayed description based on whether isLive is true or not.
This patch prevents the stopped live location events from being filtered out in the latest events.
This extracts the `/capabilities` logic to its own `HomeserverCapabilities` component in the SDK that can be manually asked to fetch, cache locally and return these capabilities.
### Expose sync v2 API through FFI via `Client.sync()` and
`Client.sync_once()` #6348
Mobile clients can now sync using the traditional `/sync` v2 endpoint
through the FFI bindings, without requiring Sliding Sync (MSC4186)
support on the homeserver.
This PR introduces a new API (non-breaking change).
#### Implementation notes
I chose to expose only the **list of room IDs** (invited, joined, left,
knocked) in the `SyncResponse`, rather than forwarding the full per-room
event payloads. This keeps the FFI surface simple. Clients that need
room details can query them through the existing `Room` APIs after being
notified of changes via the listener.
Two entry points are provided:
- **`Client.sync(settings, listener)`** starts a continuous sync loop,
returning a `TaskHandle` for cancellation. The `SyncListener` callback
fires after each successful sync response.
- **`Client.sync_once(settings)`** performs a single sync call, useful
for initial sync or one-off use cases.
`SyncSettings` exposes `timeout_ms` and `full_state`.
Signed-off-by: Philippe Bertin <pbertin@teladochealth.com>
This avoids profile updates when a user decides to leave on their own (in which case their profile is kept as is), and when a user is banned (in which case their profile is removed).
Signed-off-by: JoFrost <20685007+JoFrost@users.noreply.github.com>
This means that when some caller is subscribing to the `EventCache`,
even if the event cache drops in the background, the task will remain
active until the end of the subscriber.
There wasn't good reason to use an async lock, as this lock is always
super short-lived, it can be sync, which avoids complications in the
subsequent commit when calling sync init code.
- Change the example config file to not make it appear as though it
processes environment variables
- Remove the `ar` setting from the example config file, as that setting
is deprecated and unused (see
https://doc.rust-lang.org/cargo/reference/config.html#targettriplear)
- Replace references of `.cargo/config` to `.cargo/config.toml`, as the
former is deprecated
- Add example of how to set the linker through an environment variable
- Add instruction to include the NDK binary tools directory to PATH,
because builds may fail without it
(see https://github.com/matrix-org/matrix-rust-sdk/issues/4042)
When ThreadListService is created it now immediately spawns a background
task (via the client's TaskMonitor) that subscribes to the room event
cache and listens for RoomEventCacheUpdate::UpdateTimelineEvents.
For every incoming event that carries an m.thread relation pointing to a
root we are already tracking, the service rebuilds a ThreadListItemEvent via the
existing build_latest_event helper and replaces latest_event on the matching
ThreadListItem and increments num_replies by 1
Introduce ThreadListItemEvent as a shared struct for both the thread
root and the latest reply, replacing the previous flat fields on
ThreadListItem
The `latest_event` is populated from the bundled thread summary returned by the
server alongside the root event, as is the number of replies.
We think this might be a cause for intermittent failures of the
`room_unread_count` test on CI, as the `room_info` might be outdated
after we decided to process it.
More generally, the room info is a critical resources that should be
protected in better ways, as it's inner mutable state that can be
modified by all code claling `set_room_info` in any place, but that'll
be a problem for later.
`ThreadListService` is the FFI-facing wrapper around
[`matrix_sdk_ui::timeline::thread_list_service::ThreadListService`]. It
maintains an observable list of [`ThreadListItem`]s and exposes a
pagination state publisher, making it straightforward to build reactive UIs
on top of the thread list.
This patch updates the fuzzy filter from using _smart case_ to _ignore
case_. Most of the time, the keyboard might activate an upper case for
the first character pressed in the search bar. Some users aren't used
to smart case and will believe there is a bug. Let's disable smart case
here.
This will skip using the custom workaround for Android and the latest rustls, but since that was to fix an issue with the verifier and the verifier is not used anymore, it should be fine
There was a hack added that the unread count of a room shouldn't
decrease, if the room's latest active receipt hasn't changed.
Unfortunately, this heuristic doesn't hold: if an event was counted
because it was encrypted, and it turns out that after decrypting it as a
UTD, it should now be uncounted, then the read count would in fact
legitimately decrease.
Let's remove this hack, and in the meantime keep on working on automatic
backpagination, which should help fix this kind of issues.
<!-- description of the changes in this PR -->
Depends on: https://github.com/ruma/ruma/pull/2414
Partity with web/js-sdk.
Allows to get the consus intent for the current call using the
membership `m.call.intent`
EW use it to change the icon in the room list
<img width="298" height="117" alt="image"
src="https://github.com/user-attachments/assets/21e59f69-e099-40a6-ae27-d9246df35b64"
/>
- [x] I've documented the public API Changes in the appropriate
`CHANGELOG.md` files.
- [ ] This PR was made with the help of AI.
<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by:
The test shows a situation where an in-thread message would be counted
as an implicit receipt, while, when we're in the `main` timeline mode,
we're counting unreads only for the main timeline. In this case, the
test would fail because the unread counts would be set to 0, since
select_best_receipt would have selected $3.
The patch is to *not* select an implicit receipt, in that mode, when
it's in a thread.
Related to https://github.com/element-hq/element-x-android/pull/6420
Part of https://github.com/element-hq/element-x-android/issues/5075
I noticed when investigating a bug about resetting your identity when
using a MAS login that we poll the server checking whether the user has
given us permission with no limit on how fast we poll, and with no
ability to give up if it's not working.
This change causes us to retry only twice per second, and give up after
2 minutes. These are guesses as to the right values and I am open to
discussion.
This adds back the `webpki` verifier and sets it to a custom rustls instance created only for Android, instead of using the platform verifier that results in false positives with Let's Encrypt certs (and from other CAs).
See https://github.com/matrix-org/matrix-rust-sdk/issues/6319
My only guess for this semantic change, is that the pagination status
update and the end of the pagination now happen at different times, or
close enough that they're regrouped in the same stream update. This
doesn't fundamentally change the semantics, so we'll see if this holds
on slower machines (e.g. CI).
- use the modern MatrixMockServer facilities
- provide a previous-batch token so as not to wait for the initial batch
token
- lower the delay for the /messages responses to 1 sec
This makes it possible to common out the implementations of functions
that should be available to both kinds.
Also, moves a bit of code that could easily live in the
`RoomEventCacheState` impl block, instead of being free functions.
There was a subtle bug that a receipt would be considered active, and
then on the subsequent call to `select_best_receipt`, it could be
forgotten in favor of an older receipt. The regression test shows one
such case, where before this patch, the count would incorrectly say 3,
not 2, because the active read receipt moved backwards to the implicit
receipt.
The solution is to stop looking for a better receipt, if we run into the
latest active read receipt. Having `found` set to `None` in this case
means we hadn't found any better read receipt anyways.
It turns out on Android, rustls needs [a custom setup](https://github.com/rustls/rustls-platform-verifier#android) and adding the `rustls-platform-verifier-android` library that's [not available on Maven](https://github.com/rustls/rustls-platform-verifier/issues/115).
Then, from the Android clients we'd need to call some exposed JNI function so we can provide a JVM context from where Rust can take the `Application` component and access its contents to read its credentials storage. Thanks to some tricks we can use `libloading` to simulate this call from Rust itself and properly initialise the platform verifier.
Note self-signed certificates will no longer work with these changes on Android, and providing them in `ClientBuilder::add_root_certificates` will make most requests fail. This can be handled separately.
This method is now only used by tests, so I opted to lock it
behind the test configuration to appease CI.
Signed-off-by: Skye Elliot <actuallyori@gmail.com>
This patch removes the `enable_latest_event_sorter` flag in
`RoomList::entry_with_dynamic_adapters_with`. This sorter is now stable
enough, we can always enable it.
The method
`RoomEventCacheStateLockWriteGuard::load_more_events_backwards` is used
only in one-place: in `RoomPagination::load_more_events_backwards`. This
patch inlines this method as it aims at living in `RoomPagination`, not
somewhere else.
It's purely code move. Nothing else has changed.
This patch also updates a test that was accessing
`load_more_events_backwards` directly. Now it runs it via
`RoomPagination`.
This patch updates `ThreadPagination` to hold a `ThreadEventCacheInner`
instead of a `RoomEventCacheInner`! It makes more sense and it
splits/isolates the types even more.
`RoomEventCache::thread_pagination` is now async and returns a
`Result<ThreadPagination>` because it needs to load its state to fetch
a `ThreadEventCache`. Later, accessing a thread wouldn't happen in
`RoomEventCache` but in `Caches`, one step at a time.
This patch adds the `weak_room: WeakRoom` field to
`ThreadEventCacheInner`. This is a prerequisite to have
`ThreadPagination` uses `ThreadEventCacheInner` instead of
`RoomEventCacheInner`!
This patch creates the `ThreadEventCacheState` type. It uses
`caches::lock::StateLock`, just like `RoomEventCacheState`. It allows
to have the `read()` and `write()` method to access the state, and to
reload it when necessary, see the `caches::lock::Store` implementation.
This patch thus creates `ThreadEventCacheStateLockReadGuard` and
`ThreadEventCacheStateLockWriteGuard`. The methods touching the state in
`ThreadEventCacheInner` are moved to these lock types.
They are purely code moves (plus changes to reach the correct data): no
change in the semantics.
This patch creates `ThreadEventCacheInner` so that `ThreadEventCache`
can be shallow cloned (which will be useful for `ThreadPagination`).
That's also the first step to introduce `ThreadEventCacheState`!
The new integration tests for the event cache cover the same situations
that were tested by the previous tests on compute_unread_count_legacy,
so we're fine here.
A gappy sync may cause a linked chunk to shrink, waiting for callers to
lazy-reload it again in the future. But, because the unread counts
computation rely on the in-memory linked chunk, this means that the
values computed for the unread count may be incorrect (and decrease).
Fortunately, this situation is rather easy to detect, because the latest
active read receipt doesn't change in this case, so we can first check
that, and then manually readjust the unread counts, if they've
decreased.
Future work should trigger back-pagination in those cases, so the unread
counts keeps on being precise, despite the gappy sync.
This test exhibits an edge case: when a room event cache is shrunk
(because of a gappy/limited sync), then the unread count might decrease,
without the latest active read receipt changing.
`test_room_notification_count` started to intermittently fail on main,
because the computation of unread counts has moved from the sliding sync
processing to the event cache. As a result, new irrelevant RoomInfo
updates (related to the unread counts) can happen, and they might happen
quickly enough that the server reponse for sending an event happens
after 2 seconds (remember, we need to factor in the time to do the e2ee
key exchange, and so on and so forth).
Bumping the time between two RoomInfo updates should be sufficient to
avoid the intermittent failure.
This patch fixes a bug in `xtask log sync` which can miss a `sync_once`
log when the `pos` field is absent. It happens when there is no `pos`!
Example where `pos` is absent before `timeout`. Note the double space
before `timeout`:
```
… > sync_once{conn_id="room-list" timeout=0} > send{request_id="REQ-15" …
```
While when the `pos` is present, it's:
```
… > sync_once{conn_id="room-list" pos="0/m67590980…" timeout=30000} > send{request_id="REQ-23" …
```
This is a basic implementation that works, but it should unlock
improvements already (getting the unread count updated whenever a UTD
has been resolved) and it will pave the way for future improvements
(notably with respect to performance).
This is almost only code motion in this commit.
At this point, some tests don't pass, as the support for using the read
receipt code in the event cache isn't plugged in to the event cache
itself.
This patch makes `RoomEventCacheInner` more private, from `event_cache`
to `event_cache::caches`.
Consequently, `PinnedEventCacheState`, `RoomPagination::new` and
`ThreadPagination::new` follows the same restriction.
This patch makes `RoomEventCache::new`,
`RoomEventCache::handle_joined_room_update` and
`RoomEventCache::handle_left_room_update` more private. They are no more
accessible from `event_cache` but only from `event_cache::caches`.
This patch moves `test_uniq_read_marker` from `event_cache` to
`event-cache::caches::room`.
This patch is a prerequisite to the next patch where the
`RoomEventCache::handle_joined_room_update` will become more private.
Moving this test is necessary.
This patch moves `EventLocation` from `event_cache::caches::room` to
`event_cache::caches`.
This type is used by the redecryptor, and can possibly be used by other
event caches. So let's move it in the `caches` module.
This patch puts the `EventCache::subscribe_thread_subscriber_updates`
method behind `#[cfg(feature = "testing")]` along with the
`EventCacheInner::thread_subscriber_receiver` field.
This data is only used for tests, as the documentation tells so. Let
make it clear. Also, it reduces the size `EventCacheInner` by 16 bytes
for non-testing builds.
This patch updates `EventCacheInner::all_caches_for_rooms` by returning
an `OwnedRwLockReadGuard` instead of `Caches`. `Caches` no longer
implement `Clone`, which prevents cloning all the event caches per room
when we need only one for example.
`Caches` has two new methods: `handle_joined_room_update` and
`handle_left_room_update`. This type acts more like a dispatcher now,
which was the initial idea. That way, we don't need to dispatch manually
on all event caches: `Caches` is responsible for that.
We need to be a bit careful now since `all_caches_for_rooms` returns an
owned read-lock over `EventCacheInner::by_room`.
This patch introduces the `Caches::prepare_to_reset` method, which
returns a `ResetCaches` type. This new type is responsible to lock all
the event caches related to a room, and to reset their in-memory state
with `ResetCaches::reset_all`. This patch fixes 2 bugs (see below).
This type is acquiring exclusive locks over all the event caches
managed by `Caches`. Once dropped, all the locks are released. Note that
`ResetCaches::reset_all` takes `self`, not `&self` or `&mut self`, i.e.
it consumes `ResetCaches`, ensuring the locks are _always_ released.
This patch also fixes a possible bug when acquiring the exclusive
locks could have failed, but the error wasn't stopping the execution;
the database would have been reset anyway. Now, `try_join_all` is used
before and after resetting the database (prior to this patch, it was
using `join_all` before resetting the database).
This patch also ensures that only one reset per `Caches` can
happen at a time, by making `Caches::prepare_to_reset` taking a
`&mut self`. This was partially supported by the write lock over
`EventCacheInner::by_room`, but it would have still been possible to
reset the same `Caches` concurrently.
This patch is the first step for the `Caches` type. It creates it, along
with the `new` constructor. More changes are required, but this is a
first step.
The pattern `Caches { room }` is used everywhere where a
`RoomEventCache` was read previously, so that we are sure the type
system will complain when we will add more fields to `Caches` (like for
threads and pinned events).
This isn't strictly necessary, but the lack of these events was
causing spurious CI timeouts when tested with the logic that
assumed a stricter history visibility than the spec required.
This commit additionally flips the order of a few assertions to
meet developer expectations, i.e. errors are reported as diffs
from expected.
Signed-off-by: Skye Elliot <actuallyori@gmail.com>
- https://github.com/matrix-org/matrix-spec-proposals/blob/matthew/location/proposals/3488-location.md
- `If m.asset is missing from the location's content the client should render it as m.self as that will be the most common use case. Otherwise, if it's not missing but the type is invalid or unknown the client should attempt to render it as a generic location. Clients should be able to distinguish between m.self and explicit assets for this feature to be correctly implemented as interpreting everything as m.self is unwanted.`
- this aligns the behavior with the newly introduced live location asset type handling
# Overview
There are scenarios in which it is sensible to have an event exist in
the same room more than once. Notably, this is true in the context of a
thread, where an event exists in the main timeline of a room, as well as
in a thread of that same room.
Support for this behavior has been implemented in the
`SQLiteEventCacheStore` in #6065; however, this was never implemented
for the `IndexeddbEventCacheStore` or the `MemoryStore`. This pull
request extends this behavior to both of those stores.
# Changes
## Integration Tests
First, `test_event_chunks_allows_same_event_in_room_and_thread` was
moved from `matrix_sdk_sqlite::event_cache_store` to
`matrix_sdk_base::event_cache::store::integration_tests`. Then, a few
additional integration tests were added to ensure that behavior is
consistent across implementations of `EventCacheStore`.
## `IndexeddbEventCacheStore`
In order to accommodate the behavioral changes specified by the
integration tests, it was necessary to modify the schema in the
IndexedDB implementation of `EventCacheStore`. Namely, the events object
store was cleared and removed and then replaced with a nearly identical
one, the only difference being the removal of a uniqueness constraint on
one of the indices.
The remaining changes mostly involved updating the behavior of top-level
`EventCacheStore` functions - e.g., filtering out events where they were
duplicated or removing positioning information where it was not
relevant.
## `MemoryStore`
The changes to `MemoryStore` mostly involved updating the behavior of
top-level `EventCacheStore` function - e.g., filtering out events where
they were duplicated or removing positioning information where it was
not relevant.
That being said, it also involved some breaking changes to
`RelationalLinkedChunk`.
1. `RelationalLinkedChunk::items` - this function returned an `Iterator`
that did not contain information about the `LinkedChunkId`, so this
information was added to the items in the `Iterator`.
2. `RelationalLinkedChunk::save_item` - this function did not update the
item in all linked chunks of the provided `Room`. It now does this, but
requires that the provided `Item` be `Clone`.
(1) could probably have been a new function, but I thought a nicer
interface was worth the breaking change. (2) could probably be prevented
by re-organizing `RelationalLinkedChunk`'s internal data structures to
remove the `Clone` requirement, but that seemed like it could turn into
a large refactoring project, so I opted for something simpler albeit
somewhat crude.
In both cases, I'm open to suggestions and would be happy to revisit if
something else is preferred.
---
Closes#6094.
- [x] I've documented the public API Changes in the appropriate
`CHANGELOG.md` files.
- [x] I've read [the `CONTRIBUTING.md`
file](https://github.com/matrix-org/matrix-rust-sdk/blob/main/CONTRIBUTING.md),
notably the sections about Pull requests, Commit message format, and AI
policy.
- [ ] This PR was made with the help of AI.
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
---------
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
**Note:** _this pull request has a companion pull request in the
[`complement-crypto`](https://github.com/matrix-org/complement-crypto/pull/229)
repository, which must be merged in conjunction with this one._
_Before merging, this should be tested in conjunction with the Element X
iOS client to ensure that TLS v1.3 is working properly._ @stefanceriu
has agreed to work on this.
## Overview
The primary change in this pull request upgrades the `reqwest`
dependency to its latest version, which defaults to using `rustls` with
support for `rustls-platform-verifier` instead of `native-tls` (see
[`reqwest@0.13.0`](https://github.com/seanmonstar/reqwest/releases/tag/v0.13.0)).
The benefit here is that `rustls` supports TLS v1.3 on all platforms,
whereas [`native-tls` does
not](https://github.com/sfackler/rust-native-tls/pull/278).
Additionally, this pull request makes `rustls` the default TLS
implementation in all the crates in this repository.
This will be particularly helpful with element-hq/element-x-ios#786.
## Changes
- `reqwest` bumped to `0.13.1`
- The API for adding/replacing certificates has changed a bit, so this
required some updating in `HttpSettings::make_client`
- `oauth2-reqwest` added in favor of `oauth2/reqwest`
- This is required in order to be compatible with `reqwest^0.13`
- _**`oauth2-reqwest` is currently in alpha release, so it probably
makes sense to let this stabilize a bit.**_ For details, see
https://github.com/ramosbugs/oauth2-rs/issues/333#issuecomment-3906712203.
- `getrandom` bumped to `0.3.4`
- This is required in order to be compatible with `oauth2@5.1.0`
- `proptest` bumped to `1.9.0`
- This is required in order to be compatible with `getrandom@0.3.4`
- Make `rustls` the default TLS implementation
## Questions
### Mirror feature flag names?
A number of feature flags have been replaced in the dependencies above.
1. _**`reqwest/rustls-tls` => `reqwest/rustls`**_ - this is simply a
name change, but is semantically identical (see
[`reqwest@0.13.0`](https://github.com/seanmonstar/reqwest/releases/tag/v0.13.0)).
2. _**`getrandom/js` => `getrandom/wasm_js`**_ - the semantics here have
changed slightly, but it seems to just make it easier to enable the
`wasm_js` backend (see
[`getrandom@0.3.4`](https://github.com/rust-random/getrandom/blob/master/CHANGELOG.md#major-change-to-wasm_js-backend)).
At any rate, I have updated references to these flags in each of the
various `Cargo.toml` files, but have not changed the names of our
exposed features to mimic those in the dependencies.
Any thoughts or preferences on whether to mirror those names? That
would, of course, result in a breaking change.
### Default to using `rustls`? Deprecate `native-tls`?
Now that the dependencies have all been bumped, we can use `rustls` on
all platforms. Should this be the new default given that `native-tls`
will very likely never support TLS v1.3 on Apple devices? And should
`native-tls` be deprecated as a result?
**UPDATE:** _The consensus here seems to be that we should default to
using `rustls`, but that `native-tls` should still be available._
---
Fixes#5800.
- [ ] Public API changes documented in changelogs (optional)
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
---------
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
Turns out, the `m.read` event was invalid, because it should've been
part of the ephemeral events in the sync response (and not part of the
room's timeline response), so the event was dismissed. The test already
passed while behaving this way, so let's make it reflect what it did
indeed.
The test was aborted just a bit too early, in that if you introduce
arbitrary sleep statements, it would fail because the stream of notable
reasons updates wouldn't be empty, and include two `LATEST_EVENT`
updates instead.
It's not clear why we get the second update, but this isn't critical to
fix at the moment, so I'll leave this as an exercise to the reader.
This will allow to reuse it outside of the `oauth` module.
It can now also be converted from a `QueryString`, for improved
compatibility with `LocalServerRedirectHandle`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The log message can contain HTML data. It happens notably when the
homeserver is broken, and an HTML document is returned in some errors.
We don't want to parse the fields in this case, because HTML breaks
everything.
We rely on the EventFactory to generate a hash of the events for the
event IDs, and we use the appropriate length for room IDs.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
We rely on the EventFactory to generate a hash of the events for the
event IDs, and we use the appropriate length for room IDs.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
We rely on the EventFactory to generate a hash of the events for the
event IDs, and we use the appropriate length for room IDs.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
We rely on the EventFactory to generate a hash of the events for the
event IDs, and we use the appropriate length for room IDs.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
As a fallback when the ID is not provided when constructing the event.
It allows to work with data that looks like what we would get in
production, which is important for benchmarks.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This allows passing the `Transaction` by mutable reference, instead of
passing it by ownership and requiring the callback to pass it back,
which is slightly better in terms of ergonomics. This was hard to
achieve without async closures, but now that we have them, this is
trivial.
Many of our tests make use of `assert_let` for checking that some value
comes out of a stream, while they could use `assert_let_timeout`, which
provides better ergonomics when the expected value doesn't arrive
immediately, by failing quickly.
This converts a few instances, making those tests easier to debug in the
future, would they fail again.
Removed a few TODOs that were not applicable anymore, because they were
either very low value (in timeline test code) or already done (in event
cache, with respect to the cross-process locking).
Also removed my nick from some TODOs and comments, as code comments
aren't the best way to store assignees for issues.
This patch logs errors from `EventLinkedChunk` and send them to Sentry
(if Sentry is enabled).
The trick is to use [`#[instrument(err)]`][0] for logging errors.
Quoting the documentation:
> If the function returns a `Result<T, E>` and `E` implements
> `std::fmt::Display`, adding `err` or `err(Display)` will emit error
> events when the function returns `Err`:
>
> ```rust
> #[instrument(err)]
> fn my_function(arg: usize) -> Result<(), std::io::Error> {
> Ok(())
> }
> ```
>
> The level of the error value event defaults to `ERROR`.
It sounds exactly what we need.
[0]: https://docs.rs/tracing-attributes/0.1.31/tracing_attributes/attr.instrument.html#examples-2
They are error prone because they need to be bumped for every migration
otherwise the new migration will not happen because we exit early.
So instead we get rid of the early returns and log each individual
upgrade separately. It makes more noise when creating a new database,
but since it is logged at the DEBUG level it is not much of a problem.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
When the event cache decides to deduplicate items, it will remove the
duplicate items, then push them back at a position further down the
line.
This can lead to spurious re-creation of items, which may show up, in
embeddings, as different items as they don't share the same internal id.
This patch makes it so that if the same transaction includes a move of
an event (i.e. it's removed then reinserted elsewhere), then the
internal ID will be reused in this case.
There seems to be a race condition where the
`RoomSendQueueUpdate::SentEvent` update arrives after the remote echo
has already been processed which leads to the latest event value getting
stuck at `LocalHasBeenSent`. This fixes the issue by trying to retrieve
the event from the cache first.
- [x] I've documented the public API Changes in the appropriate
`CHANGELOG.md` files.
- [x] I've read [the `CONTRIBUTING.md`
file](https://github.com/matrix-org/matrix-rust-sdk/blob/main/CONTRIBUTING.md),
notably the sections about Pull requests, Commit message format, and AI
policy.
- [ ] This PR was made with the help of AI.
---------
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
This is equivalent to what happens in `init_focus` when the timeline is
initialized from scratch.
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
The PR template includes an item for a warning that is automatically
shown once (and once and for all) by the Github UI. In the previous
review of the changes to the pull request template, Ivan agreed that
this was redundant, so it seems there's no point in keeping it in the
pull request template itself.
Instead encourage users to use the ones available on
`AuthorizationServerMetadata` because they support both the stable and
unstable actions.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The method `RoomEventCacheStateLockWriteGuard::handle_backpagination`
is used in a single place. This patch inlines it in…
`RoomEventCachePagination`, where it's supposed to be
declared! More precisely, inside the `PaginatedCache`
implementation for the `RoomEventCachePagination`, in the
`conclude_backwards_pagination_from_network`. The `state` module is
lighter with this change, and the code lives in the correct place.
This patch also renames `EventLinkedChunk::finish_back_pagination` to
`push_backwards_pagination_events`. The naming follows other names, like
`push_live_events`. Moreover, it removes the entire concept of “this
is part of a flow of methods”, it's just a single standalone method. On
this `EventLinkedChunk` alone, it is absolutely stateless.
This patch is purely code move, nothing changes.
This patch creates the new `RoomEventCacheUpdateSender` type to group
both the room update sender, and the room generic update sender. It
simplifies a couple of constructor and makes the code more robust by
isolating this logic in a single type instead of two types.
Firstly, the idea is to avoid accessing `RoomEventCache::inner`. Second,
by having a `send_updates` method, we increase the chances to forget
about one update (like `RoomEventcacheGenericUpdate` as it was the case
in the past).
This patch simplifies a lot of `pub(in super::…)` to just `pub`. The
visibility is now defined by the type itself, onto which the methods
are implemented.
Check if an Event is redacted before trying to decrypt it.
Use a new enum `NotificationStatus.EventRedacted` when trying to resolve
an event for a notification.
PR done with the help of AI: GitHub copilot chat in VisualStudio.
I confirm that the fix is working in EXA with the code in
https://github.com/element-hq/element-x-android/pull/6241Fixes#5796
<!-- description of the changes in this PR -->
- [x] I've documented the public API Changes in the appropriate
`CHANGELOG.md` files.
- [x] I've read [the `CONTRIBUTING.md`
file](https://github.com/matrix-org/matrix-rust-sdk/blob/main/CONTRIBUTING.md),
notably the sections about Pull requests, Commit message format, and AI
policy.
- [x] This PR was made with the help of AI.
<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by: benoitm@element.io
Previously, invite acceptance details were cleared in `RoomInfo::set_state`. We
can't do that any more, because (a) that method is synchronous (b) it doesn't
have access to the crypto store (c) it would be a bit of a layering violation
even if it did.
Instead, we pull the logic up to higher-level methods which do have access to
the crypto store (though, for now, we don't use it).
Step two in a series of refactoring: move and rename
`matrix_sdk_base::InviteAcceptanceDetails` to
`matrix_sdk_crypto::store::types::RoomPendingKeyBundleDetails`.
We're going to store this in the crypto store instead, so need to move it
down. I also want to rename it to better reflect how we interpret it.
This field is only ever used when encryption is enabled, and we want to move it
to the crypto crate. So, for a starting point, gate it behind the
e2e-encryption feature flag.
`matrix_sdk_base::response_processors::e2ee::E2EE` exists to pass E2EE context to the
logic within `response_processors`. Currently we pass it around by value in
many places, and hence have repetitive code for building the context, as well
as lots of calls to `.clone`.
Cloning of this type is cheap, but we can do better, by passing it around by
reference instead.
This patch adds the `waited_for_initial_prev_token` field directly
inside `LoadMoreEventsBackwardsOutcome::Gap`. It removes the need
to manage the `state_guard` manually (which can be error-prone). It
also removes one access to the `state_guard` in the pagination module.
Finally, it paves the road for a shared `Pagination<C>` type for
`RoomEventCache` and `ThreadEventCache`.
This patch renames the `RoomPaginationStatus` enum to `PaginationStatus`
because it won't be restricted to the `RoomEventCache` only: indeed, the
`ThreadEventCache` will soon be able to yield it too. Let's do the
renaming now.
The code was dereferencing to the borrowed type, only to convert it
back to an owned type. We can just use `.clone()` for this.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Similarly to #5382 and #5744, this patch introduces a write-only
connection in `SqliteCryptoStore`. The idea is to get many read-only
connections, and a single write-only connection behind a lock, so that
there is a single writer at a time.
This patch renames the `acquire` method to `read`, and it introduces a
new `write` connection.
This patch adds a new checkbox to ensure the user has read the `CONTRIBUTING.md` file, notably the Pull requests, Commit message format, and AI policy Sections.
Signed-off-by: Ivan Enderlin <ivan@mnt.io>
This avoids the sleep statement by only listening to the room's event
cache, instead of listening to the background send task and then wait
for it to save the sent event in the room cache. The test is more
resilient this way.
Change JoinedRoomBuilder::add_account_data() to accept any type that
implements Into<Raw<AnyRoomAccountDataEvent>>, preparing for migration
away from RoomAccountDataTestEvent enum.
Add support for room account data events in EventFactory:
- Add RoomAccountData format to EventFormat enum
- Add From implementations for Raw<AnyRoomAccountDataEvent>
- Add room_account_data() generic method
- Add fully_read() helper for m.fully_read events
- Add marked_unread() helper for m.marked_unread events
Replace all usages of ENCRYPTION_CONTENT and
ENCRYPTION_WITH_ENCRYPTED_STATE_EVENTS_CONTENT static values
with EventFactory::room_encryption().into_content() calls.
This uses the new into_content() method to get just the event
content for HTTP response mocking.
Add a generic method to EventBuilder that returns just the event
content as a serde_json::Value. This is useful when mocking HTTP
responses that return event content rather than full events.
There's one case where we want to create a custom join rule, and thus
must parse directly from JSON, but the rest can reuse helpers that
already exist.
An invite room is only constitued of stripped-state events. These events
do not have an `origin_server_ts` field. It means we cannot compute
the timestamp of the `LatestEventValue`. To workaround this, we set
the timestamp to `now()`. See `Builder::new_remote_for_invite` to learn
more. If an invite room receives a new event, its `LatestEventValue`'s
timestamp can be updated to `now()` again, which will make the room
bumps to the top of the room list for example. This is not an acceptable
behaviour because it can be an “attack vector”, i.e. a way to annoy
people with spammy invites. That's why, once a `RemoteInvite` has been
computed, we do not refresh it.
The fix is 2 instructions. The rest are comments and tests.
This new file writer supports both total size and age based rolling, and
will take care of a whole class of edge cases that make rageshake
uploading fail.
* It will rotate log files when the configured time period elapses
(e.g., hourly, daily).
* When the total size of all log files exceeds the configured limit, the
oldest files are removed.
* Logs older than the configured max age are automatically removed
during cleanup.
* Only files matching the configured prefix and suffix are managed by
any given writer instance.
The pinned event timeline only cares about updates to the vector of
events, not the other types of updates, at the moment. As such, it
doesn't need to use the fully-fledged `RoomEventCacheUpdate`, but a
simpler version, like the one that is being used for threads. Hence, we
can reuse `TimelineVectorUpdate` here.
Without this, the `Account::set_avatar_url()` function does not work
on homeservers that don't advertise support for the new endpoints
for setting profile fields.
This patch adds the `open` attribute to the `<details>` for displaying
leaf nodes of the tree. My experience shows that it's nice to always
have them open. The “occurences” list is still folded, so it shouldn't
take to much space on the screen most of the time (one line per level of
logs in this node).
This patch adds the `log overview` task that generates a standalone HTML
report representing the logs as a tree where each node is a target, and
each leaf is a log location with occurrences, spans and fields.
Each node displays the sum of errors and warnings for this node.
It helps to quickly spot the problematic targets, and it guides to
exploration of the node without taking the reader's hand by trying to
draw conclusions. We don't want to guide the reader to a mistake: we
just want to guide the reader to draw its own conclusions.
Each line can be highlighted. When a node is folded/closed, it is also
highlighted if at least one of its child is highlighted.
The occurrences of logs are displayed on a timeline.
This patch changes `RoomEventCacheState::waited_for_initial_prev_token`
from `Arc<AtomicBool>` to `bool`. First off, the `Arc` wasn't used in
any useful way (never cloned for example). Second, the `AtomicBool` was
always used as a regular bool, no atomicity was really used. Lastly,
this patch adds the `assume_has_waited_for_initial_prev_token` method to
replace the `= true` operation to make code a bit more readable.
This patch removes the write lock acquisition in
`RoomEventCache::subscribe_to_pinned_events` to replace it by read lock
acquisition. Nothing requires a `&mut self` at any point in this flow,
since `OnceLock::get_or_init` needs a `&self`.
The `RoomEventCacheStateLockWriteGuard::subscribe_to_pinned_events`
method is moved onto `RoomEventCacheStateLockReadGuard`.
`LinkedChunk::push_items_back` expects an `IntoIter<Item = Event>`.
`EventLinkedChunk::push_live_events` has an `events` of kind `&[Event]`.
Using `events.iter().cloned()` instead of `events.to_vec()` not only
removes one `Vec` allocation, but it allows the compiler to apply more
optimisation.
Checking on godbolt.org, I see twice fewer LLVM IR lines, and 2.8x times
less ASM code.
This patch relies on `MembershipChange` to decide when a `m.room.member`
represents a `LatestEvent` candidate. It was a mistale to rely on the
`membership` strictly, because the `prev_content` must be taken into
account.
Thus, this patch adds the following cases to `Knocked`, `Joined` and
`Invited`: `InvitationAccepted` and `KnockedAccepted`. Moreover, this
patch excludes other cases, including `ProfileChanged`, which was a bug
previously! When the user had a new display name, it was considered as a
`LatestEvent` candidate.
This patch changes an `info!` log to a `trace!`. Latest Events are
pretty stable now, and we don't get an info for each new computation
except when we want a proper trace.
This patch changes an `error!` log to a `info!`. Indeed, this is not an
error to compute a Latest Event that doesn't exist yet. The system is
lazy purposely.
Small bug fix that makes `remove_child_from_parent` behave like
`add_child_to_parent`.
Additionally introduces a new Error case so that clients can decide to
ignore any failures updating the child → parent relationship.
## Problem
When a room goes through:
join -> leave/kick -> re-invite
Sliding Sync responses still include the room, but the SDK does not emit
an
Invited/Knocked update. Because of this, RoomListService is never
notified and
the room disappears from the room list until the application restarts.
## Root cause
"update_any_room()" only returned a RoomUpdateKind when one was
explicitly
produced. For re-invites it could return "None", causing the room to be
skipped.
## Fix
Always emit a default:
- "RoomUpdateKind::Invited"
- "RoomUpdateKind::Knocked"
when the room state is Invited/Knocked but no update kind was generated.
## Tests
Added a regression test covering:
join -> leave -> re-invite to ensure the room is surfaced again in the
invited list.
---------
Signed-off-by: Lakshya Nayak <89520692+VEL0C1TY22@users.noreply.github.com>
This patch fixes a design issue. The
`BaseClient::room_info_notable_update_sender` is moved inside
`BaseStateStore` so that, when creating a new `BaseStateStore`, the
updates are not shared with other state stores. Updates are isolated to
the state store.
This bug has surfaced in `BaseClient::clone_with_in_memory_state_store`,
where a new `BaseStateStore` is created, but the
`room_info_notable_update_sender` was _cloned_, and that is a bug! We
could have re-created a new channel from scratch, but it would have
been hacky. Semantically, this channel should be part of the state store
itself. One proof is how it simplifies many call-sites, functions,
methods and structs: the `room_info_notable_update_sender` was passed
to multiple methods on `BaseStateStore`.
There were two issues:
- first, `load_or_fetch_event_with_relations()` allowed to pass a
filter, but the filter wasn't taken into account when fetching relations
from the network. This would cause the initial load of pinned events to
also include thread responses, which we don't want.
- similarly, when adding related events from sync, we'd only look if an
event had a `m.relates_to` field; but it could be a thread response
being added in live.
The two issues are fixed similarly, by using a new `extract_relation`
serde helper that gives both the related_to event and the relation type.
That way, we can apply a manual filter in
`load_or_fetch_event_with_relations` after fetching relations from
network, and we can filter out live events based on the relation type.
We usually don't care if the event was redacted or not, we usually want
to no whether a field is set or not, so we don't need `Original` and
`Redacted` variants.
This simplifies several parts of the code since we don't have to handle
the intermediate enum to access the content now. Due to new APIs in
Ruma we can also just convert original and redacted event contents to
possibly redacted event contents.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch updates the `cargo xtask log sync` command to extract the
`pos` and `timeout` fields so that we can display them. The `timeout`
is displayed in its own column, while the `pos` is displayed in the
line summary.
There was nothing called `RoomEventCacheState` anymore, and the `Inner`
suffix is dubious, at best. Also, we can get rid of the `Lock`
component, since indeed it's locked, but it's a detail from the point of
view of the `RoomEventCacheState` itself. This makes for a shorter and
nicer name.
It allows having way smaller binaries while still being able to have proper backtraces: `reldbg` is great for iOS because it allows inline debugging using LLDB in Xcode, but it produces enormous binaries, while for Android we can't use that properly and we'd only be interested in having symbolicated backtraces, which this profile achieves with binaries an order of magnitude smaller.
This is intended for reducing the binary size of the SDK distributed in Android/iOS bindings.
Its optimization level is 'binary size', it contains LTO optimizations and by default removes part of the debug info - the rest can be removed later if needed.
The method is kept on the pinned loader trait at the moment, because
it's too inconvenient to remove it quite yet. This will happen in a
subsequent PR.
The tests removed are either covered by other tests or
ensure properties that shouldn't exist - e.g., that
new chunks can link to chunks that haven't been put
into the store yet.
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
This will come in handy once we attempt to support MSC4388 as this MSC
changes how the client-server API operates. The rendezvous channel will
in the future operate on JSON messages where we'll include our sealed
ciphertext as a base64 encoded string.
This patch adds the `LatestEventValue::RemoteInvite` variant. The goal
of this is to be able to compute a `LatestEventValue` for an invite to
a room. Using `LatestEventValue::Remote` isn't possible because it's
usually built from the `RoomEventCache`. However, the `EventCache`
doesn't handle invites for one reason: invites only manipulate stripped
state-events, whist the `EventCache` manipulates non-stripped (state)
events.
The `LatestEvents` API receives a stream of `RoomInfoNotableUpdate`. It
reacts to update from the `RoomInfo`. It filters out all reasons except
`MEMBERSHIP`. When the `MEMBERSHIP` is updated, and the room' state is
`Invited`, then a `RemoteInvite` is computed.
The `Invite` type is updated to include the `inviter_id` in case the
`inviter` is missing. Indeed, we always know the user ID of the inviter,
this information isn't optional.
This patch replaces the `interact(…).unwrap()` by a proper error.
So far, `interact()` was only returning `InteractError::Panic`
despites `InteractError::Aborted` exists. With
https://github.com/deadpool-rs/deadpool/pull/461, we now get
`InteractError::Aborted` when the SDK is shutdown, sometimes. This
results in hitting the `unwrap` and having a panic again. This patch
solves the problem by changing the `unwrap` to a proper error. Note: in
case of `InteractError::Panic`, we continue to panic.
This patch makes sense with or without the merge of the PR on
`deadpool`.
This patch introduces a new family of commands: `xtask log`. The goal
is to manipulate logs, to extract the right amount of data we need to
solve specific problems. The first member of this family is `sync` to
visualise logs about the sync process. It presents the sync requests and
responses in a table, with a "timeline" _à la_ network profiler graph.
The code is rather simple, on purpose. The generated HTML reports are
lightweight, and fully standalone: no JavaScript, pure HTML and CSS, no
external resources. These reports can be shared or archived super
easily.
Features:
- requests/responses are grouped by connection ID
- permalink to specific request ID
- status have colours
- time is displayed in a human form
- duration is calculated from the log timestamps
- view syncs in a "tree-like" flavor, a "time graph", super quick to
spot long requests
- each line can be "opened" to see details, so far only log line numbers
to get more context manually
MSC4388 won't have the full rendezvous URL encoded in the QR code,
instead it'll have a rendezvous ID.
So let's remove this accessors and use the `intent_data()` getter
instead.
MSC4388: https://github.com/matrix-org/matrix-spec-proposals/pull/4388
Since the intent is encoded differently in MSC4108 and MSC4388 it
doesn't make sense to publicly expose the binary constants for a
specific MSC in the public API.
This patch removes access to the binary constants and you only access to
a generic enum.
This patch modifies the QrLoginData, it now hides all its public fields
and appropriate getters have been created for it instead.
This is necessary to hide the MSC specific parts of the data type thus
allowing support of multiple versions of the data type.
Our current implementation of this QR code data type corresponds to the
data type defined in MSC4108. The data format has been updated a bit in
MSC4833 and thus we'll need to support both formats for a while.
This moves al the MSC4108-specific parts into a separate MSC-specific
submodule.
MSC4108: https://github.com/matrix-org/matrix-spec-proposals/pull/4108
Instead of going through `serde_json::to_value()` and then converting it
to canonical JSON to serialize it.
Currently `to_canonical_value()` has the same behavior internally as
here, but an upcoming change in Ruma makes it use its own `Serializer`
so it is directly serialized as a `CanonicalJsonValue` which should be
somewhat more efficient.
This upcoming change also removes the `CanonicalJsonError::SerDe`
variant, so it is not as straightforward to propagate
`serde_json::Error`s.
This commit also removes outdated `#[allow(clippy::…)]` attributes.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Sometimes, running the wasm tests with a given runner will fail with
obscure, undecipherable reasons. As a result, it's convenient to be able
to locally run the wasm-pack tests with only a single runner, which this
commit allows.
There is an error in how JNA performs the API checksums that results in incorrect checks that make the app fail as soon as any SDK method is called, since initializing the SDK performs these checks
This test was setting a client-wide retry limit of 3 attempts for every
single network request. It happens that it was using the login method,
which unconditionally overrides this retry limit to 3 anyways, in
`LoginBuilder::send()`, so it worked only because the two retry limits
were accidentally in sync. Changing the retry limit in the test to 4
would make it thus fail; the test has been changed so it tries to use
the /whoami endpoint instead of login, as the former doesn't override
the retry limit.
The `default_timeout` is a timeout value provided by `backon`, and
that's a suggestion of what the timeout value should be for the next
request (based on the backoff method used under the hood — in our case,
the exponential backoff). Since we have another concept of a default
timeout (the one present in the RequestConfig), it seems better to call
the timeout suggested by backon in a different manner, that's more
explicit in the given context.
The sync lock was acquired too late in `LatestEvent::store`, which could lead to a race condition where we read some room info, that room info was modified and saved in parallel somewhere else, and then we modified the copy of the room info and overwrote that saved data with it, resulting in data loss.
In the clients, this was experienced as notifications sometimes lacking the room display name
Use case: Display membership changes (join, leave, etc.) in the timeline but suppress profile changes (display name or avatar URL). This is currently not possible with `TimelineEventTypeFilter` because both types of changes have the same event type (`m.room.member`).
This pull request introduces a new `TimelineEventFilter` for filtering on either the event type or parts of its content. Content filters are only added for membership and profile changes but more enum variants can be added in future.
While https://github.com/matrix-org/matrix-rust-sdk/pull/6017 is mostly
functional, there are two issues:
- I did not process `changes.room_key_bundles_fully_downloaded` in
`matrix-sdk-sqlite`, meaning any updates made via `Changes` would not be
persisted;
- I used a non-encrypting `JsValue` serialisation for the same field in
`matrix-sdk-indexeddb`, which causes errors when passed to the
decryption-enabled deserializer.
Solutions:
- Process the aforementioned changes such that keys are added to SQLite;
- Use a non-encrypting deserialiser, since this is effectively a
hash-set, and the contents aren't sensitive.
Signed-off-by: Skye Elliot <actuallyori@gmail.com>
If the homeserver provides a state event to a client, it means that it
considers the event to be valid. If a state event is valid, it always
updates the state map of the room. So ignoring events that fail to
deserialize means that the local state map is different than the one
from the server.
In some cases the Matrix spec even explicitly says that if a required
field is missing from the content of a state event, it should be treated
as if the event is missing from the state map. And if a required field
is missing, the event will fail to deserialize.
So this handles state events very closely to how a server would we only
deserialize the event type and the state key first to make sure that a
valid state event always updates the local state map. Then we only
deserialize the events lazily when we encounter an event type that
updates the `RoomInfo`. Because we deserialize the event lazily and some
methods might edit parts of an event before passing it to `RoomInfo`,
the (possibly edited) deserialized event is cached alongside the raw
event and its keys to be able to pass it further down the chain.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch replaces `HashMap` by `BTreeMap` in `EventCacheInner` as
we don't need any ordering. It is then faster to get (or insert) a new
`RoomEventCache`:
- an insert is O(1) for `HashMap` vs. O(log(n)) for `BTreeMap`,
- a get is O(1) for `HashMap` vs. O(log(n)) for `BTreeMap`.
This patch fix an off-by-one check for `Error::InvalidItemIndex` in
`LinkedChunk::remove_item_at`.
This patch updates the `test_remove_item_at` test to cover this bug.
Before: after uploading a media and a thumbnail with the send queue, the
thumbnail would be cached only as a "file", and not as a thumbnail. This
is wasteful, if the embedder is interested in getting a thumbnail of the
exact same dimensions, for the file they've updated; there's no good
reason to wait for the server to return it back.
However, there were good reasons to store it as a file in the past. So,
we're choosing here to duplicate the thumbnail in the media store:
- it's saved as a file for its own MXC URI (which preserves the previous
behavior)
- it's also saved as a thumbnail for the media MXC URI (which implements
the desired behavior).
Tests are updated to reflect this.
This is half of the work: this will load the threaded receipt for each
thread, every time we add/update a timeline item for an event that had a
thread summary. Since we don't know which of the private or the public
receipt is the most advanced, we simply pass both, to start with; it's
expected that this code dies later, when we fold it in into the event
cache.
The second half will consist in updating the thread summaries when a new
read receipt event happens.
This patch adds a new state event candidate for `LatestEventValue`:
`m.room.member` when the `membership` is `join` and the `state_key`
is the current user ID. Put differently: when the current user joins a
room, we are able to compute a `LatestEventValue`.
The `SpaceFilter`s API provides a simple interface that can be used in conjuncture with the `RoomList` to filter down the hierarchy to a particular space or its descendants.
Per design, the first level `SpaceFilter`s will only contain direct descendants while the second level ones will contain the rest of the hierarchy recursively.
The full feature is defined in https://github.com/element-hq/element-meta/issues/2966
This patch ensures that a `LatestEventValue` is erased when a room has
been emptied.
If we are computing a value from the Event Cache, it's because we
have received an update from the Event Cache. This update falls in two
categories: either an event has been added or updated, or the room has
been emptied. We consider the room has been emptied by default. If we
are able to scan at least one in-memory event, we consider the room has
not been emptied.
This patch adds one specific, and updates other tests that were using
an empty Event Cache (which now produces a different result in this
situation).
This patch splits the `latest_events/latest_event.rs`
module into `latest_events/latest_event/mod.rs` and
`latest_events/latest_event/builder.rs`. The file was too big and asked
for a diet. The `LatestEventValueBuilder` type has been renamed to
`Builder`, and the `LatestEventVAluesForLocalEvents` has been renamed
to `BufferOfValuesForLocalEvents` for the sake of clarity and shorter
names.
This fixes an issue that prevented default values coming from the SDK from being uploaded in the create room request, which could mean rooms created with the wrong power levels if the default values in the homeserver didn't match those of the SDK
This patch introduces the `PollTimeout` type to represent
either no timeout with `PollTimeout::None`, some timeout
with `PollTimeout::Some(_)`, or a default timeout with
`PollTimeout::Default`. It's finer than the previous `bool` that
was used, where `false` meant `PollTimeout::None`, and `true` meant
`PollTimeout::Default`. It's now possible to pass a precise timeout
value.
Hello!
As the `Not` filter is not available on the FFI SDK due to UniFFI
constraints, this PR adds a NonFavorite filter to RoomList, implemented
as the negation of the existing Favorite filter. This was made to
address the issue #5978.
- [x] 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:
---------
Signed-off-by: JoFrost <20685007+JoFrost@users.noreply.github.com>
In the send queue, failures to send can be classified into two
categories:
- permanent failures (e.g. invalid parameters)
- recoverable failures (e.g. network is down; server responded with a
transient error code)
The latest event system would classify all the failures as "cannot be
sent", which is slightly incorrect if the failure was recoverable. In
this case, we should still consider the local event as being sent, as
the system should try to send it some time soon.
https://github.com/matrix-org/matrix-rust-sdk/pull/4568 merged together
`SyncTimelineEvent` and `TimelineEvent`, but removed some of the useful
documentation on `TimelineEvent`, and left behind some confusing
references. This change fixes it up.
This patch changes `subscribe_to_rooms` in `RoomListService` to replace
the old subscriptions. It avoids accumulating subscriptions forever and
is closer to the old `visible_rooms` sliding sync list behaviour.
This patch adds two methods on `SlidingSync`: `unsubscribe_to_rooms`
and `clear_and_subscribe_to_rooms` to respectively remove many room
subscriptions, and to replace room subscriptions by new ones.
Our information were wrong. `room_subscriptions` is definitely not
sticky, we must send them for each request.
This patch removes `RoomSubscriptionState`. Subscriptions are not marked
as “applied” anymore, they are always sent.
For some reason, the automatic WAL checkpoints don't seem to be working as expected. Since we should periodically run VACUUM operations, we might as well add checkpoints before vacuuming (so the WAL size is reset and can grow to fit the whole DB) and after (so we clean up after that).
This patch restores a couple of assertions from a recently removed
test where it is asserted that `Request::extensions::to_device::since`
is set from the Olm machine.
This patch extracts `SlidingSyncListStickyParameters::filters` to
no longer make it sticky. We are dropping sticky parameters as it's not
part of the last MSC.
THis patch extracts `SlidingSyncListStickyParameters::required_state` to
no longer make it sticky. We are dropping sticky parameters as it's not
part of the last MSC.
This patch removes `SlidingSyncStickyManager` as it only contains
the logic for a single request field: `room_subscriptions`. Also,
previously, `room_subscriptions` was considered sent based on the
transaction ID. This is useless as it's always sticky per MSC4186. The
logic from `SlidingSyncStickyManager` is sent inlined, allowing to
effectively remove this type.
This patch extracts `SlidingSyncStickyParameters::extensions` to no
longer make it sticky. We are dropping sticky parameters as it's not
part of the last MSC.
The issue is related to the encrypt_store_dir fn where, when creating
the key file, it doesn't ensure that the parent directory exists first.
It might be not optimal for the user of the crate to ensure in an non
hacky manner, as the sdk iterates through most of its directories
internally. Have a test to verify it, which can be removed later (if
being merged)
Needs a review, might not be the optimal solution as this is my first pr
with the crate and am not that familiar with it (although do use it in
one of my apps).
We can have 3 different states for the same aggregation in
related_events, in chronological order:
1. The local echo with a transaction ID.
2. The local echo with the event ID returned by the server after
sending the event.
3. The remote echo received via sync.
The transition from states 1 to 2 was already handled in
`mark_aggregation_as_sent()`.
But the transition from states 2 to 3 was never handled and we ended up
with both the local echo and the remote echo in the related events.
This resulted in the local echo being chosen over the remote echo when
computing the latest edit only because it was first in the list, even
though it didn't contain the raw JSON of the edit.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Remove unused `ShieldStateCode::SentInClear`
`VerificationState::to_shield_state_{strict,lax}` return a type `ShieldState`, whose inner
type `ShieldStateCode` currently includes a variant `SentInClear` for "unencrypted event".
This is very misleading, because those functions never actually set that variant.
Rather, there is a separate method in `matrix-sdk-ui`, `EventTimelineItem::get_shield`,
which uses the same type, but *does* set that variant where appropriate.
As a user of matrix-sdk-common, without the matrix-sdk-ui layer, this is dangerously
misleading: it gives the impression that we are checking for unencrypted events, when in
fact we are not.
The solution seems to be to use different types for the different levels of the stack.
While we're at it, we fix up some of the confusion of methods that return an `Option` of an
enum type which itself has a `None` variant.
feat: Add `forwarder: ForwarderInfo` to `EncryptionInfo`.
Introduces `ForwarderInfo` which which exposes information about the forwarder of the keys with which an event was encrypted if they were shared as part of an [MSC4268](https://github.com/matrix-org/matrix-spec-proposals/pull/4268) room key bundle.
<!-- description of the changes in this PR -->
- Introduces a new enum `ForwarderData` as a wrapper for valid variants
of `SenderData` for which we can accept key bundles under MSC4268.
- Converts `forwarder_data` in `InboundGroupSession` and
`PickledInboundGroupSession` to use `Option<ForwarderData>` over
`Option<SenderData>`.
- [x] Public API changes documented in changelogs (optional)
---------
Signed-off-by: Skye Elliot <actuallyori@gmail.com>
This patch implements a new feature: when a `m.room.redaction` targets
the current [`LatestEventValue`], this one must be erased by the new
computed `LatestEventValue`.
This patch spreads the current value's event ID in
`LatestEventValueBuilder`.
This patch also changes `LatestEventValueBuilder::new_remote` to return
an `Option`, similarly to `new_local`. The `must_overwrite_existing`
variable is set to `true` to keep the existing behaviour, but it's going
to change in the next patch.
This patch is purely a refactoring with no feature change. Most of the
changes are in test to keep track of the _previous value_ so that the
current value's event ID can be calculated instead of hardcoded.
This patch renames a variable. Since `rfind_map_event_id_memory_by`
returns the previous event instead of the previous event ID, this
variable must have been renamed.
Separate the shield types between common and UI, so that we can change common
without breaking UI.
The new type does not include a `message` field: since it cannot be localised,
clients should not be using it.
What's more, this is saved into the event cache and sometimes it overrides another instance of the same event that actually contains the right info. This results in unresolvables UTDs.
This change tries to fetch the session id from the existing event content. It's fixed these kind of UTDs when tested in a real client.
This time we're testing the redecryption of pinned events that were not
part of the main timeline, more importantly we never backpaginated
enough for them to be part of the main timeline and thus never got put
into the event cache.
This test expectedly fails for now.
We can't use `LatestEventValue::None` as an optional value anymore,
since it erases the previous `LatestEventValue`. This patch updates
`LatestEventValueBuilder::new_local` to return an `Option` to handle all
the cases where a local value cannot be computed.
This patch changes the semantics of the Room List `latest_event`
sorter by changing “is local” to “is remote like”, to include the new
`LatestEventValue::LocalHasBeenSent` variant.
The problem we are trying to solve is the following:
- a local event is being sent,
- the `LatestEventValue` is `LocalIsSending`,
- the local event is finally sent,
- the `LatestEventValue` is still `LocalIsSending` purposely, with the
hope that an update from the Event Cache will replace it.
But sometimes, this update from the Event Cache comes **before** the
update from the Send Queue. Why is it problem? Because updates from the
Event Cache are ignored until the buffer of local `LatestEventValue`s
aren't empty, which means that if an update from the Event Cache is
received before `RoomSendQueueUpdate::SentEvent`, it is ignored, and the
`LatestEventValue` stays in the `LocalIsSending` state. That's annoying.
The idea is to introduce a new state: `LocalHasBeenSent` which mimics
`Remote`, but for a local event. It clarifies the state of a sent event,
without relying on the Event Cache.
This patch simplifies the code after the recent refactorings.
It uses `LatestEventValue::is_none()` to replace a `matches!`, and it
replaces the last use of `new_remote` by `new_remote_with_power_levels`
to finally rename this latter to `new_remote`.
The `LatestEventValue` can be `None` (the default value) but the Event
Cache contains enough data to compute a `Remote(_)` one. The system
lazily triggers a `LatestEventQueueUpdate` to achieve that.
Previously, `LatestEventValue` was always initialized from the
`RoomEventCache`. Now, it is restored from the `RoomInfo`. First off,
this is something we wanted to do since a long time. Second, it is
more performant. Third, it allows the system to be lazier. Indeed,
it's possible that when a `LatestEvent` is created, its correspond
`RoomEventCache` doesn't exist yet. It happens during a sync when a room
is new: latest events are registered, but their `RoomEventCache` aren't
yet created. By postponing the use of `RoomEventCache`, the system is
lazier and more solid.
Bonus, less methods are async, which simplifes the workflow.
This patch removes `RoomRegistration` along with the full room
registration mechanism. It's been introduced to remove contention
around the `RegisteredRooms` lock, but it actually creates more async
flows, which makes the `latest_events` logic a bit less predictable.
By removing this room registration mechanism, our hope is to make the
result more predictable and less buggy in appareance. Our real-life
tests have shown that the lock contention isn't problematic, especially
since `RoomLatestEventsReadGuard` and `RoomLatestEventsWriteGuard` have
been introduced.
This test for one reason or the other sporadically panics with an:
> RuntimeError: unreachable
Let's disable this test on Wasm for now since the memory store isn't
that relevant anyways, especially not on Wasm.
This patch abstracts away the cryptographic channel which is used in the
SecureChannel implementation for the QR code login support.
This will allow us to use HPKE alongside of ECIES since MSC4108 recently
proposed the switch to HPKE.
This patch revisits the way redacted and redaction events are handled in
the Latest Event.
Previously, all redacted events were considered suitable candidate. It's
no longer the case.
Redaction and redacted events are no longer considered suitable.
This patch also revisits `rfind_map_event_in_memory_by` to return a
`&TimelineEvent` instead of an `OwnedEventId`, which could be more
performant in the future.
The tests have been updated accordingly.
---
* Fix https://github.com/matrix-org/matrix-rust-sdk/issues/5899
* Address https://github.com/matrix-org/matrix-rust-sdk/issues/4112
Signed-off-by: Stefan Ceriu <stefanc@matrix.org>
Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
This patch increases the capacity of the room registration channel. The
hope is that it can reduce the need to wait on available permits under
heavy load.
This patch removes the use of `Fuse` in the
`listen_to_event_cache_and_send_queue_updates` task. `mpsc::Receiver`
and `broadcast::Received` are cancellation safe.
This patch reduces the lifetime of the write locks in
`RegisteredRooms::room_latest_event` when the `RoomLatestEvents`
doesn't exists. If the `room_registration_sender` channel is full,
it has to wait. When waiting, the write lock is still alive, probably
blocking other operations. The idea is to create the `RoomLatestEvents`,
to downgrade the write lock to a read lock, and then to send the
registration message onto the `room_registration_sender`.
In the implementation of EventCacheStore, there are a number of
places where the upper and lower bounds of an EventId are
constructed. It is important to bypass hashing and encryption
when constructing these bounds, otherwise the values will be
modified and will no longer represent the bounds.
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
Note that the encrypted tests were actually being run unencrypted.
Introducing a store cipher causes them to run encrypted, and
furthermore, reveals some bugs which are only visible when running
an encrypted event cache store.
Signed-off-by: Michael Goldenberg <m@mgoldenberg.net>
This path adds events or state events to force the test to execute as
expected since a change in `bump_stamp` alone doesn't trigger a room
list update anymore.
This patch fixes a “bug” in the Room List. It's updated by
`RoomInfoNotableUpdateReasons`. However, 1 reason is creating
unnecessary updates: `RECENCY_STAMP`. The Room List is already updated
by the Latest Event. One usage of the Latest Event is to sort the Room
List by recency. Thus, since the Room List is updated by `LATEST_EVENT`,
we can ignore `RECENCY_STAMP`.
- Add `NotificationItem::raw_event` to get the raw event content of the event that triggered the notification, which can be useful for debugging and to support clients that want to implement custom handling for certain notifications. ([#6122](https://github.com/matrix-org/matrix-rust-sdk/pull/6122))
- [**breaking**] Extend `TimelineFocus::Event` to allow marking the target
- Add `NonFavorite` filter to the Room List API. ([#5991](https://github.com/matrix-org/matrix-rust-sdk/pull/5991)
- Add `call_intent` (either `RtcCallIntent::Audio` or `RtcCallIntent::Video`) field to `RtcNotification` event content. ([#6207](https://github.com/matrix-org/matrix-rust-sdk/pull/6207))
- Add `RoomInfo::active_room_call_consensus_intent` method to get the call intent for the current call,
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.