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.).
The previous code would skip based on the position's index, but not the
position's chunk. It could be that the position's chunk is different
from the first items chunk, as shown in the example, where the linked
chunk ends with a gap; in this case, the position's index would be 0,
while the first chunk found while iterating backwards had 3 items. As a
result, items 'd' and 'e' would be skipped incorrectly.
The fix is to take into account the chunk id when skipping over items.
This is needed to tell apart rooms in left and banned state in places like `RoomInfo` or `RoomPreview`.
The banned rooms will still count as left rooms in the sync processes.
This subscription will combine 3 streams: one notifying the members in the room have changed, another notifying the seen join requests have changed, and finally a third one notifying when the room members are no longer synced.
With this info we can track when we need to generate a new list of join requests to be emitted so the client can always have an up to date list.
This will allow us to keep track of which join room requests are marked as 'seen' by the current user and return them as such.
Also, add some methods to `Room` to mark new join requests as seen and to get the current ids for the seen join requests.
The conditions required to cause the bug might have been impossible to
reach in the real world, because it assumes a mix of:
- events present in the linked chunk
- no prev-batch token
However: now that we have storage, we could end up in this situation,
when reaching the start of the timeline (since there'll be no previous
gap in that case). We need to handle that better in the linked chunk
representation itself, but in the meanwhile, we should insert the gap
and the events in a relative correct order.
If a linked chunk update starts with a RemoveChunk update, then the
transaction may start with a SELECT query and be considered a read
transaction. Soon enough, it will be upgraded into a write transaction,
because of the next UPDATE/DELETE operations that happen thereafter. If
there's another write transaction already happening, this may result in
a SQLITE_BUSY error, according to
https://www.sqlite.org/lang_transaction.html#deferred_immediate_and_exclusive_transactions
One solution is to always start the transaction in immediate mode. This
may also fail with SQLITE_BUSY according to the documentation, but it's
unclear whether it will happen in general, since we're using WAL mode
too. Let's try it out.
This patch fixes an edge case where the member is alone in the room with
a service member. We already subtracted the number of service members
in the case we calculated the room summary ourselves, but we did not do
so when the server provided the room summary.
This lead to the room, instead of being called `Empty`, being called
`Foo and N others`.
Update the workaround for https://github.com/rust-lang/rust/issues/109717 to
avoid hardcoding the clang version; instead, run `clang -dumpversion` to figure
it out.
While we're there, use the `CC_x86_64-linux-android` env var, which should
point to clang, rather than relying on `ANDROID_NDK_HOME` to be set.
The `MemoryStore` implementation of the `StateStore` has grown into a
monster, with one lock per field. It's probably overkill, as individual
fields don't need fine-grained locks like this; after all, accesses to
the store shouldn't be reentrant in general.
Fixes#3720.
- rename RawLinkedChunk -> RawChunk
- rename RawChunk::id -> RawChunk::identifier
- precise that a `RawChunk` is mostly a `Chunk` with different
previous/next links.
And let the caller rebuild the linked chunk. This is slightly nicer in
that it allows us to display the raw representation of a reloaded linked
chunk, before checking its internal state is consistent; this will allow
for better debug of issues related to the linked chunk internal state.
No functional changes.
The `MediaFormat` reflects only the request that would be made to the homeserver.
There is no link between the format of the files stored in the media cache and their purpose in an event.
`MediaFormat::Tumbnail` means that we request a server-generated thumbnail of a file in the media repository.
Since the thumbnail is its own file in the media repository, it makes more sense to use `MediaFormat::File`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
By default, the event cache store will be disabled. If disabled, it will
clean all the events in the cache store; most of the time this will do
nothing, since the store will not even be filled with any event data, so
it would be cheap to do. If some data was filled in the cache store
before, then it would be cleared after the cache store has been
disabled.
This makes a less awkward API than the previous one, where `None` and
`Some(false)` carried different semantics.
This patch creates `ObservableItemsTransactionEntry` that mimics
`ObservableVectorTransactionEntry`. The differences are `set` is
renamed `replace`, and `remove` is unsafe (because I failed to update
`AllRemoteEvents` in this method due to the borrow checker).
This patch creates `ObservableItemsEntries` and particularly
`ObservableItemsEntry` that wraps the equivalent
`ObservableVectorEntries` and `ObservableVectorEntry` with the
noticeable difference that `ObservableItemsEntry` does **not** expose
the `remove` method. It only exposes `replace` (which is a renaming
of `set`).
This patch moves `AllRemoteEvents` inside `observable_items` so that
more methods can be made private, which reduces the risk of misuses
of this API. In particular, the following methods are now strictly
private:
- `clear`
- `push_front`
- `push_back`
- `remove`
- `timeline_item_has_been_inserted_at`
- `timeline_item_has_been_removed_at`
In fact, now, all `&mut self` method (except `get_by_event_id_mut`) are
now strictly private!
This patch adds the Room::send_raw method to the bindings, making it usable from
e.g. Swift.
Signed-off-by: Jonas Richard Richter <jonas-richard.richter@telekom.de>
Whenever it needs to back-paginate, the event cache should start with
the *most recent* backpagination token, not the oldest one.
This isn't a functional change, until the persistent storage is enabled.
The reason is that, currently, there is one previous-batch token alive;
after it's used, it's replaced with another gap and the events it served
to request from the server.
When persistent storage will be enabled, we'll have situations like the
one shown in the test code, where we can have multiple previous-batch
token alive at the same time. In that case, we'll need to back-paginate
from the most recent events to the least recent events, and not the
other way around, or we'll have holes in the timeline that won't be
filled until we got to the start of the timeline.
Extracted from #4329. This does not change the `MediaFormat` of the
request used in the media cache by the send queue.
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It is triggered by the `xshell::cmd!` macro, and is fixed in xshell 0.2.7, which we cannot upgrade to.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The test requires subtle conditions to trigger:
- initialize a timeline from a room-list-service's room
- start a backpagination with that timeline (so the room event cache's
paginator is busy)
- try to initialize another timeline with the same room-list-service's
room (e.g. because the first room has been closed, and the app using it
doesn't have a room cache)
This would fail, because initializing a timeline calls
`EventCache::add_initial_events()` all the time, which tries to reset
the paginator's state, which assumes the paginator's not paginating at
this point. In a soon future, we'll get rid of the
`add_initial_events()` function because the event cache will handle its
own persistent storage; in the meantime, a correct fix is to skip
`add_initial_events()` if there was already something in the linked
chunk. After all, we're likely to fill the initial events with the same
events all the time, or a subset of more recent events. By doing that,
we're likely keeping *more* events in the linked chunk, instead.
Thanks to @stefanceriu for reporting the issue and confirming the fix
works!
Currently the WidgetDriver just returns unspecified error strings to the
widget that can be used to display an issue description to the user. It
is not helpful to run code like a retry or other error mitigation logic.
Here it is proposed to add standardized errors for issues that every
widget driver implementation can run into (all matrix cs api errors):
https://github.com/matrix-org/matrix-spec-proposals/pull/2762#discussion_r1838804895
This PR forwards the errors that occur during the widget processing to
the widget in the correct format.
NOTE:
It does not include request Url and http Headers. See also:
https://github.com/matrix-org/matrix-spec-proposals/pull/2762#discussion_r1839802292
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
Adds new UtdCause variants for withheld keys, enabling applications to display customised messages when an Unable-To-Decrypt message is expected.
refactor(crypto): Move WithheldCode from crypto to common crate
Since xshell 0.2.3 the behavior of the run() function has changed in a
incompatible manner. Namely the stdin for the run() function no longer
inherits stdin from the shell. This makes it impossible for commands
that are executed by the run() function to accept input from the shell.
We don't use this functionality in many places but the `xtask release
prepare` command is now broken.
Let's just pin xshell to a working version while we wait for this to be
resolved upstream.
Upstream-issue: https://github.com/matklad/xshell/issues/63
Virtual timeline items will still be provided and the `default_event_filter` will be applied before everything else.
Instances of these timelines will be used to power the 2 different tabs shown on the new media browser. The client will be responsible for interacting with it similar to a normal timeline and transforming its data into something renderable e.g. section by date separators (which will be made configurable in a follow up PR)
Having a mutable iterator can be dangerous and is probably too generic
regarding the safety we want to add around the `AllRemoteEvents` type.
This patch removes `iter_mut` and replaces it by its only use case:
`get_by_event_id_mut`.
This patch replaces `VecDeque<EventMeta>` by `AllRemoteEvents` which
is a wrapper type around `VecDeque<EventMeta>`, but this new type aims
at adding semantics API rather than a generic API. It also helps to
isolate the use of these values and to know precisely when and how they
are used.
As a first step, `AllRemoteEvents` implements a generic API to not break
the existing code. Next patches will revisit that a little bit step
by step.
The `add_or_update_remote_event` method always returns `true`. This
patch updates the method to return nothing, and cleans up the call sites
accordingly. This patch also adds comments to clarify the code flow.
The bool value returned by `add_or_update_remote_event` was supposed
to be `false` if the event was duplicated. First off, as soon as the
`Timeline` receives its events from the `EventCache` via `VectorDiff`,
the `event_cache::Deduplicator` will take care of deduplication,
so the `Timeline` won't have to handle that itself. Second,
`add_or_update_remote_event` was sometimes removing an event, but it
was re-inserting a new one immediately without returning `false`: it was
never returning `false` because a new event was always added.
This test was checking that a new device which has access to backups
returned an unknown UTD when it was given empty JSON for the event. It
was only passing because we currently have incorrect behaviour when
backups are enabled.
The fix is to make the device old and without access to backups, so that
we still consider this UTD unexpected.
Any `.remove` operation called on a `ObservableMap` did not re-index
`values` _after_ the removed position, which means any later operation
on elements inserted after the previously removed key would either be
fetched wrongly, or panic when using `.get_or_create`.
This PR fixes these two related bugs and adds extra test cases.
---------
Signed-off-by: g@leirbag.net
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
This patch changes `TimelineStateTransaction::add_remote_events_at`
to take an `IntoIterator<Item = Into<SyncTimelineEvent>>`
for `events`. In the current code, it saves one
`iter().map(Into::into).collect::<Vec<_>>()`, but it will save another
one when we will support `VectorDiff`s coming from the `EventCache`.
It also avoids to allocate a vector to pass new events (this mostly
happens in the test, but it can happen in real life).
If no server names are provided for the room summary request and the
room's server name doesn't match the current user's server name, add the
room alias/id server name as a fallback value. This seems to fix room
preview through federation.
Also, when getting a summary for a room list item, if it's an invite
one, add the server name of the inviter's user id as another possible
fallback.
Changelog: Use the inviter's server name and the server name from the
room alias as fallback values for the via parameter when requesting the
room summary from the homeserver.
This required adding support for *reading* out of the event cache, for
the sqlite backend. This paves the way for the next PR (reload from the
cache), and it should also help with testing at the `EventCacheStore`
trait layer some day.
A comment was duplicating (the first trace! that's removed here), and
the second block comment only applied to new items, and was not as
concise as it could be.
This patch unifies the logic for inserting timeline items at `Start`
and `End` positions. Both `TimelineItemPositions` can share the same
implementation, making separate logic unnecessary. Previously, `End`
included a duplicated events check as well, while `Start` did not, leading
to inconsistency.
The changes strictly involve moving and refactoring, with no functional
modifications.
This PR introduces a new variant to `UtdCause` specifically for device-historical messages (`HistoricalMessage`). These messages cannot be decrypted if key storage is inaccessible. Applications can leverage this new variant to provide more informative error messages to users.
This patch updates `LinkedChunk::new_with_update_history` to emit an
`Update::NewItemsChunk` because the first chunk is created and it must
emit an update accordingly.
This patch fixes the `test_echo` test. It was doing the following:
* client sends an event to the server,
* servers acknowledges with the ID `$wWgymRfo7ri1uQx0NXO40vLJ`,
* client syncs and the server returns one event with ID `$7at8sd:localhost`,
* the test expects those 2 events to be the same!, which is incorrect.
The test was working because the transaction IDs are the same, but
that's an abuse of the existing code (the code will change soon, another
patch is coming). Whatever the code does: the connection must be based
on the event ID, not the transaction ID.
Building the docs for xtask spews a bunch of unexpected cfg warnings. As
these warnings come from a macro in a dependency and the docs for xtask
don't exist nor will, let's just not build them with the rest of the
docs.
These are all coming from macro invocations of macros that are defined
in other crates. It's likely a clippy issue. We should try to revert
this the next time we bump the nightly version we're using.
This patch tries to clear confusion around
`TimelineItemPosition::UpdateDecrypted(usize)`: it does contains
a timeline item index. This patch changes to
`TimelineItemPosition::UpdateDecrypted { timeline_item_index: usize }`
It's unused so it's mostly cosmetic, and it's trivial to reimplement
using `linked_chunk.items().count()`; let's do that instead of keeping
the perfect exact count synchronized with the chunks, which pollutes the
code in a few places.
This patch renames `TimelineEnd` into `TimelineNewItemPosition` for
2 reasons:
1. In the following patches, we will introduce a new variant to insert
at a specific index, so the suffix `End` would no longer make sense.
2. It's exactly like `TimelineItemPosition` except that it's used
only and strictly only to add **new** items, which is why we can't use
`TimelineItemPosition` because it contains the `UpdateDecrypted`
variant. This renaming reflects it's only about **new** items.
This patch takes the opportunity to move the `RemoteEventOrigin` inside
`TimelineNewItemPosition` to simplify method signatures. They always
go together.
These two are required to properly compute the room preview of a joined
room:
- m.room.create ends up filling the `room_type` (space or not)
- m.room.history_visibility ends up filling the `is_world_readable`
field.
It seems sensible to assume that if a client is able to generate a thumbnail,
it should be able to get all this information for it too.
A thumbnail with no information is not really useful, as we don't know when it could be used instead of the original image.
Removes `BaseThumbnailInfo`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch fixes a bug in `AsVector`: when an `Update::Clear` value
is received, `AsVector`'s internal state must be cleared too, i.e. the
`UpdateToVectorDiff::chunks` field should be reset to an initial value!
This patch adds a test to ensure this works as expected.
Ruma doesn't currently validate mxuri's and as such `MediaSource`s passed over FFI can contain invalid/empty URLs. This change introduces a wrapper type around Ruma's and failable transformations so that appropiate actions can be taken beforehand e.g. returning a `TimelineItemContent::FailedToParseMessageLike` or nil-ing out the thumbnail info.
This patch implements `LinkedChunk::clear`. The code from `impl Drop
for LinkedChunk` has been moved inside `Ends::clear`, and replaced by
a simple `self.links.clear()`. In addition, `LinkedChunk::clear` indeed
calls `self.links.clear()` but also resets all fields.
This patch adds the `Clear` variant to `Update`.
This patch updates `AsVector` to emit a `VectorDiff::Clear` on
`Update::Clear`.
Finally, this patch adds the necessary tests.
This patch updates `EventCacheStore::handle_linked_chunk_updates` to
take a `Vec<Update<Item, Gap>>` instead of `&[Update<Item, Gap>]`.
In fact, `linked_chunk::ObservableUpdates::take()` already returns a
`Vec<Update<Item, Gap>>`; we can simply forward this `Vec` up to here
without any further clones.
This patch creates a new `MemoryStoreInner` and moves all fields from
`MemoryStore` into this new type. All locks are removed, but a new lock
is added around `MemoryStoreInner`. That way we have a single lock.
A `RelationalLinkedChunk` is like a `LinkedChunk` but with a relational
layout, similar to what we would have in a database.
This is used by memory stores. The idea is to have a data layout that
is similar for memory stores and for relational database stores, to
represent a `LinkedChunk`.
This type is also designed to receive `Update`. Applying `Update`s
directly on a `LinkedChunk` is not ideal and particularly not trivial
as the `Update`s do _not_ match the internal data layout of the
`LinkedChunk`, they have been designed for storages, like a relational
database for example.
This type is not as performant as `LinkedChunk` (in terms of memory
layout, CPU caches etc.). It is only designed to be used in memory
stores, which are mostly used for test purposes or light usages of the
SDK.
When instantiating a room preview, previously it would try to just check if the room exists locally either as joined, invited, knocked, left, etc., and then retrieve the info we cached about it.
While this seems fine for most cases, it turns out for non-joined rooms, the info we have locally will **always** be the one we received when the invite/knock/leave action took place and it'll never be updated,
so we may have the case where we knock into a room, never receive a response, someone changes the join rule of the room to something else and we'll think about this room as a 'request to join' room until we clear the local cache.
To prevent that, we can only use the local data for joined rooms, which are constantly updated, and try to use the room summary API and other fallbacks for the rest, even if they're rooms known to us.
There's a lock making sure we're not doing multiple refreshes of an OIDC
token at the same time. Unfortunately, this lock could be dropped, if
the task spawned by the inner function was detached.
The lock must be held throughout the entire detached task's lifetime,
which this refactoring ensures, by setting the lock's result after
calling the inner function.
It has the same semantics used when creating a caption (if no formatted
caption is provided, assume a provided caption is markdown and use that
as the formatted caption).
This PR makes audio, file, image and video messages be editable so that
the timeline signals when it is possible to use #4277/#4300 for editing
captions.
The (matrix-sdk-)common crate used the (matrix-sdk-)test crate only to
benefit from the `async_test` proc macro, which is conveniently defined
in another crate.
My goal is to make `EventFactory`, at this point in the commit history,
defined in the main SDK crate, available in the test crate.
`EventFactory` makes use of some types defined in common, so there's a
circular dependency at the moment.
To split this circular dependency, I've changed the common crate to
depend on the test-macro crate directly; now the test crate can depend
on the common crate, and everybody's happy.
test(timeline): add an integration test for sending an attachment
test(timeline): add tests for multiple caption edits and local reaction to a media upload
There has been a recent change on `Decryptor::decrypt_event_impl` causing
the function to return an TimelineEvent of kind unable to decrypt
instead of failing with an error.
The `late_decrypt` detection code was not changed, causing any retry to
mark UTDs as late decrypt.
This patch introduces a struct that normalizes and sanitizes display
names. Display names can be a source of abuse and can contain characters
which might make it hard to distinguish one display name from the other.
This struct attempts to make it easier to protect against such abuse.
Changelog: Introduce a DisplayName struct which normalizes and sanitizes
display names.
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
There was an implicit relationship that the `being_sent` lock needed to
be taken in order to do non-atomic state store operations. With the
change from this commit, the relationship is now more explicit: to get a
handle to the state store, or being_sent, you have to obtain a
`StoreLockGuard` by locking against the store itself. The `WeakClient`
isn't stored in the QueueStorage data structure itself, so it's the only
way to get a `dyn StateStore` from the `QueueStorage`.
Prior to this patch, the send queue would not maintain the ordering of
sending a media *then* a text, because it would push back a dependent
request graduating into a queued request.
The solution implemented here consists in adding a new priority column
to the send queue, defaulting to 0 for existing events, and use higher
priorities for the media uploads, so they're considered before other
requests.
A high priority is also used for aggregation events that are sent late,
so they're sent as soon as possible, before other subsequent events.
Add the `markdown` feature to the SDK crate, otherwise we can't use `FormattedBody::markdown`.
Refactor the pattern matching into an if, add tests to check its behaviour.
Changelog: For `Timeline::send_*` fns, treat the passed `caption` parameter as markdown and use the HTML generated from it as the `formatted_caption` if there is none.
Changelog: This patch introduces a mechanism similar to
`Client::add_event_handler` and `Client::add_room_event_handler`
but with a reactive programming pattern. This patch adds
`Client::observe_events` and `Client::observe_room_events`.
```rust
// Get an observer.
let observer =
client.observe_events::<SyncRoomMessageEvent, (Room, Vec<Action>)>();
// Subscribe to the observer.
let mut subscriber = observer.subscribe();
// Use the subscriber as a `Stream`.
let (message_event, (room, push_actions)) = subscriber.next().await.unwrap();
```
When calling `observe_events`, one has to specify the type of event
(in the example, `SyncRoomMessageEvent`) and a context (in the example,
`(Room, Vec<Action>)`, respectively for the room and the push actions).
This patch updates `eyeball-im` and `eyeball-im-util` to integrate
https://github.com/jplatte/eyeball/pull/63/. With this new feature, we
can have a single implementation of `ObservableMap` (instead of 2: one
for all targets, one for `wasm32-u-u`). It makes it possible to get
`Client::rooms_stream` available on all targets now.
The caption and filenames were weirdly duplicated in each media content,
when the expected behavior is well defined:
- if there's both a caption and a filename, body := caption, filename is
its own field.
- if there's only a filename, body := filename.
We can remove all duplicated fields, knowing this, and reconstruct the
body based on that information. This should make it clearer to FFI users
which is what, and provide a clearer API when creating the caption and
so on.
This patch continues to simplification of the `matrix_sdk_ffi::Client`.
The constructor can receive a `enable_oidc_refresh_lock: bool` instead
of `cross_process_refresh_lock_id: Option<String>`, which was a copy of
`matrix_sdk::Client::cross_process_store_locks_holder_name`.
Now there is a single boolean to indicate whether
`Oidc::enable_cross_process_refresh_lock` should be called
or not. If it has to be called, it is possible to re-use
`matrix_sdk::Client::cross_process_store_locks_holder_name`. Once
again, there is a single place to read this data, it's not copied over
different semantics.
This patch simplifies a little the `ClientBuilder` API:
* `enable_cross_process_refresh_lock` is removed
* `enable_oidc_refresh_crypto_lock` + `set_session_delegate` must be
used instead.
This patch removes the `process_id` argument from
`EncryptionSyncService::new()` and replaces it by
`Client::cross_process_store_locks_holder_name`. The “process ID” is
set when the `Client` is converted into another `Client` tailore for
notification in `NotificationClient` with `Client::notification_client`
which now has a new `cross_process_store_locks_holder_name` argument.
See the Changelog Section to get the details.
Changelog: `Client::cross_process_store_locks_holder_name` is used everywhere:
- `StoreConfig::new()` now takes a
`cross_process_store_locks_holder_name` argument.
- `StoreConfig` no longer implements `Default`.
- `BaseClient::new()` has been removed.
- `BaseClient::clone_with_in_memory_state_store()` now takes a
`cross_process_store_locks_holder_name` argument.
- `BaseClient` no longer implements `Default`.
- `EventCacheStoreLock::new()` no longer takes a `key` argument.
- `BuilderStoreConfig` no longer has
`cross_process_store_locks_holder_name` field for `Sqlite` and
`IndexedDb`.
This patch adds `ClientInner::cross_process_store_locks_holder_name` and
its public method `Client::cross_process_store_locks_holder_name`. This
patch also adds `ClientBuilder::cross_process_store_locks_holider_name`
to configure this value.
Changelog: Implement proper redact handling in the widget driver.
This allows the Rust SDK widget driver to support widgets that
rely on redacting.
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
Previously this only used the Ruma checks, which only handled the initial `#` char and the domain part. With these changes, the name part is also validated, checking it's lowercase, with no whitespaces and containing only allowed chars, similar to what `DisplayName::to_room_alias_name` does.
Moved the code to the SDK crate so it can be properly tested.
This one is used when caching a thumbnail everywhere, and when
attempting to retrieve it; it gives us a single place where to
coordinate the default `MediaThumbnailSettings` parameters.
The previous values would lead to super large memory allocations, as
observed with `valgrind --tool=massive` on the tiny test added in this
commit:
- for 400 rooms each having 100 events, this led to 540MB of
allocations.
- for 1000 rooms each having 100 events, this led to 1.5GB of
allocations.
This is not acceptable for any kind of devices, especially for mobile
devices which may be more constrained on memory. The bloom filter is an
optimisation to avoid going through events in the room's event list, so
it shouldn't cause a big toll like that; instead, we can reduce the
parameters values given when creating the filters.
With the given parameters, 1000 rooms each having 100 events leads to
1.2MB of allocations.
With this, we get notified of the current verification state almost immediately.
Without it, you may either call it too soon and receive an `Unknown` state or you might have to call `Encryption::wait_for_e2ee_initialization_tasks()` and wait until it's finished to request a valid state value.
This patch introduces `EmptyChunk`, a new enum used to represent whether
empty chunks must be removed/unlink or kept from the `LinkedChunk`. It
is used by `LinkedChunk::remove_item_at`.
Why is it important? For example, imagine the following situation:
- one inserts a single event in a new chunk (possible if a (sliding)
sync is done with `timeline_limit=1`),
- one inserts many events at the position of the previous event,
with one of the new events being a duplicate of the first event
(possible if a (sliding) sync is done with `timeline_limit=10` this
time),
- prior to this patch, the older event was removed, resulting in an
empty chunk, which was removed from the `LinkedChunk`, invalidating
the insertion position!
So, with this patch:
- `RoomEvents::remove_events` does remove empty chunks, but
- `RoomEvents::remove_events_and_update_insert_position` does NOT remove
empty chunks, they are kept in case the position wants to insert in this
same chunk.
This fixes a problem when doing an incremental sync at launch,
where `NotLoaded` event would not be dispatched until data became
available or timeout is reached, leading to app waiting for it.
Changelog: the parameter `room_info_notable_update_receiver` was removed
from `RoomList::entries_with_dynamic_adapters`, since it could be
inferred internally instead.
Notably, make it super clear what parameters are required to create the
attachment type, since the function doesn't consume the whole
`AttachmentConfig` for realz.
Changelog: The send queue will now store a serialized
`QueuedRequestKind` instead of a raw event, which breaks the format.
As a result, all send queues have been emptied.
This makes it possible to have different kinds of *parent key*, to
update a dependent request. A dependent request waits for the parent key
to be set, before it can be acted upon; before, it could only be an
event id, because a dependent request would only wait for an event to be
sent. In a soon future, we're going to support uploading medias as
requests, and some subsequent requests will depend on this, but won't be
able to rely on an event id (since an upload doesn't return an
event/event id).
Since this changes the format of `DependentQueuedRequest`, which is
directly serialized into the state stores, I've also cleared the table,
to not have to migrate the data in there. Dependent requests are
supposed to be transient anyways, so it would be a bug if they were many
of them in the queue.
Since a migration was needed anyways, I've also removed the `rename`
annotations (that supported a previous format) for the
`DependentQueuedRequestKind` enum.
Breaking: `ffi::Client::resolve_room_alias` now returns `Result<Option<ResolvedRoomAlias>, ClientError>` instead of `Result<ResolvedRoomAlias, ClientError>`. This allows the client to match the 3 possible cases:
- The room alias exists.
- The room alias does not exist.
- The function failed internally.
This should take care of a bug that caused pinned events to be incorrectly removed when the new pinned event ids list was based on an empty one if the required state of the room didn't contain any pinned events info
This patch removes `RoomListService::new_with_encryption`. This feature
is not used, not useful since it's best to use `EncryptionSyncService`,
and it can be racy depending on how it's used. To avoid potential errors
and bugs, it's preferable to remove this code.
Changelog: a new optional `via_server` parameter was added to `sdk::RoomDirectorySearch::search`, to specify which homeserver to use for searching rooms. In the FFI layer, this parameter is called `via_server_name`.
This patch uses the new `Deduplicator` type, along with
`LinkeChunk::remove_item_at` to remove duplicated events. When a new
event is received, the older one is removed.
This patch introduces `Deduplicator`, an efficient type to detect
duplicated events in the event cache. It uses a bloom filter, and
decorates a collection of events with `Decoration`, which an enum that
marks whether an event is unique, duplicated or invalid.
Changelog: Renamed all the send-queue related "events" to "requests", so
as to generalize usage of the send queue to not-events (e.g. medias,
redactions, etc.).
In a next commit, the `QueuedEvent` will be renamed to `QueuedRequest`.
This specifies which kind of request we want to send with the send
queue; for now, it can only be an event.
This patch fixes a bug in an optimisation inside `UpdateToVectorDiff`
when an `Update::PushItems` is handled. It can sometimes create
`VectorDiff::Append` instead of a `VectorDiff::Insert`. The tests will
be part of the next patch.
This patch adds an `Event` type alias to `SyncTimelineEvent` to (i) make
the code shorter, (ii) remove some cognitive effort, (iii) make things
more convenient.
This method will return a `RoomPreview` for the provided room id.
Also added `fn RoomPreview::leave()` action to be able to decline
invites or cancel knocks, since there wasn't a
`Client::leave_room_by_id` counterpart as there is for join.
The PR also deprecates `RoomListItem::invited_room`, since we have a
better alternative now.
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
Changelog: Support for preallocated media content URI has been added in
`Media::create_content_uri()`, and uploading the content for such a
preallocated URI is possible with `Media::upload_preallocated()`.
Modify the SendQueue in order to persist the error that cause the event
to fail to send as a `QueueWedgeError`. The `QueueWedgeError` is not a
1:1 mapping for all kinds of errors, but holds variant and information
that the client can react to in order to propose "quick fixes"/solution
before retrying to send.
Fixes https://github.com/matrix-org/matrix-rust-sdk/issues/3973
Also fixes https://github.com/element-hq/element-x-ios/issues/3287
because when a timeline reset occurs the fail to send reason is also
lost.
This PR starts with a refactoring commit
https://github.com/matrix-org/matrix-rust-sdk/commit/e7696003e846b64c41761109f326fd37c4506040
to introduce the new `QueueWedgedError` and move the logic that was in
the ffi layer to convert api errors to SendState error variant. This
`QueueWedgedError` can be directly use in the `SendingFailed` variant
and expose to ffi.
Second commit
https://github.com/matrix-org/matrix-rust-sdk/commit/109c1337465ba7965825fec858fd2a4b8b954611
adds the persistence, `QueuedEvent` now have an optional error field
instead of a `is_weged` boolean. Same for LocalEchoContent::Event.
Adds also Migration for sqlite and indexeddb
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
Changelog: We now persist the error that caused an event to fail to send. The error `QueueWedgeError` contains info that client can use to try to resolve the problem when the error is not automatically retry-able. Some breaking changes occurred in the FFI layer for `timeline::EventSendState`, `SendingFailed` now directly contains the wedge reason enum; use it in place of the removed variant of `EventSendState`.
Before we do any more work here, give this variant a better name
Breaking-Change: `matrix_sdk_crypto::type::events::UtdCause::Membership` has
been renamed to `...::SentBeforeWeJoined`.
The FFI will request a scaled version of the thumbnail by default; let's
use the same cache key when caching the thumbnail after an upload.
Thanks @zecakeh for flagging the issue.
This patch removes the `settings` argument of
`RoomListService::subscribe_to_rooms`. The settings were mostly composed
of:
* `required_state`: now shared with `all_rooms`, so that we are
sure they are synced; except that `m.room.create` is added for
subscriptions.
* `timeline_limit`: now defaults to 20.
This patch thus creates the `DEFAULT_REQUIRED_STATE` and
`DEFAULT_ROOM_SUBSCRIPTION_TIMELINE_LIMIT` constants.
Finally, this patch updates the tests, and updates all usages of
`subscribe_to_rooms`.
This patch adds the `m.room.topic` and `m.room.pinned_events` state
events in the `required_state` of the `all_rooms` sliding sync list of
`RoomListService`.
We can't know which key is going to be used precisely for the thumbnail,
so assume non-animated cropped same-size thumbnail media request.
Changelog: when `SendAttachment::store_in_cache()` is set, the thumbnail
is also cached with a sensible default media request (not animated,
cropped, same dimensions as the uploaded thumbnail).
Make the tests behave the same way as the network code, by returning UTDs
as `TimelineEventKind::UnableToDecrypt` instead of `TimelineEventKind::PlainText`.
There's no need for this API anymore.
Changelog: `Timeline::get_event_timeline_item_by_transaction_id` has
been removed. There's no API that makes use of an `EventTimelineItem`
now, those APIs are using a `TimelineEventItemId` instead.
I feel like the ability to convert straight from a `Raw<AnySyncTimelineEvent>>`
into a `SyncTimelineEvent` is somewhat over-simplified: the two are only
occasionally equivalent, and it's better to be explicit.
Changelog: `SyncTimelineEvent` no longer implements `From<Raw<AnySyncTimelineEvent>>`.
The event cache stores its events in a linked chunk. The linked chunk
supports updates (`ObservableUpdates`) via `LinkedChunk::updates()`.
This `ObservableUpdates` receives all updates that are happening inside
the `LinkedChunk`. An `ObservableUpdates` wraps `UpdatesInner`, which
is the real logic to handle multiple update readers. Each reader has a
unique `ReaderToken`. `UpdatesInner` has a garbage collector that drops
all updates that are read by all readers. And here comes the problem.
A category of readers are `UpdatesSubscriber`, returned by
`ObservableUpdates::subscribe()`. When an `UpdatesSubscriber` is
dropped, its reader token was still alive, thus preventing the garbage
collector to clear all its pending updates: they were kept in memory
for the eternity.
This patch implements `Drop` for `UpdatesSubscriber` to correctly remove
its `ReaderToken` from `UpdatesInner`. This patch also adds a test that
runs multiple subscribers, and when one is dropped, its pending updates
are collected by the garbage collector.
The name wasn't very descriptive, and it's tweaking the content, so
let's do that in place, instead of deferring to another method somewhere
else in the codebase.
The tails of the prepare_attachment_message and
prepare_encrypted_attachment_message were almost the same, with the one
different that they were using different ctors for the `EventContent`
types. In fact, all these `EventContent` types also expose a plain `new`
function that can take in either an encrypted or a plain media source,
so we can commonize the code there.
This allows clients to set custom join rules for a room, as would be needed for the knock-only rooms, or restricted rooms (those that can only be joined if the user is part of some other room or space).
See previous commit for explanations. This makes for a simpler API
anyways.
Changelog: `Timeline::edit` doesn't return a bool anymore to indicate it
couldn't manage the edit in some cases, but will return errors
indicating what the cause of the error is.
I think this can't happen, but the send queue can return an error if a
local echo identified by a transaction id doesn't exist anymore in the
database. The only reason the latter could happen is because the local
echo has been sent, in which case an update to the timeline would be
dispatched, and the timeline item would have morphed into a remote echo
in the meantime. So it's really rare that this would happen, and the
`Timeline::redact()` method doesn't have to return a boolean to indicate
success in general.
Changelog: `Timeline::redact()` doesn't return a boolean; previously, it
would only return false if the internal state was invalid, so a new
error `RedactError::InvalidLocalEchoState` has been introduced to
represent that.
This maintains functionality we had prior to the previous commit: if an
event's missing from the timeline (e.g. timeline's been cleared after a
gappy sync response), then still allow editing it.
In particular, this means that trying to edit an event that's not
present anymore in a timeline (e.g. after a timeline reset) will fail,
while it worked before.
Changelog: `Timeline::edit_by_id` has been fused into `Timeline::edit`,
which now takes a `TimelineEventItemId` as the identifier for the local
or remote item to edit. This also means that editing an event that's not
in the timeline anymore will now fail. Callers should manually create
the edit event's content, and then send it via the send queue; which the
FFI function `Room::edit` does.
Changelog: `Timeline::redact_by_id` has been fused into
`Timeline::redact`, which now takes a `TimelineEventItemId` as an
identifier of the item (local or remote) to redact.
We can now use this type instead of passing a string, which means
there's no way to confuse oneself in methods like
`toggle_reaction_local`.
Changelog: Introduced `TimelineUniqueId`, returned by
`TimelineItem::unique_id()` and serving as an opaque identifier to use
in other methods modifying the timeline item (e.g. `toggle_reaction`).
This would not report the `txn_id` field because of the `skip_all`. It's
actually interesting to also get the error, so I'm only skipping self
from now on.
I suppose these were useful at the FFI layer at some point, but they
aren't anymore, so they could be removed.
Changelog: Got rid of `From<String/&str>` for `TimelineEventItemId`.
This would have avoided a few hours of debugging where we thought there
was an issue with multiple timelines spawned at the same time, and then
realized it was expected because of the existence of the pinned timeline
in EX apps.
Older versions of Git require --interactive when we supply --autosquash,
and it's also probably a good idea generally.
See https://stackoverflow.com/a/77663575/22610 for more info.
Changelog: `Client::url_for_oidc_login` is now `Client::url_for_oidc` with an additional `OidcPrompt` parameter. `abort_oidc_login` has been renamed to `abort_oidc_auth`.
This allows clients to directly open the web page they want: the login one, the registration one, consent, etc. It should improve the UX in the registration flow since we can now skip the login one.
We depend on the `futures_util::steam_select` macro since 9b36a04b. This
macro requires the async-await-macros and std feature of futures-util.
These features are the default features so let's just stop disabling the
default features for futures-util.
Signed-off-by: Damir Jelić <poljar@termina.org.uk>
Co-authored-by: Jonas Platte <jplatte@matrix.org>
This patch updates the `required_state` of `all_rooms` inside the
`RoomListService` to add `m.room.name`. Apparently, Synapse doesn't
always update the `response.rooms.*.avatar` field when the avatar is
updated. It's being investigated, but it doesn't hurt to ensure we get
it from the state events.
To fix the `test_room_avatar_group_conversation`, we need to ask for the
`m.room.avatar` state event from `required_state`. The rest of the patch
rewrites the test a little bit to make it more Rust idiomatic.
The `response.rooms.*.avatar` field from sliding sync should contain the
new avatar, but for the moment, it doesn't. It seems to be a bug.
To fix the `test_left_room`, we need to ask for the `m.room.member`
state event from `required_state`. The rest of the patch rewrites the
test a little bit to make it more Rust idiomatic.
Sliding sync expects all state events to be in `required_state`. State
events in `timeline` **must be ignored**. However, in sync v2, state
events in `timeline` **must be handled**.
In the sync response flow, both sliding sync and sync v2 uses the same
`handle_timeline` method. This patch adds an argument to ignore state
events. This is not ideal, but it's a temporary solution as a first
step. The next step is to refactor this code, but let's start easy.
The rest of the patch updates the tests accordingly.
With sliding sync, we must handle state events from `required_state`
only, not from `timeline`, this is a mistake as they might be incomplete
or _staled_.
I'm going to be replacing the inner structure of `TimelineEvent` with an
implementation that holds a `Raw<AnySyncTimelineEvent>`, rather than a
`Raw<AnyTimelineEvent>`. Prepare for that by changing the accessors to return
`Raw<AnySyncTimelineEvent>`.
... and add accessors instead.
Give `TimelineEvent` the same treatment we just gave `SyncTimelineEvent`: make
the fields private, and use accessors where we previously used direct access.
... and add accessors instead.
I'm going to change the inner structure of `SyncTimelineEvent`, meaning that
access will have to be via an accessor in future. Let's start by making the
fields private, and use accessors where we previously used direct access.
I'm going to change the internal structure of `SyncTimelineEvent`, and since
it implements `Deserialize`, we need to not break it. Let's add a test for the
current format.
`bootstrap_cross_signing` holds a lock on the private identity. In case
a new identity is created, it will try to acquire a lock on `account`.
The latter is locked by `sync`, which tries to acquire a lock on the private identity.
Note that the `bootstrap_cross_signing` call is executed in a separate
task e.g. in `restore_session`. In particular, this task and `sync` both
race to acquire locks described above.
Signed-off-by: boxdot <d@zerovolt.org>
This is useful for the knocking feature since we'll be able to differentiate between rooms that you were just invited from rooms that you knocked and then were granted access, or rooms that you left and rooms where your knocking attempt was rejected.
The `mark_room_as_*` functions have been updated so they reuse the same `set_state` function underneath, which only updates the previous state if the new one doesn't match.
Was added post-merge to the MSC for servers that support
authenticated media but do not support all of Matrix 1.11 yet.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch changes the behaviour of `timeline_limit` in sliding sync
requests. It previously was sticky, but since it's now mandatory
with MSC4186, it's preferable it to be non-sticky, otherwise in
some scenarios it might default to 0 (its default value). How?
If the server doesn't reply with our `txn_id` (because it doesn't
support sticky parameters or because it misses a `txn_id`), the
next request will be built with a default `timeline_limit` value,
which is zero, and won't get updated to the `timeline_limit` value
from `SlidingSyncListStickyParameters`. This is not good. Instead,
we must consider `timeline_limit` as non-sticky, and moves it from
`SlidingSyncListStickyParameters` to `SlidingSyncListInner`. This is
what this patch does.
The content of a poll timeline item goes to the content directory. The
data structure handling pending poll events goes into state.
No functional changes, only code motion.
It can occur that the data contains rooms that were forgotten.
Knowing that we now update that data after every sync, that creates
a lot of noise in the logs.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The `handle_reaction_redaction` method is called by `handle_redaction`
for every single redaction event that we receive as a first step to
check if the redaction matches a reaction.
It means that not finding a reaction to redact is perfectly fine and is not worthy of a warning.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This old method was checking invariants that were
spooky-action-at-a-distance: these invariants have changed since then,
so this would panic instead of returning a proper error to the caller.
Signed-off-by: oliverw@element.io
---------
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
This was because we used a `BTreeSet`, which doesn't make sense anymore
since the data part of the key got mangled with some value unrelated to
the key itself.
This seems to be the only way to make the log rotation fix work and avoid build warnings like:
```
warning: patch for the non root package will be ignored, specify patch at the workspace root:
package: matrix-rust-sdk/bindings/matrix-sdk-ffi/Cargo.toml
workspace: = matrix-rust-sdk/Cargo.toml
Finished `dev` profile [unoptimized] target(s) in 0.30s
```
This improves parsing times in mobile Clients. On Android, this means a 5-10x faster parsing of timeline events.
To do that I had to:
- Make functions like `edit/redact/forward` take an identifier (EventId/TransactionId) instead of the actual event. This id will be used to look for the actual SDK timeline event in the timeline. This change will make these functions a bit less performant.
- Make `InReplyToDetails` an object instead since a record can't recursively contain itself.
- Turn `EventTimelineItem` into a record type. Do the same with `Message`, which is now `MessageContent`.
These tests were failing since the migration from the sliding sync proxy
to Synapse.
Since the previous fixes to re-enable other tests, these 2 passes for
free.
This test was failing since the migration from the sliding sync proxy
to Synapse.
This patch fixes the test. The failing parts were:
1. The `timeline_limit` wasn't set, so Synapse was returning an error,
2. The `unread_notifications` was set to 0 and could not be set to 1
because that's an encrypted room.
The fact `timeline_limit` is now mandatory has been mentioned in the MSC:
https://github.com/matrix-org/matrix-spec-proposals/pull/4186/files#r1775138458
A patch in Ruma has been created. The previous patch in this repository
also contains the fix for the SDK side.
The assertions around `unread_notifications` have been removed. We no
longer use this API anymore (and it should be deprecated by the way).
Since MSC4186, the `timeline_limit` value is required.
This patch uses 1 as the default value for `timeline_limit`, and forces
the `timeline_limit` to be defined everywhere.
When Bob receives the invite, the room has the correct name. Bob to sync
more to receive the new name. This is not a bug.
This patch updates the `CreateRoomRequest` to set the correct name
immediately.
This test was failing since the migration from the sliding sync proxy
to Synapse.
This patch fixes the test. The failing part was:
```rust
assert_eq!(notification.joined_members_count, 1);
```
This patch changes the value from 1 to 0. Indeed, Synapse doesn't share
this data for the sake of privacy because the room is not joined.
A comment has been made on MSC4186 to precise this behaviour:
https://github.com/matrix-org/matrix-spec-proposals/pull/4186#discussion_r1774775560.
Moreover, this test was asserting a bug (which is alright), but now
a bug report has been made. The patch contains the link to this bug
report.
The code has been a bit rewritten to make it simpler, and more comments
have been added.
Instead of forcing the room encryption to be known when the timeline is created and failing if it's not known, take the latest room encryption info as a base value and update it when processing timeline events.
At the time of writing this commit, the encryption info is only used to decide whether shields should be calculated for timeline items or not.
- explain what these tests are
- mention that it's sometimes needed to rebuild the synapse image
---------
Signed-off-by: Benjamin Bouvier <benjamin@bouvier.cc>
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
This patch updates `merge_stream_and_receiver` to display an `error!`
when the room info receiver reads an error, like `Closed` or `Lagged`.
This is helpful when debugging.
The NotificationClient, responsible for handling, fetching, and
potentially decrypting events received via push notifications, creates a
copy of the main Client object.
During this process, the Client object is adjusted to use an in-memory
state store to prevent concurrency issues from multiple sync loops
attempting to write to the same database.
This copying unintentionally recreated the OlmMachine with fresh data
loaded from the database. If both Client instances were used for syncing
without proper cross-process locking, forks of the vodozemac Account and
Olm Sessions could be created and later persisted to the database.
This behavior can lead to the duplication of one-time keys, cause
sessions to lose their ability to decrypt messages, and result in the
generation of undecryptable messages on the recipient’s side.
This patch adds a new `cancel_in_flight_request` argument to
`SlidingSync::subscribe_to_rooms`, which tells the method cancel the
in-flight request if any.
This patch also updates `RoomListService::subscribe_to_rooms` to turn
this new argument to `true` if the state machine isn't in a “starting”
state.
The problem it's solving is the following:
* some apps starts the room list service
* a first request is sent with `pos = None`
* the server calculates a new session (which can be expensive)
* the app subscribes to a set of rooms
* a second request is immediately sent with `pos = None` again
* the server does possibly NOT cancel its previous calculations, but
starts a new session and its calculations
This is pretty expensive for the server. This patch makes so that the
immediate room subscriptions will be part of the second request, with
the first request not being cancelled.
This method is now private inside `matrix_sdk_ui` and removed
from `matrix_sdk_ffi`. This method is returning a stream of rooms,
but updates on rooms won't update the stream (only new rooms
will be seen on the stream). Nobody uses it as far as I know, and
`entries_with_dynamic_adapters` is the real only API we want people
to use.
This field is helpful as it tells us the sequence number of the message in the
megolm session, which gives us a clue about how long it will have been since
the session should have been shared with us.
This fn will loop until it finds an at least partially synced room with the given id. It uses the `ClientInner::sync_beat` listener to wait until the next check is needed.
This patch adds `m.room.canonical_name` in the `required_state` of the
`all_rooms` list defined by `RoomListService`.
This is useful to better compute the room name in a more robust way.
## Changes
Takes care of [this
TODO](https://github.com/matrix-org/matrix-rust-sdk/blob/9df1c480795c42afcee39e4c7e553d5a927a2680/crates/matrix-sdk-ui/src/timeline/mod.rs#L520).
- sdk & sdk-ui: unify `Timeline::edit` and `Timeline::edit_polls`, the
new fn takes an `EditedContent` parameter now, which includes a
`PollStart` case too.
- ffi: also unify the FFI fns there, using `PollStart` and a new
`EditContent` enum that must be passed from the clients like:
```kotlin
val messageContent = MessageEventContent.from(...)
timeline.edit(event, EditedContent.RoomMessage(messageContent))
```
Since the is mainly about changing the fns signatures I've reused the
existing tests, including one that used `edit_poll` that now uses the
new fn.
---------
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
There is a non-negligible difference MSC3575 and MSC4186 in how the
`e2ee` extension works. When the client sends a request with no `pos`:
* MSC3575 returns all device lists updates since the last request
from the device that asked for device lists (this works similarly to
to-device message handling),
* MSC4186 returns no device lists updates, as it only returns changes
since the provided `pos` (which is `null` in this case); this is in
line with sync v2.
Therefore, with MSC4186, the device list cache must be marked as to be
re-downloaded if the `since` token is `None`, otherwise it's easy to
miss device lists updates that happened between the previous request and
the new “initial” request.
This patch adds the `OldMachine::mark_all_tracked_users_as_dirty`.
This patch rewrites a bit `OlmMachine::new_helper` by extracting some
piece of it inside `OlmMachine::new_helper_prelude`. With that, we
can rewrite `OlmMachine::migration_post_verified_latch_support` to use
`IdentityManager::mark_all_tracked_users_as_dirty`.
This latter is the shared implementation with
`OlmMachine::mark_all_tracked_users_as_dirty`.
This patch adds a test for `OlmMachine:mark_all_tracked_users_as_dirty`.
This patch improves `Client::available_sliding_sync_versions` when
trying to detect the sliding sync proxy. Previously, we were relying
on the `Client::server` to send the `discover_homeserver::Request`.
Sadly, this value is an `Option<_>`, meaning it's not always defined
(it depends how the `Client` has been built with `HomeserverConfig`:
sometimes the homeserver URL is passed directly, so the server cannot
be known).
This patch tries to find to discover the homeserver by using
`Client::server` if it exists, like before, but it also tries by using
`Client::user_id`. Another problem arises then: the user ID indeed
contains a server name, but we don't know whether it's behind HTTPS or
HTTP. Thus, this patch tries both: it starts by testing with `https://`
and then fallbacks to `http://`.
A test has been added accordingly.
The term session is usually only used in the crypto crate to reference a
Megolm session, the rest of the SDK uses the name from the event and the
Matrix spec, this should lower the amount of confusion since the main
crate has already a session concept and its unrelated to end-to-end
encryption.
My theory is that the intermittent failure depends on the ordering of
the requests, and if the /keys/upload request happened before the key
backup request, then after failing the next key backup request wouldn't
run.
This is likely a small typo that the key upload returns a 404 error
instead of a 200, let's see if this improves the situation.
It does not make much sense to create an UI client that does not support
end-to-end encryption, besides disabling the feature was broken for
quite some time.
* Not verifying the remote device/user is normal: log it at debug rather than
info.
* On the other hand, if we do verify something, let's log that at info rather
than trace.
Also fix a comment, while we're here.
* Upgrade the log when we get the "reciprocate" message (which tells us the
other side has scanned our QR code) to debug, instead of trace.
* Warn if we get a reciprocate we don't understand
* Log when the user confirms that the other side has scanned successfully.
This is the message that tells us whether the other side wants to do QR code or
SAS (emoji) verification. Knowing which they have chosen is really helpful for
following the flow!
Attach the flow_id (the transaction ID or message ID from the `request`
message) to the span, so that it is displayed alongside loglines that happen
when processing the request.
Take the logging that happens when a QR code verification is added to the
`verification cache`, and push it down to the `VerificationCache` itself. Doing
so means that we will log when we *show* a QR code as well as when we scan it.
I would have found this helpful when trying to debug a verification flow this
week.
For debugging, it's useful to have a record of what we believe our own public
cross-signing keys to be. Currently, we log the keys at startup if we restore
them from the database, but if we subsequently create, or download, a set of
keys, they aren't logged.
When we receive an `/keys/query` response, look for existing
inboundgroupsessions created by updated devices, and see if we can update any
of their senderdata settings.
This module has a number of useful types (in particular, error types). Rather
than addding even more types to the top level module, let's export the
`sender_data_finder` module as a whole.
Turns out that most of the places we call `find_using_device_keys`, we already
have a DeviceData. So we might as well pass that in directly, rather than
extracting the device keys and then rebuilding a DeviceData.
This patch renames `HomeserverConfig::Url` to `HomeserverUrl`, and
`HomeserverConfig::ServerNameOrUrl` to `ServerNameOrHomeserverUrl`.
Funnily, the methods on `ClientBuilder` doesn't need to be renamed to
match the new naming since they already use this naming!
When subscribing to an already subscribed room, the subscription state
was reset, the subscription was resent by cancelling the in-flight
request. All this is useless and can create a feeling of lag.
This patch checks if a room is subscribed first. If it is, nothing
happens. If it is not, the room subscription is created, and the
in-flight request is cancelled.
Tests are updated to reflect this new change.
Note: room subscription settings are not taken into account in this
“presence” pattern. It means that if we subscribe to an already
subscribed room but with different settings, nothing will happen. The
server will ignore the new settings anywhere for the moment.
This patch moves `client/builder.rs` into `client/builder/mod.rs`.
This patch also moves the `HomeserverConfig` type and its siblings
(`discover_homeserver`, `UrlScheme` etc.) into its own module `client/
builder/homeserver_config.rs`.
This is purely for cleaning up.
This patch adds `Client::server`: the URL of the server.
Not to be confused with the `Client::homeserver`. The `server`
holds some information, like the `.well-known` file, to discover the
homeserver. The homeserver is the client-server Matrix API.
`server` is usually the server part in a user ID, e.g. with
`@mnt_io:matrix.org`, here `matrix.org` is the server, whilst
`matrix-client.matrix.org` is the homeserver.
This patch also moves the code about homeserver discovery in the
`HomeserverConfig::discover` new method. A new struct is introduced to
hold the result, to replace a 4-tuples.
`Client::server` is also now a `Option<_>` because in the case of
`HomeserverConfig::Url`, the server cannot be known.
This patch also removes several clones here and there.
Finally, this patch updates a test to quickly test the new behaviour. A
next patch will introduce proper tests.
Especially for remote items, it should be in sync with `should_add` as
it's used in this method, otherwise read receipt tracking will not work
correctly.
This will only apply to `async_test` functions, but I think this is a
win:
1. for consistency within the codebase, since I've started doing so in
many places,
2. because these function names will clearly identify these functions as
tests, in the call tree interfaces, when rendered using the LSP
show-callers/show-callees functionality.
Including non-live timelines (pinned event timelines and permalinked
timelines). This makes it possible to see that you're adding a reaction
etc. in real time, while it wasn't the case anymore.
Fixes#3906.
This was copied from SqliteStateStore, but the reason
that they are separated there is because some migrations
require the store cipher.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Setting the version number only when all migrations are done
means that the version will be wrong if a migration fails.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Otherwise, this would mean that logged out clients would infinitely
repeat network requests failing in the background.
Without this fix, the added test will time out, endlessly reattempting
network requests.
This patch adds bindings to `Client::available_sliding_sync_versions`
to `matrix-sdk-ffi`.
This patch also moves `Client::sliding_sync_version` from “private” to
“public” FFI API, in thee sense that this method is now exported with
UniFFI.
Previous patches have unified all sliding sync versions behind a
single type: `Version`. More recent previous patches have introduced
`VersionBuilder` so that a `ClientBuilder` can use them to coerce or
find the best `Version` possible. This patch implements a last missing
piece: `Client::available_sliding_sync_versions` will report all
available `Version`s at a given time. This is useful when a `Client`
is already built, and a session has been opened/a user is logged,
but someone has to take the decision whether it's useful to switch to
another sliding sync version or not.
This patch adds a builder for `sliding_sync::Version`. It is a similar
enum except that it has `DiscoverProxy` and `DiscoverNative` to
automatically configure `Version::Proxy` or `Version::Native`.
This patch changes the type of
`discover_homeserver_from_server_name_or_url`. It now returns a `Url`
instead of a `String` for the homeserver URL. It also returns an
`Option<get_supported_versions::Response>` in addition to the other
values.
The change from `String` to `Url` is necessary to avoid a
double-parsing. It was parsed in `build()` but previously in
`discover_homeserver_from_server_name_or_url` in the last branch.
The addition of `get_supported_versions::Response` is necessary for the
next patch. It's going to be helpful to auto-discover sliding sync in
Synapse. The change happens here because
`get_supported_versions::Response` is already received in
`discover_homeserver_from_server_name_or_url`. This patch makes it easy
to re-use it so that the request is sent only once.
This patch therefore changes `check_is_homeserver` a little bit to
become `get_supported_versions`, and inlines its previous call inside
`discover_homeserver_from_server_name_or_url`.
This patch replaces all the API using simplified sliding sync, or
sliding sync proxy, by a unified `sliding_sync::Version` type!
This patch disables auto-discovery for the moment. It will be re-enable
with the next patches.
If we're building for the wasm architecture, jump through the hoops to
tell wasm_bindgen about `ShieldStateCode`. This solves the need to
declare an identical copy of `ShieldStateCode` in the wasm bindings.
This is part of https://github.com/matrix-org/matrix-rust-sdk/pull/3662,
pulled out to into a separate PR. Recent changes in `main` made it
pretty much impossible to merge this section of code from `main` into
that PR, and Rich wanted to see the refactoring bits separate from the
behavioural changes. So I've re-written the refactoring.
Pulls the `match` on `sharing_strategy` outside of the `for` loop, and
moves any code that is specific to one strategy into the appropriate
branch.
This commit contains a new `assert_next_matches_with_timeout!` macro that will take a `Stream` and wait for a little while until its next item is ready, then match it to a pattern.
It was found that it's making the whole build slower because it's
hitting a pathologically slow path in type-checking. Considering that it
doesn't do much, let's get rid of it and inline it instead.
After this, compiles times are reduced from 30 seconds to 22 seconds on
my machine
This patch uses the new `RoomSubscriptionState` enum to filter
room subscriptions that have already been sent, when building a
`http::Request` with the sticky parameters.
By default, to start, a `http::request::RoomSubscription` is in the
state `Pending`, i.e. it's not sent yet. Once the sticky parameters are
committed, the state is updated to `Applied`. When the sticky parameters
are applied, only the `Pending` room subscriptions are added.
This patch contains one test to specifically assert this behaviour.
This patch adds the `commit` method on the `StickyData` trait. It is
called by `SlidingSyncStickyManager::maybe_commit` when we are sure the
data can be validated because of a valid response to the sent request.
## Changes
- Creates a separate `AllEventsCache` struct holding both the actual all
events cache map and the relationship one. This new cache wrapper also
holds a single `RwLock` to both inner caches, as they are independent
from each other.
- When a new event is saved either from `/sync` or another HS request,
it'll be saved to both the 'all events' cache and the relationship map.
- Add tests for the relationship cache.
Allows to save media in a different path than the state store.
This adds a "last_access" field to the SQLite implementation, to prepare
for future work on a media retention policy.
This removes the IndexedDB media cache implementation, because as far as
I know it is currently unused, and I have no idea how to implement
efficiently the planned media retention policy with a key-value store.
Closes#1810.
- [x] Public API changes documented in changelogs (optional)
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch clears all sliding sync room subscriptions when a session
expires. Indeed, we might not want to request all room subscriptions
when the session restarts. Imagine if the client has subscribed to 400
rooms and the session expires: once the session restarts, it will ask
for 400 room subscriptions, which is a lot and will result in a quite
slow response.
We're finding ourselves in the situation in which we can't interact with
invites through normal Room APIs as `full_room`s can't be build from the
RoomListItem. Full rooms require the timeline to be configured before
use and the timeline can't be configured because encryption cannot be
fetched for invited rooms on homeservers that have previews disabled
(see #3848 and #3850)
In response we now expose the room's membership directly from the
`RoomListItem` so that the final client can chose which of the 2 rooms
types (invited or full) to ask for before using aforementioned APIs.
Powers https://github.com/element-hq/element-x-ios/pull/3189
This patch updates when sliding sync requests have a `timeout`.
Prior to this patch, all requests had a `timeout` query, set to the
`poll_timeout` duration value. However it means: if there is no data
to return, wait `timeout` milliseconds for new data before returning.
This definition is correct. Problem: if the current range of a list
has no data, the server will wait! It means that, in a situation where
there is no update at all, but the client is fetching all rooms batch by
batch, it will wait `poll_timeout` for each batch!
The behaviour described above is absolutely correct. Some server
implementations are less strict though, and we didn't realise our code
was doing that, because the server had some optimisations to ignore the
timeout if the range wasn't covering all the rooms. Nonetheless, a new
server implementation (namely Synapse) is strict, and it confirms we
have a bug here.
This patch then configures a `timeout` if all lists require a timeout,
otherwise there is no `timeout`, which is equivalent to `timeout=0`.
- this prevents issues where spoofing the sender field is enough to spoof and edit and display wrong decorations in the app
- fixes matrix-org/internal-config/issues/1549
Most times we pulled an InboundGroupSession from the sqlite DB, we were
overriding whatever value for `backed_up` was stored inside the pickled
value, and using the value stored in the SQL column.
But when we pulled a single InboundGroupSession from the DB by ID, we
did not override it.
I am fairly sure this was an accidental oversight, so this change
corrects it, and unifies the code with other places we create these
objects.
It seems that the fact that matrix-rust-sdk contains `olm-rs` in its
`Cargo.lock` sparked panic, so let's attempt to fend off future concerns by
adding a comment.
This patch fixes a bug in the tracing system. It introduces one
fields formatter _per layer_ to force the fields to be recorded in
different span extensions, and thus to remove the duplicated fields in
`FormattedFields`.
The patch contains links to the bug report in `tokio-rs/tracing`. This
patch is a workaround.
This patch removes `NotificationSettings::subscribe_to_changes` because
it's not used anywhere in our code except in tests. It is indeed part of
the public API but I'm not aware of anyone using it for the moment. It
only adds complexity in the code.
This patch replaces `RoomInfo::user_defined_notification_mode` by
its cached variant: `cached_user_defined_notification_mode`, and
call `Room::cached_user_defined_notification_mode` which will boost
performance when computing a new `RoomInfo`.
This patch splits/copies the
`test_room_info_deserialization_without_optional_items` test into the
same test + `test_room_info_deserialization`.
It appears that the _without optional items_ part has been forgotten.
In the past, the test has been updated to test optional items. The
initial idea (based on my understanding of the comments) is to test
potentially old `RoomInfo` can still be deserialized today. So this test
must never be changed, except if a non-optional field is added.
For this reason, this patch removes from this test the assertions about
optional fields. A new test, named `test_room_info_deserialization` is
created, and tests all the fields, including the optional ones.
One important thing:
`test_room_info_deserialization_without_optional_items` now runs
even if the `experimental-sliding-sync` feature is absent. It was
required only because of `latest_event`, but that's an optional
field! However, the `test_room_info_deserialization` requires the
`experimental-sliding-sync` feature, as it tests `latest_event` but
also `recency_stamp`.
Finally, `test_room_info_deserialization` tests
`cached_user_defined_notification_mode`.
This patch updates `matrix_sdk::Room::user_defined_notification_mode`
to cache its result if some mode has been found. The cached result can
be retrieve with
`matrix_sdk_base::Room::cached_user_defined_notification_mode`.
Use a for loop rather than `partition_map`. We're about to add a third list, so
partition_map won't work.
(partition_map ends up using Vec::push under the hood, so this is pretty much
equivalent.)
Update Ruma dependency to expect call membership state events with state
keys that are arbitrary strings, not just pure MXIDs.
When a call membership state key does not exactly match the format of an
MXID, treat it as a valid state key if it starts with an MXID followed
by an underscore, with that MXID designating the owner of the event.
(The state key may also be optionally prefixed with an underscore, which
is permitted as a way to bypass pre-MSC3757 authorization rules against
sending state events with state keys that do not exactly match the
sender's MXID.)
---------
Signed-off-by: Andrew Ferrazzutti <andrewf@element.io>
Co-authored-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Benjamin Bouvier <benjamin@bouvier.cc>
The timeline already listens to changes to the pinned events list (via a
stream), so there's no need to fully reload all the pinned events every
time we receive a new event that's pinned. Technically it may avoid one
or a few lookups, but this is cheap and a subsequent commit/PR will
merge the pinned event cache into the event cache.
This patch restricts the call to `compute_limited` to the sliding sync
proxy implementation (aka MCS3575). It is not necessary for the sliding
sync native implementation (aka Simplified MSC3575). The proxy doesn't
implement the `limited` flag, contrary to Synapse. Let's not run
workarounds when we don't need them.
The patch https://github.com/matrix-org/matrix-rust-sdk/pull/2395 has
introduced `SlidingSyncInner::past_positions` as a mechanism to filter
duplicated responses. It was a problem because the sliding sync `ops`
could easily create corrupted states if they were applied more than
once.
Since https://github.com/matrix-org/matrix-rust-sdk/pull/3664/, `ops`
are ignored.
Now, `past_positions` create a problem with the sliding sync native
implementation inside Synapse because `pos` can stay the same between
multiple responses.
While `past_positions` was helpful to fix bugs in the past, it's no
longer necessary today. Moreover, it breaks an invariant about `pos`: we
must consider it as a blackbox. It means we must ignore if a `pos` value
has been received in the past or not. This invariant has been broken for
good reasons, but it now creates new issues.
This patch removes `past_positions`, along with the associated code
(like `Error::ResponseAlreadyReceived` for example).
This patch changes the visibility of
`SlidingSyncList::invalidate_sticky_data` from `pub` to `pub(super)`.
This is the only place where it must be accessible from.
This patch asserts that when subscribing to a new room, the old room
subscriptions are still present. Is it the behaviour we want? Probably
not, but this is the standard behaviour right now, and we need to assert
it.
We had *two* copies of `response_from_file`, and all calls to them were always
immediately followed by an operation to parse the response as a Ruma response
object.
We can save a whole lot of boilerplate with a generic function that wraps the
json into an HTTP response *and* parses it into a Ruma object.
We weren't updating the database schema version immediately after the v10 -> v11
migration. This was fine in practice, because (a) for now, there is no v12
migration so we ended up setting the schema version immediately anyway; (b) the
migration is idempotent.
However, it's inconsistent with the other migrations and confusing, and is
about to make my test fail, so let's clean it up.
It's better to have fewer public APIs, especially when there's little
annoyance to have it. We could use a request builder that converts into
a Future, too, but considering there's only a single optional parameter,
it's fine to include it in the function's signature.
We should only show the spinner if the *first* sliding sync request is
taking a while. If we have received some data and the second request
takes a while, that is OK.
For the state transition of `Init -> SettingUp` this is handled
correctly, however for `Terminated -> Recovering -> Running` we waited
until the second request returned before hiding the sync spinner. This
meant that if the first request returned quickly the app would show new
data and *then* the sync spinner would show (if the second request took
time).
This situation occurs frequently with the new SSS API, where if all the
new data was returned in the first sync then the second sync would
block waiting for new data, triggering the sync spinner.
This patch changes the `SlidingSync::subscribe_to_room` method to
`subscribe_to_rooms`. Note the plural form. It's now mandatory to
subscribe to a set of rooms. The idea is to avoid calling this method
repeatedly. Why? Because each time the method is called, it sends a
`SlidingSyncInternalMessage` of kind `SyncLoopSkipOverCurrentIteration`,
i.e. it cancels the in-flight sliding sync request, to start over with
a new one (with the new room subscription). A problem arises when the
async runtime (here, Tokio) is busy: in this case, the internal message
channel can be filled pretty easily because its size is 8. Messages
are not consumed as fast as they are inserted. By changing this API:
subscribing to multiple rooms will result in a single internal message,
instead of one per room.
Consequently, the rest of the patch moves the `subscribe` method of
`room_list_service::Room` to `room_list_service::RoomListService`
because it now concerns multiple rooms instead of a single one.
Our CI used to be quite slow and used up a lot of CI time, so as an
optimization we disabled CI for draft PRs.
This is a bit annoying since people want to open draft PRs to check if
CI passes, but without triggering any review requests.
Since our CI is nowadays a bit more efficient let's see if we can enable
it for draft PRs.
This method works the same as `Room::event` but you can provide a custom `RequestConfig` to it.
It's especially useful for the pinned events timeline, since we need a max number of retries and a max number of concurrent requests. With this we can remove some unnecessary complexity.
This way it matches the rest of timelines in the SDK, I reversed it here because I didn't realise most clients just do this reversal of ordering themselves. As they do, they need the same order for this timeline too to be able to reuse their existing logic.
This ensures the cache keeps the events even when the associated `Room` is dropped, which is what we want when using it to cache the pinned events for rooms in the client.
Add `fn Client::pinned_event_cached()` to get a reference to it.
In `matrix.rs` we add methods to interact with the matrix homeserver. And in `machine/mod.rs` we implement the widgetMachine cases for handling (checking capabilities and using the matrixDriver) delayed events.
Add `PinnedEventsLoader` to encapsulate this logic, being able to provide a max number of events to load and how many can be loaded at the same time. Also implement an event cache for it.
Add `PinnedEventsRoom` trait to use it in the same way as `PaginableRoom`, only for pinned events.
The code used to only add new targets to rooms
but never remove the ones that are not in the event anymore.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch ensures that we retain the master key for a given UserIdentityData object, even when a new and different identity arrives via the `/keys/query` endpoint. This concept, called pinning, is similar to certificate pinning in web browsers.
Retaining the master key allows us to detect changes and notify the user accordingly.
This tiny change allows one to easily name the return type of
`EventTimelineItem::reactions()` such that you can use it in a function
signature. Same goes for the `ReactionInfo` type.
I think this was likely just a small oversight in recent changes to the
reactions API, so hopefully it's not controversial.
Without this, it's impossible to write a function that uses
`ReactionsByKeyBySender` or `ReactionInfo` in the signature.
Signed-off-by: Kevin Boos <kevinaboos@gmail.com>
- disable backups and recovery before requesting the reset handle
- attempt device key upload
- re-enable backups both when UIAA is required and when not
This means we have all the information inside SenderData to populate
VerificationStatus and DeviceId for EncryptionInfo, so we can share the
code between SenderDataFinder and get_verification_state.
This makes it impossible to represent states like "there's a local *and*
a remote echo for the same sender for a given reaction", or multiple
reactions from the same sender to the same event, and so on.
Remove `Result` where it is not needed, and switch to `CryptoStoreError`
instead of `OlmError` where possible. Soon, this will allow us to call
some of these methods from places that don't know about `OlmError`.
These calls are equivalent because the old code called
`self.get_user_devices` with a `timeout` of `None`, which meant the call
to `wait_if_user_pending` inside was a no-op.
As it says on the tin. Needed the functions but they were missing. They are analogous to the GlobalAccountData setters.
Signed-off-by: Benjamin Kampmann <ben@acter.global>
The sliding sync proxy has a bug: despite the presence of
`m.room.create` in `bump_event_types`, an invite with an `m.room.create`
event will not have a `timestamp`. Thus, such a room cannot be sorted
reliably.
This patch fixes this problem with a terrible hack, where it tries to
find an `origin_server_ts` value from within the `invite_state` state
events.
Please read the comment to learn more.
The `UserIdentity::is_verified()` method in the matrix-sdk-crypto crate
before version 0.7.2 doesn't take into account the verification status
of the user's own identity while performing the check and may as a result
return a value contrary to what is implied by its name and documentation.
This patch fixes this and adds a regression test.
The method itself is not used internally and as such has not a larger
impact.
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
Signed-off-by: Damir Jelić <poljar@termina.org.uk>
The `RoomList` provides a `Stream<Item = Vec<VectorDiff<Room>>>`.
This `Stream` receives updates from 2 sources: `RoomList::entries`,
and `Receiver<RoomInfoNotableUpdate>`. When a `RoomInfo` is
updated, a notable update is emitted and broadcasted. The
`RoomList` was filtering these notable updates by _reasons_ (namely
`RoomInfoNotableUpdateReasons`).
This is great and it's a good idea since we can filter which
`RoomInfoNotableUpdate` will trigger a `RoomList` update. However, too
many _reasons_ were hidden/implicit, and it creates several regressions
because (i) these _reasons_ were implicit, (ii) since the business rules
are not defined, there is no tests for that (not in this SDK, not in
apps like ElementX). It means we discover missing _reasons_ bug after
bug. It's not pleasant.
The reality is: we are in the middle of big changes, mostly with room
list client-side sorting and simplified sliding sync. We want to relax
a little bit. This patch then disable the feature _filter updates by
reasons_. The `RoomList` will update to all `RoomInfoNotableUpdate` for
the moment. We will get back to this optimisation later.
The `UserIdentity::is_verified()` method in the matrix-sdk-crypto crate
before version 0.7.2 doesn't take into account the verification status
of the user's own identity while performing the check and may as a result
return a value contrary to what is implied by its name and documentation.
This patch fixes this and adds a regression test.
The method itself is not used internally and as such has not a larger
impact.
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
Signed-off-by: Damir Jelić <poljar@termina.org.uk>
Simplified sliding sync no longer has `sort` or `bump_event_types`
because they are static values on the implementation/server side. This
patch removes them here.
This patch renames “recency timestamp” to “recency stamp”. It prepares
the fact that simplified sliding sync has a `bump_stamp` instead of a
`timestamp`. The notion of _timestamp_ must be removed.
This patch extracts most of `SlidingSync::sync_once` into a
method named `SlidingSync::send_sync_request`. The name mimics
the `SlidingSync::generate_sync_request` similar method: first we
_generate_, then we _send_.
The `SlidingSync::send_sync_request` is generic over the `Request` and
`::sync_once` passes the correct type depending of whether Simplified
MSC3575 is enabled.
This patch is the first over two patches to change the support
of Simplified MSC3575 from a compiler feature flag to a runtime
configuration. This configuration is held by the `Client`.
By default, it's turned off inside `matrix-sdk-ffi` and
`matrix-sdk-integration-testing`, otherwise it's turned on.
Currently on Element X if you receive a sticker in a room, the room list
will show the room as updated but it will show the latest event that is
not a sticker. This change fixes that.
Signed-off-by:
Marco Antonio Alvarez <surakin@gmail.com>
---------
Signed-off-by: Marco Antonio Alvarez <surakin@gmail.com>
Signed-off-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Benjamin Bouvier <public@benj.me>
New feature from Matrix 1.11.
- [x] Public API changes documented in changelogs (optional)
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
There were some leftovers from the rename of the ReadOnlyDevice and
identity structs. The store still referenced them.
This gets rid of all the mentions and improves the documentation of the
store methods for devices and identities.
This reduces the work we do to calculate changed devices etc. when DEBUG
logging is not enabled, but more importantly (to me) it makes clear
that this code is only used for logging.
It is possible to remove the m.call capability because we now have
merged and released a version that does not request it anymore on
call.element.io
---------
Signed-off-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Benjamin Bouvier <public@benj.me>
This patch rewrites the `test_delayed_decryption_latest_event` test a
little bit. It does exactly the same things, but in a simpler way: it
removes multiple `sleep` and remove 2 sliding sync loops.
First off, the `SyncService` already starts the `RoomListService and the
`EncryptionSync` service. Both of them have their own sliding sync
loop. The test doesn't need other sliding sync loops in their own tasks,
this is not necessary at all: it's just pretty confusing and doesn't
reflect the reality, i.e. how these API are supposed to be used.
Second, it also tests the room for Bob is seen as encrypted.
Third, the `VectorDiff::Reset` is tested before the event from Bob
is sent. It's not only for clarity: it makes the test more robust for
future modifications.
Fourth, instead of waiting with a `sleep` for the event from Bob to be
received by Alice, we instead wait on the room list's stream of Alice to
receive an update. It's more robust this way and reflects the real usage
of this API. It also helps to remove an intermediate `assert_pending!`
that is no longer necessary because we are waiting on the stream just
after.
Finally, just like for the previous modification, this patch removes
another `sleep` for the to-device event from Bob to be received by
Alice, and instead wait on the room list's stream to receive an update.
It's again more robust and reflects the real usage of this API. Plus, it
makes the last `assert_pending!` macro to not be flaky.
This patch fixes a bug where rooms stored in the sliding sync cache
aren't restored by the `SlidingSyncBuilder`.
This patch also removes `SlidingSyncBuilder::rooms` fields which was
used but never modified. It's dead code.
Again, a transaction id received from the remote flow doesn't mean it
corresponds to a local echo sent *this particular session*, so no need
to warn about it.
This log can happen when an event is received, has a transaction id (in
the data received from sync), and doesn't have a corresponding timeline
item (be it local or remote). There's no reason to warn about this,
because this would happen in most cases, for new incoming events coming
from sync, and this pollutes the logs of rageshakes.
This patch removes the `test_room_info_notable_update_deduplication`
test. First off, it's flaky because sometimes Synapse lags, or sends
another events, which makes the test to fail. Second, the same feature
is tested inside the `matrix_sdk_ui::room_list_service` test suite,
with `test_room_sorting` and `test_room_latest_event`, and inside the
`matrix_sdk_base::sliding_sync` test suite, with a better granularity.
And lastly, this test doesn't test what it says: there is no room info
notable update deduplication whatsoever. I personally don't believe it
has ever existed. This test isn't necessary.
ReadOnlyDevice is not particularly useful as a description of why we
have two device types. This commit renames it into DeviceData, as this
struct is used to hold the device keys and additional local device data.
I'm not quite sure why it took me so long to come up with a better name.
Please forgive me past readers.
The test database was created using a slightly modified `oidc-cli`
example, to turn of the database encryption, on commit
d6dca91df86413b0cbf193a4be191835dd81862e
Since it's only used for remote events, and a local echo couldn't figure
that out anyways (since it's not sent yet, and that information makes
sense after sending).
This is needed to prevent the race condition where the invite request finished, the `/sync` one didn't fetch the new membership event yet and we send a message in the room. This message won't be encrypted for the newly invited user and will result in an UTD.
I added a new integration test and I can confirm this [complement-crypto test](https://github.com/matrix-org/complement-crypto/pull/98) now passes instead of being skipped.
Fixes#3622.
---
* fix(sdk): force room member reload after inviting a user
This is needed to prevent the race condition where the invite request finished, the `/sync` one didn't fetch the new membership event yet and we send a message in the room. This message won't be encrypted for the newly invited user and will result in an UTD.
* Use `room.mark_members_missing()` instead, add integration test
* Abort syncing before the test ends
* Resolve nit: else after a return
* Fix race condition where bob may try to join the room before the invite is received
* Remove double sync
This patch removes everything related to the computation of `ops`
from a sliding sync response. With the recent `RoomList`'s client-side
sorting project, we no longer need to handle these `ops`. Moreover, the
simplified sliding sync specification that is coming removes the `ops`.
A `SlidingSyncList` was containing a `rooms` field. It's removed by
this patch. Consequently, all the `SlidingSyncList::room_list` and
`::room_list_stream` methods are also removed.
A `FrozenSlidingSyncList` was containing the `FrozenSlidingSyncRoom`.
This patch moves the `FrozenSlidingSyncRoom`s inside
`FrozenSlidingSync`. Why is it still correct? We only want to keep the
`SlidingSyncRoom::timeline_queue` in the cache for the moment (until
the `EventCache` has a persistent storage). Since a `SlidingSyncList`
no longer holds any information about the rooms, and since `SlidingSync`
itself has all the `SlidingSyncRoom`, this move is natural and still
valid.
Bye bye all this code :'-).
The only thing is that our client builder allows setting only the server
versions, so this means the new field has to contain two `Option`al
fields. This causes a bit of churn, but isn't too bad in the end.
I've been debugging a cause of flakey complement-crypto tests for
about a month now. I was pretty convinced it was deadlocking
somewhere in the memory store `save_changes` code. With additional
logging, it's now clear that the there is an ABBA style deadlock
when `save_changes` is called at the same time as `get_state_events`.
I've also adjusted code for `get_user_ids` as it has a very similar
pattern and also acquires locks in reverse order to `save_changes`,
so is potentially vulnerable to this.
This patch avoids to emit a
`RoomInfoNotableUpdateReasons::RECENCY_TIMESTAMP` for rooms that are new.
Otherwise the entries in `matrix_sdk_ui::room_list_service::RoomList`
receive a `VectorDiff` because a new room is inserted, and then a
`VectorDiff` because the recency timestamp is updated. The second
`VectorDiff` is useless in this case.
First off, this patch removes the
`RoomInfoNotableUpdate::trigger_room_list_update` field. It is replaced
by a `reasons: RoomInfoNotableUpdateReasons` 8-bit unsigned integer. It
addresses the following issues:
1. When a subscriber receives a `RoomInfoNotableUpdate`, they have no
idea what has triggered this update.
2. In
`matrix_sdk_base::sliding_sync::BaseClient::process_sliding_sync_e2ee`,
we were triggering an update even if the latest event wasn't
modified: it is a false-positive, it was a bug and a waste of
resources. Now it's more refined, see the why below.
Second, this patch removes the second `trigger_room_list_update`
argument of `matrix_sdk_base::BaseClient::apply_changes`. This method
now knows where to find the reasons for the room info notable updates,
see next point.
Third, this patch adds a new
`matrix_sdk::StateChanges::room_info_notable_updates` field which is a
B-tree map between an `OwnedRoomId` and a
`RoomInfoNotableUpdateReasons`. The idea is that all places that receive
a `StateChanges` can also create a room info notable update with a
specific reason. This is a finer grained mechanism, and it avoids to
pass new arguments everywhere. It's cleaner.
Finally, it's easier than ever to add a new reason and to propagate it
to subscribers.
The patch renames `RoomInfoUpdate` to `RoomInfoNotableUpdate`.
The functions, methods or variables whose names start with
`roominfo_update(.*)`` are renamed `room_info_notable_update$1`.
* ffi: expose methods for SSO login
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
* Update bindings/matrix-sdk-ffi/Cargo.toml
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
* Refactor code to use a separate object to complete the SSO login
* Remove superfluous .workspace
* Remove superfluous field name
* Fix formatting with nightly toolchain
* Fix clippy errors using nightly toolchain
* Move SSO methods over into Client as AuthenticationService will go away very soon
* Add login tests
* Assign tokio runtime and url getter
* Reformat
* Relocate parts of the code as per review comments
* Add url to debugging representation of SsoHandler
* Add example for login_with_sso_callback
* Use unwrap_or_default to avoid creating empty string
* Remove leftover dependencies
---------
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
When a request fails because of the exponential backoff, it won't be
re-logged again. It would be useful, for the purposes of the send queue
notably, to see when a request is re-attempted.
Synapse returns a bare `{ "membership": "leave" }` as the content of a
room membership event (for leave membership changes and likely others).
In this case, it'd still be nice to have some kind of display
name/avatar URL to show in UIs; it's possible to reuse information from
the previous member event, if available.
Add a new `max_concurrent_requests` parameter in the `RequestConfig` limits the number of http(s) requests the internal sdk client issues concurrently (if > 0). The default behavior is the same as before: there is no limit on concurrent requests issued.
This is especially useful for resource constrained platforms (e.g. mobile platforms), and if your pattern might lead to issuing many requests at the same time (like downloading and caching all avatars at startup).
- [x] Public API changes documented in changelogs (optional)
Signed-off-by: Benjamin Kampmann <ben.kampmann@gmail.com>
It turns out this will cause a network request if the encryption info hasn't been loaded before, which is the case for opening a client in offline mode. It will slow down displaying the room list or loading the room info in general.
Turns out legacy unencrypted objects can take many forms, and we need to be
tolerant of them.
Also expose `deserialize_legacy_value` as a separate function, because we're
going to need to special-case it.
This patch revisits the need to trigger a room list update for
all changes of `RoomInfo`. For the moment, it reduces the scope to
`recency_timestamp` update.
This patch comes with a test to ensure things work as expected.
... and make `deserialize_value` handle both the old and new formats.
`maybe_encrypt_value` uses a much more efficient representation, so let's
migrate to that.
It's currently possible for integ test results to leak from one test run to the
next (for example, the indexeddb stores hang around in the browser), causing
bad test results.
Extend the test setup routine to clear out the store before the test starts.
This patch removes the `LatestEvent::cached_event_origin_ts`.
It's no longer necessary to cache this value as the
`matrix_sdk_ui::room_list_service::sorter::recency` sorter no longer
uses it.
This patch adds a new field in `RoomInfo`: `recency_timestamp:
Option<MilliSecondsSinceUnixEpoch>>`. Its value comes from a Sliding
Sync Room response, that's why all this API is behind `cfg(feature =
"experimental-sliding-sync")`.
This allows seeing the events directly from the room event cache. I'm
hoping this will give us some interesting insights about duplicates,
among other things.
Most tests would randomize the username when creating a
`TestClientBuilder`; make it the default, since it's a sensible choice,
and avoids interference between different tests / test runs.
A single test required an actual non-randomized username, so a specific
way to opt out from this new default behavior has been introduced.
* Use `IndexeddbSerializer` more widely in test code
reuse `IndexeddbSerializer::maybe_encrypt_value` instead of re-inventing it.
* Rewrite `StoreCipher::decrypt_value_base64_typed`
Instead of un-base64-ing and calling `decrypt_value_typed` (which deserializes
the result`), call `decrypt_value_base64_data` (which un-base64s before
decrypting but does not deserialize the result), then deserialize.
This makes it more symmetrical with `encrypt_value_base64_typed`, and helps me
get rid of `decrypt_value_typed` (which is barely used.)
* Fix docs on `StoreCipher::encrypt_value_base64_typed`
looks like they got C&Ped from `encrypt_value_typed`.
* Inline `StoreCipher::{encrypt,decrypt}_value_typed`
Each of these are quite simple, are only used in two places, and their
existence melts my brain.
* Rewrite `IndexeddbSerializer::maybe_{encrypt,decrypt}_value`
... to use `en/decrypt_value_base64_data` instead of
`en/decrypt_value_base64_typed`.
We have to have the de/serialization code for the unencrypted case anyway, so
using the higher-level method isn't helping us much.
* Remove unused `StoreCipher::{en,de}crypt_value_base64_typed`
Outside of tests, these things are totally unused.
This patch removes the `RoomListService::rooms` cache, since now a
`Room` is pretty cheap to build.
This cache was also used to keep the `Timeline` alive, but it's now
recommended that the consumer of the `Room` keeps its own clone of the
`Timeline` somewhere. We may introduce a cache inside `RoomListService`
for the `Timeline` later.
This patch rewrites `merge_stream_and_receiver` to switch the order
of `roominfo_update_recv` and `raw_stream`. The idea is to give the
priority to `raw_stream` since it will necessarily trigger the room
items recomputation.
This patch also remove the `for` loop with `Iterator::enumerate`, to
simply use `Iterator::position`: it's more compact and it removes a
`break` (it makes the code simpler to understand).
Finally, this patch renames `merged_stream` into `merged_streams`.
Complement uses the FFI `RoomList` API. Since the patch set modifies
this API, Complement is broken. We disable it and will re-enable it once
we have updated Complement.
This patch adapts the `RoomList` FFI API to the recent changes to
suport a `Stream<Item = RoomListItem>` instead of a `Stream<Item =
RoomListEntry>`. Behind the scene, it supports client side sorting for
the rooms but this is transparent for this API.
This patch also removes the `RoomListInput` enum as no input is
supporter anymore.
The `entries` method no long returns a `RoomListEntriesResult` but
directly a `TaskHandle`. The given listener will receive the initial
entries as a `VectorDiff::Append`, which first is simpler but also fixe
a potential race condition bug.
This patch adds a new `cached_event_origin_server_ts` field on
`LatestEvent`, which is a copy of the `origin_server_ts` of the inner
`SyncTimelineEvent`.
This patch removes the `visible_rooms` sliding sync list from
`RoomListService`. As we are taking the path of doing client-side
sorting, the ordering of the server-side will most likely always
mismatch the ordering of the client-side, thus using `visible_rooms`
with room indices make no sense (indices from server-side won't map
indices on the client-side, so room ranges from client-side won't map
what the server knows).
We used to use `visible_rooms` to “preload” the timeline of rooms in
the user app viewport, with a `timeline_limit` of 20. This should be
replaced by room subscriptions starting from now. For the moment, the
user of `RoomListService` is responsible to do that manually. Maybe
`RoomListService` will handle that automatically in the future.
There were two disconnected sources of truth for the state of event to
be sent:
- it can or cannot be in the in-memory `being_sent` map
- it can or cannot be in the database
Unfortunately, this led to subtle race conditions when it comes to
editing/aborting. The following sequence of operations was possible:
- try to send an event: a local echo is added to storage, but it's not
marked as being sent yet
- the task wakes up, finds the local echo in the storage,...
- try to edit/abort the event: the event is not marked as being sent
yet, so we think we can edit/abort it
- ... having found the local echo, it is marked as being sent.
This would result in the event misleadlingly not being aborted/edited,
while it should have been.
Now, there's already a lock on the `being_sent` map, so we can hold onto
it while we're touching storage, making sure that there aren't two
callers trying to manipulate storage *and* `being_sent` at the same
time.
This is pretty tricky to test properly, since this requires super
precise timing control over the state store, so there's no test for
this. I can confirm this avoids some weirdness I observed with
`multiverse` though.
Using `SendHandle::abort()` after the event has been sent would look
like a successful abort of the event, while it's not the case; this
fixes this by having the state store backends return whether they've
touched an entry in the database.
It could be that the last event in a room's send queue has been marked
as wedged. In that case, the task will sleep until it's notified again.
If the event is being edited, then nothing would wake up the task; a
manual wakeup might be required in that case.
The new integration test shows the issue; the last `assert_update` would
fail with a timeout before this patch.
Commit d41af396c implemented MSC4147, which puts the device keys into a
Olm message. It failed to adhere to the unstable prefix proposed in the
MSC:
> Until this MSC is accepted, the new property should be named
> org.matrix.msc4147.device_keys.
This patch fixes this.
This patch switches the way we update the recovery state upon changes in
the backup state. Previously two places updated the recovery state after
the backup state changed:
1. A method living in the recovery subsystem that the backup
subsystem itself calls.
2. An event handler which is called when we receive a m.secret.send
event.
The first method is a hack because it introduces a circular dependency
between the recovery and backup subsystems.
More importantly, the second method can miss updates, because the backup
subsystem has a similar event handler which then processes the secret we
received and if the secret was a backup recovery key, enables backups.
Depending on the order these event handlers are called, the recovery
subsystem might update the recovery state before the secret has been
handled.
The backup subsystem provides an async stream which broadcasts updates
to the backup state, letting the recovery subsystem listen to this
stream and update its state if we notice such updates fixes both
problems we listed above. The method in the first bullet point was
completely removed, the event handler is kept for other secret types but
we don't rely on it for the backup state anymore.
Where a string is clearly documented as a room ID, event ID or mxc URI,
use OwnedRoomId, OwnedEventId and OwnedMxcURI, respectively.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
We tend to use fixup commits quite a bit, and in the heat of the moment
we sometimes forget to squash them before the final merge.
This should prevent us from doing so.
This will still disable the room's send queue, but the embedder may then
decide whether to re-enable the queue or not, based on network
connectivity. Ideally, we'd implement some retry mechanism here too, but
since we're at a different layer than the HTTP one, we can't get that
"for free", so let the embedder decide what to do here.
This patch is quite big… `RoomList::entries*` now returns `Room`s
instead of `RoomListEntry`s. This patch consequently updates all the
filters to manipulate `Room` instead of `RoomListEntry`. No more
`Client` is needed in the filters.
This patch also disables the `RoomList` integration test suite in order
to keep this patch “small”.
For each recipient device, we keep an "Olm wedging index" that indicates (approximately) how many times they tried to unwedge the Olm session. When we share a Megolm session, we store the Olm wedging index. This allows us to tell whether the Olm session was unwedged since we shared the Megolm session, so that we know if we should re-share it.
We detect an attempt to unwedge the Olm session by checking if the Olm message that we decrypted is from a brand new Olm session. This is not entirely accurate, since this could happen, for example, if Alice and Bob create Olm sessions at the same time. This may result in some Megolm sessions being re-shared unnecessarily, but should not make a huge difference.
It also resets the wedged state, so that the queue will retry to send
this event later. This will show useful in the following case: when an
event is too big, we can now retry to send it, even if it was blocked,
by splitting the event instead of copy/abort/recreate it.
It turns out that so as to be able to read the room ids, they need to be
*values*, not only *keys* (since keys are one-way hashed). This means we
need to duplicate the room_id field in indexeddb/sqlite, so each entry
contains both the room_id as a key (for queries) and as a value (to
return it).
Since there's no meaningful migration we can apply, the way to go is to
drop the pending events table and recreate it from the ground up. It is
assumed that no one has used the store on indexeddb; otherwise the
workaround would be to drop and recreate it.
A few were missing in the public API like SendEventError and RedactEventError and their dependencies.
This uses a wildcard because it should be rare to not want to expose an error type.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
A user of the library needs to add this crate as a dependency just to be able to match on `VectorDiff`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
The issue here seems to be that
the `panic!` and `unreachable!()` macros used in the tests return `!`.
In the future, `!` will not fallback to `()`, which is what `dependency_on_unit_never_type_fallback` checks.
`add_event_handler` expects a function that returns an `EventHandlerResult`, but it is only implemented for `()`, not for `!`.
A solution could be to implement that trait for `!` but it is an unstable feature right now.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It is only needed with the experimental-oidc and e2e-encryption features.
The former is less likely to be enabled so use it to enable the dependency.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch set does two things:
1. Extracted the logic to collect the devices that should receive a room key.
2. Introduce a new CollectStrategy enum which defines which rules are
used to collect recipient devices for a room key. Currently only the
existing rules have beenmoved under this enum.
This can happen if there's a load-balancer or any modification of the
response by a reverse proxy (e.g. rewrite 5XX errors into 429, to not
let a reverse proxy mark the upstream server as being down, as
Cloudflare seems to do).
As a result, such requests will be retried in multiple places, including
when sending something with the send queue. Also, the send queue will
mark these errors as recoverable instead of unrecoverable.
No test, because the change really is trivial and a regression test
didn't seem worth it, for once.
RoomInfo::handle_state_event(...) will check this condition so we don't have to later ask the HS whether the room is encrypted or not through room::is_encrypted().
Also, as we need some way to get this info in the room list in our clients, two ways of doing this were added the FFI crate, one through RoomInfo and another one through RoomListItem.
`RoomInfo::handle_state_event` will check this condition so we don't have to later ask the HS whether the room is encrypted or not through `room::is_encrypted()`.
This adds support to input your recovery key to the OIDC example which
will allow the OIDC example client to be verified and have access to all
the secrets (cross-signing keys and the backup recovery key).
Not particularly useful right now, but once the OIDC example is able to
log in other devices via a QR code it becomes necessary to have access
to all the secrets.
The workspace root enables some features which are required to compile
the benchmarks, but if you decide to just compile the benchmarks these
features won't be enabled since they aren't specified in the Cargo.toml
file of the benchmarks.
Let's define all the required features so compilation works in both
cases.
Fixes#3538
The current implementation for send_reply and edit only work with timeline items that have already been paginated.
However given the fact that by restoring drafts, we may restore a reply to an event for timeline where such event has not been paginated, sending such reply would fail (same for the edit event).
So I reworked a bit the code here to use. only the event id, and reuse the existing timeline if available, otherwise we can fetch the event and synthethise the content and still be able to successfully send the event.
This is the third part of the breakdown of the following PR: https://github.com/matrix-org/matrix-rust-sdk/pull/3439
Change this so that it fires off a task for each UTD event, rather than each
megolm session. This is a step towards considering the message index when
deciding whether to carry on with the download.
Not doing this leads to an invalid ordering of events, as shown in the
test: if we increase the timeline limit of a room using sliding sync,
we'll receive a duplicate event, and if we ignore it, it'll be in an
invalid position. The solution is to keep the most recent event (and
remove the old one from event_meta).
This PR makes 2 changes:
- Updates the storage of room heroes to be a single array containing the user's complete profile.
- Exposes these to the FFI so that client apps can use these for avatar colours/clusters.
Closes#2702 (again, now with avatars 🖼️)
---
* rooms: Store heroes as a complete user profile.
* ffi: Expose room heroes on Room and RoomInfo.
* chore: Remove TODO comment.
* Update crates/matrix-sdk-base/src/rooms/normal.rs
Signed-off-by: Benjamin Bouvier <public@benj.me>
---------
Signed-off-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Benjamin Bouvier <public@benj.me>
retry kind: make `characterize_retry_kind` a method of `HttpError`
---
retry kind: mark all network errors as transient
This should cause more backoff in general, if the client is disconnected
of the grid, or the remote server is, which is good behavior to have in
general.
---
http error: introduce another rustfmt-formated impl block for HttpError
The previous `impl` block was marked as skipping rustfmt, which led to
weird formatting behavior.
Changes are formatting only.
* sdk: Integ tests: factor out some helper methods
A few common methods for logic shared between the tests. This serves two
purposes:
* It reduces duplication, this making it easier to maintain the tests by
reducing the number of places that we have to change things.
* It makes the tests easier to read. By factoring out discrete steps, it's
much easier to get an overview of what a test is doing than when it's all in
one big function.
* sdk: Integ tests: timeout if nothing happens
If the test is going to fail, let's have it do so properly rather than
mysteriously getting stuck.
This patch creates an `ObservableMap` for `wasm32-unknown-unknown` which
simply wraps a `BTreeMap`, and without the `stream` method. Indeed, the
first implementation uses `eyeball_im::ObservableVector` which requires
`Send` and `Sync` on its values, which cannot compile to Wasm.
This patch implements `Client::rooms_stream` by forwarding the
result of `matrix_sdk_base::Client::rooms_stream`, and mapping the
`matrix_sdk_base::Room` to `matrix_sdk::Room`.
Running `cargo test -p matrix-sdk-base --features e2e-encryption`
makes the code to fail to compile because `crate::latest_event` isn't
defined. And indeed, it must be defined if `experimental-sliding-sync`
is enabled, but also if `e2e-encryption` is enabled.
This patch updates `Store::rooms` from a
`Arc<StdRwLock<BTreeMap<OwnedRoomId, Room>>>` to a
`Arc<StdRwLock<Rooms>>` where `Rooms` is a new type that mimics a
`BTreeMap` but that is observable. It uses an `ObservableVector`
for saving us the costs of writing a new `ObservableMap` type in
`eyeball-im`. It would have too much implications that are clearly
not necessary. The major one being that an `ObservableMap` must emit
`MapDiff`, but we expect `VectorDiff` everywhere in the SDK where rooms
are observable. It would break too many API and too many projects.
The benchmark is coming, but here are the results (for 10'000 rooms,
extreme case):
* `get_rooms` and `get_rooms_filtered` are twice faster (in practise, it
means 650µs is saved per call),
* `get_room` and `get_or_create_room` are 10% slower (in practise, it
means 8-10ns is lost per call).
Overall, I believe these results are acceptable, and even an improvement
for the first one.
This patch removes the useless `SlidingSyncList::get_room_id` method as
I don't see how it can be useful for anybody. It's mostly dead public
code, let's clean that up.
This might be controversial, but I do strongly prefer explicit over
implicit, in this case: it helps looking at the use cases, when using
the LSP's goto_references().
The HttpError variant was misplaced, as it was always used when the
`user_id()` is missing, which is causing `Error::AuthenticationRequired`
errors everywhere else in the code base. This patch streamlines usage of
`Error::AuthenticationRequired`, and gets rid of the `HttpError`
variant.
This patch renames `Client::get_rooms`, `::get_rooms_filtered` and
`::get_room` to respectively `::rooms`, `::rooms_filtered` and `::room`.
This `get_` prefix isn't really Rust idiomatic.
This patch renames `Store::get_rooms`, `::get_rooms_filtered` and
`::get_room` to respectively `::rooms`, `::rooms_filtered` and `::room`.
This `get_` prefix isn't really Rust idiomatic.
`Store::get_rooms` worked as follows: For each room ID, call
* Take the read lock for `rooms`,
* For each entry in `rooms`, take the room ID (the key), then call `Store::get_room`, which…
* Take the read lock for `rooms`,
* Based on the room ID (the key), read the room (the value) from `rooms`.
So calling `get_rooms` calls `get_room` for each room, which takes the lock every time.
This patch modifies that by fetching the values (the rooms) directly
from `rooms`, without calling `get_room`.
In my benchmark, it took 1.2ms to read 10'000 rooms. Now it takes 542µs.
Performance time has improved by -55.8%.
This patch replaces the `RwLock` by a `Mutex` in
`RoomListService::rooms` because:
1. it removes a race condition,
2. `RwLock` was used because the lock could have been taken for a long
time due to the previous `.await` point. It's no longer the case, so we
can blindly use a `Mutex` here.
This patch makes `RoomListService::room` synchronous. It no longer reads
a `SlidingSyncRoom` from `SlidingSync`, then it not needs to be async
anymore. This patch replaces the `RwLock` of `RoomListService::rooms`
from `tokio::sync` to `std::sync`.
The patch updates all calls to `RoomListService::room` to remove the
`.await` point.
This patch updates `room_list_service::Room::new` to take a `&Client`
and a `&RoomId` instead of a `SlidingSyncRoom`. The `SlidingSyncRoom` is
only used in `Room::default_room_timeline_builder` and is fetched there
from the `SlidingSync` instance lazily. It confines the
`SlidingSyncRoom` to one single method for `Room` now.
Using the resolved homeserver URL causes problems if we need to inspect
the well-known configuration of the homeserver, for example, if the
server name is matrix.org, but the homeserver URL is server.matrix.org,
the well-known might be only available for the former.
This is why we also need to receive the former, i.e. the server name in
the QR code data.
This patch removes `RoomInfo::latest_event`. To get the latest event,
one has to use `RoomListItem::latest_event` because it supports
local events and remote events. It was supposed to be the case of
`Room::room_info` too, but only when the method was called: Once the
`RoomInfo` was created, the latest event inside `RoomInfo`
was static, not dynamic. Also, this code wasn't tested
contrary to `RoomListItem::latest_event` which uses
`matrix_sdk_ui::room_list_service::Room::latest_event` which is itself
tested.
This patch changes the behaviour of the `Timeline` when a duplicated
event is received. Prior to this patch, the old event was removed, and
the one was added. With this patch, the old event is kept, and the new
one is skipped.
This is important for https://github.com/matrix-org/matrix-rust-sdk/pull/3512
where events are mapped to the timeline item indices. When an event is
removed, it becomes difficult to keep the mapping correct.
This patch also adds duplication detection for pagination (with
`TimelineItemPosition::Start`).
This patch removes the `matrix_sdk_ui::timeline::SlidingSyncRoomExt`
trait as it's no longer necessary since `room_list::Room::latest_event`
no longer uses `SlidingSyncRoom` to fetch the latest event.
This patch updates `matrix_sdk_ui::room_list::Room::latest_event`
to fetch the latest event from `matrix_sdk::Room` instead of
`matrix_sdk::sliding_sync::SlidingSyncRoom`. It removes one dependency
to `SlidingSyncRoom` and it simplifies the code.
This avoids a race condition where the caller hasn't set up the initial
items or the listener, and the listener is called *before* the initial
items have been used.
second part of the #3439 breakdown
The context for this API, is for the composer preview an reply without the need of it being actively in the timeline.
This PR is the first piece of the breakdown of the following PR: https://github.com/matrix-org/matrix-rust-sdk/pull/3439 where only the core functionalities of the feature are implemented, without addressing the issue of editing and replying to events that have not yet been paginated.
The test looks at updates of `RoomInfo`s, but these depends on external
factors like the server sending them in one part or multiple ones.
Instead of trying to figure out which partial updates the server sent,
wait for the stream of `RoomInfo`s to stabilize by trying to get the
latest item from the stream, then wait up to N seconds for another item
to show up, and continue as long as items come in.
This should allow us to get rid of some code that was required to
prevent flakey updates.
The previous code would use `ACTIVE` which means "either joined or
invited" members, but the code thereafter considered this to be the
number of joined members.
Also replaced a call to `self.members()` (which does a lot of work under
the hood) with a call to `self.joined_user_ids()`, since we only
retrieve the `.len()` of the resulting vector.
- Change incorrect "key sharing" references to "key forwarding".
- Explain that this is a feature that needs to be enabled.
- Regenerate the key forwarding algorithm diagram.
- Provide a spec link and mention alternative names.
Use a Bloom filter to keep track of which events we have already reported to the parent UTD hook.
We load the data from database on startup, and flush it out immediately on every update.
This patch renames `TimelineEventHandler::add` to `add_item`.
This patch also removes the `should_add` argument. The `add_item`
is called conditionally everytime. I believe this is much cleaner.
Otherwise the method should have been called `maybe_add_item` with a
return type or something that indicates whether the item is added. This
patch makes it clear and remove one possible state in `add_item`.
This patch updates `TimelineEventHandler` to re-use the public API and
avoid using `TimelineInnerMeta::next_internal_id`. The consequence is
that `next_internal_id` can now be private instead of public. It's
better to have isolated API in this code.
This patch removes a useless clone of `TimelineInner::items`. This clone
was technically cheap because it's a `Vector` behind the scene, which is
cheap to clone, but still, it's not necessary at all to clone it.
Because of the task cancellation that can happen at any place in the
code base, it's really hard to predict in which situation a
day-divider-adjuster should have run or not, so just demote the assert
to an error. The intent is that, if we see errors with day dividers in
the future, they'll be reported along rageshakes and we'll notice this
in the logs.
Using async when not required will increase compile times, and propagate async-ness to the callers, transitively.
See also the [lint description](https://rust-lang.github.io/rust-clippy/master/#/unused_async).
Since we only had a few false positives, I've enabled it by default.
Also reunify two methods that did the same thing, with slightly
different semantics, and test the one that wasn't tested at all.
Note that `is_editable()` was already exposed to the FFI and used in EX
apps.
It was used after a previous local echo couldn't be sent (i.e. the
sending queue failed to send it). However, it was slightly incorrect to
mark those as cancelled, since those local echoes would still have
corresponding items in the sending queue, and would be retried as soon
as the sending queue was reenabled and could send events.
Instead, this is removed: it means that previously cancelled events
would be in the NotSentYet state, which is correct. (At the limit, we
could even get rid of the SendingFailed variant, since the sending queue
will automatically retry as soon as possible.)
The test relied on the fact that sending an event from a given timeline
is not observable from another timeline. Indeed, it sent a message using
a first timeline object, then constructed a second timeline object and
expected only the remote event to be in there.
Now, the sending queue is shared across all instances of a Room, thus
all instances of a Timeline, and the second timeline can see the local
echo for the message sent by the first timeline.
The "fix" is thus in the test structure itself: when waiting for the
remote echo to be there, check that the timeline item doesn't pertain to
a local echo, i.e. is a remote echo.
Technically, the test already passed before the change in the builder,
because `TimelineEventHandler::handle_event` already filters out local
events on non-live timelines, but it's a waste of resources to even
spawn the local echo listener task in that case, so let's not do it.
By keeping a reference to the FFI Client, we make sure that the SDK
Client is dropped while in a tokio runtime context. This makes it
possible for an `Encryption` (FFI) object to outlive the `Client` (FFI)
object without crashing (because deadpool requires to be in a tokio
runtime context when dropping).
Following https://github.com/matrix-org/matrix-rust-sdk/pull/3473, we
made it so that if there's a base-path but no username, then we'll
create a sqlite database.
Unfortunately, this introduced a bad side-effect: for the temporary
client used during homeserver resolution, this would create a temporary
sqlite database.
The "fix" is to not set the base path for the temporary client, and only
for the other caller of `new_client_builder()`, manually. The long term
fix is to get rid of the `AuthenticationService` so we can test it
properly.
This patch updates Ruma to 75e8829 so that `RoomSummary::heroes` is now
a `Vec<OwnedUserId>` instead of a `Vec<String>`. This patch updates our
code accordingly by removing the parsing of heroes as `OwnedUserId`.
Without this, the configs from `.cargo/config.toml` were not read in CI
tasks, causing false positives when running Clippy on CI (i.e. there
were issues observed when compiling locally that were not found when
compiling remotely).
Not entirely sure why it's needed, because I'm seeing the issues when
I'm using `cargo xtask ci clippy` locally, with nothing changed.
It turns out that the failure came when using the known room path in the
room preview: Alice knows about the room, but for some reason the client
didn't retrieve all the state events from the sliding sync proxy yet.
Before, the sync would be considered stable after 2 seconds. This is too
little, considering that events come from the proxy that listens to
events from synapse. Raising this threshold to 15 seconds should help
getting all the room information from the proxy, and thus get all the
information we expected in the client.
While this mutex is taken, in `oldest_token()` we can get a hold of the
RoomEvent mutex, making it so that the `waited_...` token covers the
critical region of room events.
Unfortunately, in `clear()`, we're taking these two locks in the
opposite order, implying that the room events critical region now
overlaps that of the `waited_...` lock.
The way to break the cycle is to keep the `waited_` token for as short
as possible.
So as to not use sync mutexes across await points, we have to use an
async mutex, BUT it can't be immediately called in a wiremock responder,
so we need to shoe-horn a bit: create a new tokio runtime, which can
only be called from another running thread, etc. It's a bit ugly, but I
couldn't find another mechanism to block the responder from returning a
Response immediately; happy to change that anytime if there's a simpler
way.
A client would require this to know that the sending queue has been
globally disabled, across all the rooms, otherwise they couldn't know
that it needs to be re-enabled later on.
This implements the following features:
- enabling/disabling the sending queue at a client-wide granularity,
- one sending queue per room, that lives until the client is shutting
down,
- retrying sending an event three times, if it failed in the past, with
some exponential backoff to attempt to re-send,
- allowing to cancel sending an event we haven't sent yet.
fixup sdk
This can be equivalently retrieved using:
`get_timeline_event_by_event_id(event_id).content().as_message()?.content()`
As per the commit date, this is used in one place in both EXA and EXI,
so it seems fine to change the caller's call sites.
And this avoids one explicit call site of
`Timeline::item_by_event_id()`.
If an event cannot be decrypted after a grace period, it is reported to the application (and thence Posthog) as a UTD event. Currently, if it is then successfully decrypted, the event is then re-reported as a "late decryption".
This does not match the expected behaviour in Posthog - an event is *either* a UTD, or a late decryption; it makes no sense for it to be both. This PR fixes the problem.
I've attempted to make the commits sensible, but I'm not entirely sure I've succeeded. The tests do pass after each commit, though. The interesting change itself is somewhere in the middle; there is non-functional groundwork before and cleanup afterwards.
---
* ui: Factor out UTD report code to a closure
For now, this doesn't help much, but in future there will be more logic here,
and it helps reduce the repetition between the delay and no-delay cases.
* ui: Convert UtdHookManager::pending_delayed to a HashMap
* ui: Store decryption time in `UtdHookManager::pending_delayed`
This is a step on getting rid of `known_utds`
* ui: Fix re-reporting of late decryptions
This fixes the problem where a message that was previously reported as a UTD,
and was then subsequently successfully decrypted, is then re-reported as a late
decryption. This artificially inflated the UTD metrics.
We do this by checking the `pending_delayed` list in `on_late_decrypt`, instead
of the `known_utds` list. There is some associated reordering of code to get
the locking right.
* ui: Remove unused "utd report time" from `UtdHookManager::known_utds`
* ui: Replace `UtdHookManager::known_utds` with `reported_utds`
Keep a list of the UTDs we've actually reported, rather than the union of those
we've reported together with those we might report in a while.
I find this much easier to reason about.
* Address minor review comments
* Reinstate assertion in UTD hook tests
* Reinstate `known_utds`
To differentiate the SAS state between the party
that sent the verification start and the party that received it.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This patch adds a new argument to the `until` argument closure of
`RoomPagination::run_backwards`: `timeline_has_been_reset`, which
designates when the timeline has been reset.
A test has been updated accordingly.
* chore(sdk): Rename `RoomEventCacheUpdate::UpdateReadMarker`.
This patch renames `RoomEventCacheUpdate::UpdateReadMarker` to
`ReadMarker`. The `Update` prefix is already part of the enum name.
* feat(sdk): Rename `RoomEventCacheUpdate::ReadMarker::event_id` to `move_to`.
This patch renames `RoomEventCacheUpdate::ReadMarker::event_id` to
`ReadMarker::move_to` as I feel like it conveys a better semantics.
* feat(sdk): Extract `RoomEventCacheUpdate::Append::ambiguity_changes`.
This patch extracts `RoomEventCacheUpdate::Append::ambiguity_changes`
into a new variant `RoomEventCacheUpdate::Members { ambiguity_changes }
`.
This patch also creates a new private
`RoomEventCacheInner::send_grouped_updates_for_events` method to ensure
the updates are sent in a particular order.
* feat(sdk): Rename `RoomEventCacheUpdate::Append`.
This patch renames `RoomEventCacheUpdate::Append` to `SyncEvents`. The
field `events` is renamed `timeline`.
This patch also renames some variables to clarify the code and to match
the renamings in `RoomEventCacheUpdate`.
* feat(sdk): Rename `RoomEventCacheUpdate::ReadMarker` and `Members`.
This patch renames `ReadMarker { move_to: … }` to `MoveReaderMarkerTo
{ event_id: … }`.
This patch also renames `Members` to `UpdateMembers`.
Finally, this patch renames some other variables to avoid clashes with
terminology in `matrix_sdk_ui`.
* feat(sdk): Split `RoomEventCacheUpdate::SyncEvents`.
This patch splits `RoomEventCacheUpdate::SyncEvents` into 2 new variants:
`AddTimelineEvents` and `AddEphemeralEvents`.
This patch takes this opportunity to update `matrix_sdk_ui::timeline`
a little bit too. `handle_sync_events` is renamed
`handle_ephemeral_events`, and the `SyncTimelineEvent` argument is
removed: it's possible to use `add_events_at` directly to handle the
`SyncTimelineEvent`s.
* fix(sdk): Do not send `RoomEventCacheUpdate` if values are empty.
This patch prevents sending useless `RoomEventCacheUdpate` if their
respective values are empty.
* chore(ui): Update a log message.
* Apply suggestions from code review
Signed-off-by: Benjamin Bouvier <public@benj.me>
---------
Signed-off-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Benjamin Bouvier <public@benj.me>
This patch adds a new argument to `RoomPagination::run_backwards`:
`until`. It becomes:
pub async fn run_backwards<F, B, Fut>(&self,
batch_size: u16,
mut until: F
) -> Result<B>
where
F: FnMut(BackPaginationOutcome) -> Fut,
Fut: Future<Output = ControlFlow<B, ()>>,
The idea behind `until` is to run pagination _until_ `until` returns
`ControlFlow::Break`, otherwise it continues paginating.
This is useful is many scenearii (cf. the documentation). This is
also and primarily the first step to stop adding events directly from
the pagination, and starts adding events only and strictly only from
`event_cache::RoomEventCacheUpdate` (again, see the `TODO` in the
documentation). This is not done in this patch for the sake of ease
of review.
This is the right goal, and Ruma will be updated to reflect that the
`heroes` field should contain `OwnedUserId` too in [1].
This simplifies the code a bit, and avoids a round-trip encoding
user-ids into a string then decoding them from a string later, in the
case of sliding sync and room name computation.
[1] https://github.com/ruma/ruma/pull/1822
Since rendering is sync, and I want the computed display name (which
retrieval is async), I have to fetch the display name early, just after
getting the room. Oh well :)
This patch does 3 things:
1. It updates Ruma to the latest revision at the time of writing,
2. It updates `matrix-sdk-ffi` to provide the
`RoomSubscription::include_heroes` field,
3. It updates `matrix-sdk-base` so that SlidingSync consumes `heroes`
from the response and update the `RoomSummary` accordingly.
A test has been added to ensure the `RoomSummary` is updated as expected.
It doesn't make sense to expose it for a focused timeline.
Note there's no way for timeline to change focus, at the moment; this
would require special handling here, because one could subscribe to the
back pagination status on a live timeline first, then switch the
timeline to the focus mode. The stream wrapper could then observe other
states that aren't expected by the converter method.
This is actually required for one use case: if the event cache triggers
back-pagination in the background *before* a timeline is opened, it's
possible the timeline observes pagination is running at the beginning,
and doesn't know if more back-pagination is required or not.
This wraps the `Paginator::status` stream by reading the
hit_timeline_start() from the room pagination and adding it to the
`Idle` state.
This whole method is a bit broken. It assumes that, when we did an import from
backup, the backup that they came from is the same as the "current" version.
We *could* add another argument, but to be honest I find the whole method a bit
pointless. It's not particularly tied to the `BackupMachine` abstraction. Let's
instead expose `Store::import_room_keys` and
`ExportedRooomKey::from_backed_up_room_key` publicly, and tell callers to use
that directly.
When we are importing a batch of room keys, use the newly-added
`CryptoStore::save_inbound_group_sessions` method instead of
`CryptoStore::save_changes`.
To do this, we need to pass the backup version into `Store::import_room_keys`
instead of just `from_backup` flag.
When we add a batch of inbound group sessions to the store, if they came from a
backup, we need to record which backup version they came from.
`CryptoStore::save_changes` doesn't give us an easy way to set the backup
version (we could add it to the `Changes` struct, but ugh).
So, we add a new method `save_inbound_group_sessions` which takes the backup
version as a separate param. This works fine, because whenever we import
sessions there are no other changes to store.
The new method isn't used outside of tests yet -- that comes in a follow-up
commit.
This moves code around, and tweaks the behavior:
- `WeakRoom::get()` returns an `Option`, that will be None if the client
is missing or the room is missing.
- `PaginableRoom` for `WeakRoom` will now return a default response if
the room could not be reconstructed from the weak room. It's fine to do
so because we're in a shutdown context.
It's possible the timeline starts with a read marker, in which case the
first item won't be a day divider; in that case, check for the next
item, if present.
test_start_with_read_marker
This patch adds another check to ensure `AsVector` generates
`VectorDiff`s that, once combined, produce an expected `Vector`. It
avoids errors when unit testing `VectorDiff` alone.
This patch ensures that an underflow is not possible when the length
of `chunks` is 0. In practise, it's not possible because there is
_always_ one chunk inside `LinkedChunk`, but it's better to have good
code habits.
This patch removes the `unsafe` part of `as_vector`. The idea is to
pass `Iter` (the forward iterator of `Chunk`) to `AsVector` so that it
internally computes `initial_chunk_lengths`. The shape of this data must
no longer be guaranteed by the caller.
This patch goes a bit further: `UpdateToVectorDiff` has
a new constructor which consumes this `Iter` and builds
`initial_chunk_lengths` itself. Even better!
Finally, `Updates::as_vector` is removed. It's clearly no longer
necessary and it was creating borrowing issues anyway with the new code
structure.
Allow applications to skip the PBKDF2 operation if they already have a cryptographically secure key,
instead using a simple HKDF to derive a key.
In order to maintain compatibility for existing element-web sessions, if we discover that we have an
existing store that was encrypted with a key derived from PBKDF2, then we reconstruct what
element-web used to do: specifically, we base64-encode the key to obtain the "passphrase" that
was previously passed in. If that matches, we know we've got the right key, and can update the
meta store accordingly.
Part of a resolution to element-hq/element-web#26821.
Signed-off-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
This patch renames `ReattachItems` to `StartReattachItems` and
`ReattachItemsDone` to `EndReattachItems`. This naming conveys better
the idea of a _state transition_.
Add a CI step running complement crypto, automatically matching the complement-crypto branch name based on the current branch name, if needs be.
Signed-off-by: Kegan Dougal <7190048+kegsay@users.noreply.github.com>
We could end up, like in the regression test, with a sequence of
operations like that:
- remove day divider @ i+1 (because it's redundant with one @ i)
- remove day divider @ i (because it's useless, since the event before
the day divider and after the day divider use the same date).
In that case, it would break the non-decreasing invariant: we'd apply an
operation on the array @ i+1, then @ i, which troubles the offset
computation.
Instead, when doing an operation based on the "prev_item" (now with a
small helper struct, to facilitate understanding of each field), we also
record the insertion order for the operation itself: it's always "at the
end of the operation order, at the time we're looking at it", so
equivalent to a "push_back" if there's no operation in between; but that
ensures that we'll do the operation in a non-decreasing order. For
instance in the above test case, the Remove(i) is now inserted before
the Remove(i+1), instead of after.
* sdk: Return a Thumbnail from generate_image_thumbnail
We have already all the data for it.
Also fixes an error where the thumbnail format was assumed to always be
JPEG.
* sdk: Allow to select the format of the generated thumbnail
Sending an attachment could often fail if the image crate
cannot encode the thumbnail to the same format as the original.
This allows to select a known supported format to always
be able to generate a thumbnail.
* sdk: Do not return error of thumbnail generation for SendAttachment
Since the thumbnail is optional, failing to generate it should not
stop us from sending the attachment.
* Apply code review fixes
* sdk: Split attachment tests in separate file
* sdk: Add integration tests for generating thumbnails
* Revert wiremock debug log level
---------
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
It's always provided in the `avatar` response in the field, which
sliding sync's using by default, so there's no need to request the
`m.room.avatar` event too.
If we want to be able to note the absence of a room name, we shouldn't
take the name returned by the server (which may be computed, and thus
always be non-null). This way, we can expose both the name contained in
the m.room.name event as well as the computed name everywhere.
A consequence of this is that the room list service must now ask for the
m.room.name event as part of the required state for every room.
With a regression test that didn't pass on main, and would incorrectly
remove the read marker, because it tried to replace the day divider at
(4), that was just scheduled for deletion in the previous loop
iteration.
This patch removes the possibility to have `LinkedChunk` as an
`ObservableVector` via a `Stream`, which was initially the goal of
`AsVectorSubscriber`. Having a `Stream` was more complex than required
for the integration inside `EventCache`. This patch keeps the same code
but renames `AsVectorSubscriber` into `AsVector`. A new internal type,
`UpdateToVectorDiff`, applies the algorithm itself and maintains its
own state, making it possible to re-introduce a `Stream` later if we
want to.
* event cache: reuse the paginator internally
Fixes#3355.
* event cache: move the `pagination_token_notifier` into the `RoomPaginationData` as well
* event cache: introduce a `RoomPagination` API object and move code around
Only code motion. No changes in functionality.
* event cache: remove "paginate" (et al.) in `RoomPagination` method names
No changes in functionality, just renamings.
* event_cache/timeline: have the event cache handle restarting a back-pagination that failed under our feet
When a timeline reset happens while we're back-paginating, the event
cache method to run back pagination would return an success result
indicating that the pagination token disappeared. After thinking about
it, it's not the best API in the world; ideally, the backpagination
mechanism would restart automatically.
Now, this was handled in the timeline before, and the reason it was
handled there was because it was possible to back-paginate and ask for a
certain number of events. I've removed that feature, so that
back-pagination on a live timeline matches the capabilities of a
focused-timeline back-pagination: one can only ask for a given number of
*events*, not timeline items.
As a matter of fact, this simplifies the code a lot by removing many
data structures, that were also exposed (and unused, since recent
changes) in the FFI layer.
* Address review comments
This patch adds 2 new updates: `ReattachItems` and `ReattachItemsDone`.
It's useful to optimise insertion, esp. in `AsVectorSubscriber` but
almost maybe in database.
This patch renames `TruncateItems` to `DetachLastItems`. It's
technically the same things, but the fields are different: `chunk:
ChunkIdentifier` and `length: usize` become a unique `at: Position`. The
spirit is the same but the semantics is a bit different.
This patch, with this renaming, also prepares the next commits.
First off, this patch renames `Update::InsertItems` to
`Update::PushItems` because all items insertions happen at the end of
a chunk. Let's reflect that. `InsertItems` would have meant that it's
possible to insert at any position, but it's not what happens by design.
Second, this patch renames `Update::PushItems::at` to
`Update::PushItems::position_hint`. Indeed, the `at` field would have
meant that the position is specific whilst it's not. It's just a hint to
make the life of update readers simpler. It's also a good way to improve
performance in some cases: since items are pushed, to know the new
position of the items, one has to read the position of the previous last
item and compute the new position from there. Having `position_hint`
help to prevent this dance and save the cost of a reading. That's also
why the field has been renamed to `position_hint`, it's a hint.
This patch updates the constructor of `AsVectorSubscriber` to receive
the initial chunk lengths so that this type doesn't have to guess what
to do when receiving an unknown chunk identifier. `AsVectorSubscriber`
is de facto synchronized with its source `LinkedChunk` when created.
I found the previous API confusing. Firstly, the parameter name was "filename" when we want a file path.
Secondly, we take a `String` when we want a `Path`.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
Cargo nightly now checks whether a cfg option exists.
We need to declare the custom
options we use
and fix those that are wrong.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This makes the public key fields private to ensure that we don't
accidentally swap them out. It also moves the construction of the
subkeys into the master key type.
Since the master/self-signing/user-signing public key types are used for
public user identities as well as for the private key type we have, and
we'd like to sign the public key types it makes sense that the types
itself aren't using an Arc.
Let's instead put the Arc inside the user identity structs.
This will allow us later on to more easily sign the public key types.
This patch removes the notion of `take` vs. `peek` from
`LinkedChunkUpdatesInner` and widens the problem to a more general
approach: `LinkedChunkUpdatesInner` must support multiple readers, not
only two (`take` was the first reader, `peek` was the second reader,
kind of).
Why do we need multiple readers? `LinkedChunkUpdates::take` is
clearly the first reader, it's part of the public API. But the private
API needs to read the updates too, without consuming them, like
`LinkedChunkUpdatesSubscriber`. `peek` was nice for that, but it's
possible to have multiple `LinkedChunkUpdatesSubscriber` at the same
time! Hence the need to widen the approach from 2 readers to many
readers.
This patch introduces a `ReaderToken` to identify readers. The last
indexes are now all stored in a `HashMap<ReaderToken, usize>`. The rest
of the modifications are the consequence of that.
The test `test_updates_take_and_peek` has been entirely rewritten to be
`test_updates_take_and_garbage_collector` where it tests 2 readers and
see how the garbage collector reacts to that.
This patch implements `LinkedChunkUpdates::subscribe` and
`LinkedChunkUpdateSubscriber`, which itself implements `Stream`.
This patch splits `LinkedChunkUpdates` into `LinkedChunkUpdatesInner`,
so that the latter can be shared with `LinkedChunkUpdatesSubscriber`.
This patch adds the `LinkedChunkUpdates::peek` method. This is
a new channel to read the updates without consuming them, like
`LinkedChunkUpdates::take` does.
The complexity is: when do we clear/drop the updates then? We don't
want to keep them in memory forever. Initially `take` was clearing
the updates, but now that we can read them with `peek` too, who's
responsible to clear them? Enter `garbage_collect`. First off,
we already need to maintain 2 index, resp. `last_taken_index` and
`last_peeked_index` so that `take` and `peek` don't return already
returned updates. They respectively know the index of the last update
that has been read. We can use this information to know which updates
must be garbage collected: that's all updates below the two index.
Tadaa. Simple. The only _drawback_ (if it can be considered as such)
is that the garbage collection happens on the next call to `take` or
`peek` (because of the borrow checker). That's not really a big deal in
practise. We could make it happens immediately when calling `take` or
`peek` but it needs more pointer arithmetic and a less straighforward
code.
This patch updates the `LinkedChunk::update_history` field from
a simple `Vec<LinkedChunkUpdate<Item, Gap>>` type to the new
`LinkedChunkUpdates<Item, Gap>` type (note the plural).
This is going to be helpul for the next patches.
This patch removes support for OpenTelemetry because it's not used
anymore by anybody. It also adds multiple duplicated dependencies (like
`reqwest`). Anyway. Farewell.
Preferring to use "reject" wording rather than "failed to
create/update". The latter can be easily misinterpreted as a failure of
the local client to create an entirely new device from scratch, rather
than refusal to instantiate a new local device representation of an
(invalid) device definition received from the server.
This patch makes the `LinkedChunk::update_history` field optional,
so that it doesn't require the user to drain it to avoid eating the
universe.
The `new` constructor disabled the update history, the
`new_with_update_history` enables it.
This patch is a turn around about the `LinkedChunkListener`. Many
patches have been removed because `LinkedChunkListener` needed to
support I/O, so errors and async code. The whole code was affected by
that, resulting in a complex API. The idea of this patch is to decoupled
this. Here is how.
First off, `LinkedChunkListener` is removed. So it's one less generic
parameter on `LinkedChunk`. It's also one less trait, so less
implementations.
Second, now `LinkedChunk` accumulates/collects all “updates” under the
form of a new enum `LinkedChunkUpdate`. These updates can be read with
`LinkedChunk::updates(&mut self) -> &Vec<LinkedChunkUpdate>`. The reader
can simply read them, or even drain them. The reader is responsible
to handle these updates and to dispatch them in a storage or whatever.
`LinkedChunk` is no longer responsible to do that, removing the need to
support errors and to be async.
Third, the simplification has led to an optimisation by introducing a
new type `LinkedChunkLinks`. The documentation explains what it does
and why it was needed. The benefit of this type is: it doesn't increase
the size of `LinkedChunk`, but it simplifies the code: no more `Arc`,
no more `Mutex` (it was required because with I/O and async), no more
borrow checker trick, and the code stays as safe as before.
This patch removes the `displaydoc` dependency. Why?
1. It creates a warning in rustc nightly:
```
warning: non-local `impl` definition, they should be avoided as they go against expectation
--> crates/matrix-sdk-store-encryption/src/lib.rs:49:17
|
49 | #[derive(Debug, Display, thiserror::Error)]
| ^^^^^^^
|
= help: move this `impl` block outside the of the current constant `_DERIVE_Display_FOR_Error`
= note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl`
= note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type
= note: this lint may become deny-by-default in the edition 2024 and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>
= note: the derive macro `Display` may come from an old version of the `displaydoc` crate, try updating your dependency with `cargo update -p displaydoc`
= note: `#[warn(non_local_definitions)]` on by default
= note: this warning originates in the derive macro `Display` (in Nightly builds, run with -Z macro-backtrace for more info)
```
2. `thiserror` is already used, which seems to provide a similar issue.
3. That's less dependency, and less proc-macro, which will improve the
compilation time in general.
Also:
- rename `display_name` to `computed_display_name` in several places,
and reflect that change into a few callers
- simplify slightly the `computed_display_name()` method
This is in line with what the other method using sliding sync does. This
wasn't tested before, because this required `filter_by_push_rules()` to
be enabled in the notification client; now that it's the default, the
test revealed the bug, and so it could be fixed.
The builder had only one meaningful method, `filter_by_push_rules`,
which was always called by the applications — and in fact should always
be true. It was designed as an extra method because it was experimental
at the time, but it's stabilized sufficiently that we can enable this
behavior by default now, considering that a notification that is not
wanted by the user shouldn't be kept, to respect their intent. (This is
in the UI crate, which is opinionated, so it's fine to assume such
intents by design.)
They need to be updated together
because the latters depend on the former.
matrix-authentication-service is still using http 0.2
so we need to add a conversion layer between both major versions
for OIDC requests.
We need to update vodozemac too because of a dependency resolution issue.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This makes all the requests (/context and /messages) cancellation-safe
by making two changes:
- first, use sync locks instead of async locks for the prev/next batch
tokens. This ensures that we can't get cancelled after receiving a
response and managing internal state, i.e. we keep run-to-completion
semantics until the end of the function, once we got a response.
- second, introduce a RAII guard that will reset the state to a given
value when dropped. Then use this to reset the state to Initial (resp.
Idle) in /context (resp. /messages) when the async call is aborted. We
use `mem::forget` once the response has been returned, so as to not call
the `Drop` implementation of the guard later on.
A regression test has also been introduced.
This patch changes the signature of `LinkedChunk<Item, Gap, const
CHUNK_CAPACITY = usize>` to `LinkedChunk<const CHUNK_CAPACITY = usize,
Item, Gap>`. It allows to add more generic parameters if needed, without
conflicting with generic constants.
The clippy website explains that `Box::new(Default::default())` can be
shortened to `Box::default()` and that it's more readable. That's true…
when you don't have a generic parameter in the mix (which may be
required if rustc can't infer the type of the boxee), in which case it
just looks bad, e.g. `Box::<MyType>::default()` instead of
`Box::new(MyType::default())`.
I do strongly prefer the latter, and propose to get rid of the lint, as
a result.
Version 0.7.5 triggers a warning in
our version of rust nightly in CI,
but we can't update it to a recent
version because it triggers a warning
caused by displaydoc
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This introduces the `TimelineFocus`, a new enum to declare if the
timeline is "live" aka looking at events from sync and displaying them
as they come in, or focused on an event (e.g. after clicking a
permalink).
When in the second mode, the timeline can paginate forwards and
backwards, without interacting with the event cache (as this would
require some complicated reconciliation of known events with events
received from pagination, with no guarantee that those events are event
connected in whatever way).
An event-focused timeline will also show edits/reactions/redactions in
real-time (as the events are received from the sync), but will not show
new timeline items, be they for local echoes or events received from the
sync.
`Room::invite_details()` can return an error if the room member event
(the invite) is missing from the store. Usually that would be a sign
that the state is semi-broken, since there should always be such an
event for an invited room. But if it's missing, it shouldn't break the
creation of a `RoomInfo`, and just be missing from the struct.
In https://github.com/matrix-org/matrix-rust-sdk/pull/2691, I suppose
the way `add_mentions` is computed is… wrong. `AddMentions` is used to
automatically infer the `m.mentions` of the reply event based on the
replied event. The way it was computed was based on the reply event
`mentions`, which seems wrong: if the reply contains mentions, then the
sender should be part of it? Nah. That's a bug. We want the reply event
to automatically mention the sender of the replied event if and only
if it's not the same as the current user, i.e. the sender of the reply
event.
This patch fixes the `add_mentions` calculation. This patch also updates
a test and adds another test to ensure that `m.mentions` is correctly
defined when replying to an event.
The `state` lock was taken at the top level of this function, and
indirectly implicitly in the `set_fully_read_event` function. This fixes
it, and adds a regression test.
Fixes#3311.
When the timeline is lagging behind the event cache, it should not only
clear what it contains (because it may be lagging some information
coming from the event cache), it should also retrieve the events the
cache knows about, and adds them as if they were "initial" events.
This makes sure that the event cache's events and the timeline's events
are always the same, and that, in the case of a lag, there won't be any
missing chunks (caused by the event cache back-pagination being further
away in the past, than what's displayed in the timeline).
The lag behind a bit too hard to reproduce, I've not included a test
here; but I think this should be the right move.
Redaction was requiring the `RoomRedactionEventContent`, which was
eventually unused in all the code paths; this removes it.
Also adds lots of documentation for the different types of reaction that
can happen in the timeline.
@@ -24,17 +24,11 @@ The rust-sdk consists of multiple crates that can be picked at your convenience:
- **matrix-sdk-crypto** - No (network) IO encryption state machine that can be
used to add Matrix E2EE support to your client or client library.
## Minimum Supported Rust Version (MSRV)
These crates are built with the Rust language version 2021 and require a minimum compiler version of `1.70`.
## Status
The library is in an alpha state, things that are implemented generally work but
the API will change in breaking ways.
The library is considered production ready and backs multiple client implementations such as Element X [[1]](https://github.com/element-hq/element-x-ios) [[2]](https://github.com/element-hq/element-x-android) and [Fractal](https://gitlab.gnome.org/World/fractal). Client developers should feel confident to build upon it.
If you are interested in using the matrix-sdk now is the time to try it out and
provide feedback.
Development of the SDK has been primarily sponsored by Element though accepts contributions from all.
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.
This uses [`uniffi`](https://mozilla.github.io/uniffi-rs/Overview.html) to build the matrix bindings for native support and wasm-bindgen for web-browser assembly support. Please refer to the specific section to figure out how to build and use the bindings for your platform.
# OpenTelemetry support
The bindings have support for OpenTelemetry, allowing for the upload of traces to
any OpenTelemetry collector. This support is provided through the
allow_verified [label="Share the entire session from the earliest known index.\n\nOk(None)", color=4, fillcolor=3]
allow_limited [label="Share a limited session starting from index i, which is the index we previously shared at.\n\nOk(Some(i))", color=4, fillcolor=3]
refuse_device_key_changed [label="Sender key changed, refuse to share.\n\nErr(KeyForwardDecision::ChangedSenderKey)", color=6, fillcolor=5]
refuse_not_shared [label="Session was never shared with this device, refuse to share.\n\nErr(KeyForwardDecision::OutboundSessionNotShared)", color=6, fillcolor=5]
refuse_untrusted_own_device [label="Our own device, but it is untrusted and we haven't previously shared with it. Refuse to share.\n\nErr(KeyForwardDecision::UntrustedDevice)", color=6, fillcolor=5]
refuse_missing_outbound_session [label="Not our device and haven't previously shared with it. Refuse to share.\n\nErr(KeyForwardDecision::MissingOutboundSession)", color=6, fillcolor=5]
refuse_device_key_changed [label="Sender key changed, refuse to forward.\n\nErr(KeyForwardDecision::ChangedSenderKey)", color=6, fillcolor=5]
refuse_not_shared [label="Session was never shared with this device, refuse to forward.\n\nErr(KeyForwardDecision::OutboundSessionNotShared)", color=6, fillcolor=5]
refuse_untrusted_own_device [label="Our own device, but it is untrusted and we haven't previously shared with it. Refuse to forward.\n\nErr(KeyForwardDecision::UntrustedDevice)", color=6, fillcolor=5]
refuse_missing_outbound_session [label="Not our device and haven't previously shared with it. Refuse to forward.\n\nErr(KeyForwardDecision::MissingOutboundSession)", color=6, fillcolor=5]
// Additionally these should be considered to be ambiguous on their own.
assert_ambiguous!("@mxid:domain.tId");
assert_ambiguous!("@mxid:domain.t\u{217c}d");
assert_ambiguous!("@mxid:domain.t\u{ff4c}d");
assert_ambiguous!("@mxid:domain.t\u{1d5f9}d");
assert_ambiguous!("@mxid:domain.t\u{1d695}d");
assert_ambiguous!("@mxid:domain.t\u{2223}d");
}
}
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.