It is not clear why we ever would want to return the formatted_body when
we ask for the body, but it seems to not be used anywhere and there are
no tests covering that functionality. However it leads to suprising
results, where the plaintextBody can be tricked into returning html
without applying conversions. So we just get rid of that functionality.
We do the key upload asynchronously without awaiting it. This means we
may do multiple syncs before the key upload finishes. So we may generate
more keys than we should.
To fix that prevent multiple key uploads from running at once. This may
lead to outdated key uploads in some cases if we miss an OTK being used
in sync. However, the next sync will still tell us about that so in the
worst case this might delay key uploads by 30s (with the default sync
timeout), which for normal usage should be completely acceptable.
This was added in 77be6102f6 without much
documentation. I am pretty sure the intent was never to slow down every
test by 5 seconds, so let's get rid of it and do more careful delays
where it is useful (like specific sync requests for example).
Makes the tests run 5 times faster (the whole suite!) on my device.
When decrypting the last event for archived rooms when a room key is
received, we used to send a synthetic SyncUpdate. This however put the
archived room into the join section, which converted the room to a
joined room. We need to respect what section the room was in when
sending synthetic SyncUpdates.
fixes https://github.com/famedly/matrix-dart-sdk/issues/1916
This was triggered by some archive decryption test I was writing and
possibly also is triggered in production a few times. Waiting for
running transactions to complete before closing sounds sensible.
This should speed up loading the archived rooms. One of the reasons it
was so slow, is because we were loading all room members!
Additionally this may work around a bug in Synapse, where rooms stuck in
their partial state may block sync indefinitely.
Relates to https://github.com/famedly/product-management/issues/2250
- BREAKING: create `DatabaseApi.storeWellKnown` method
- BREAKING: create `DatabaseApi.getWellKnown` method
- add new getter `Client.wellKnown` containing cached `DiscoveryInformation`
- override `Client.homeserver` to invalidate `Client.wellKnown` in case the domain changed
- override `Client.getWellknown` to cache the resolved `DiscoveryInformation`
- add tests for well-known cache
Fixes: #1865
Signed-off-by: The one with the braid <info@braid.business>
Synapse includes the room in both sections if you have both an
invite->leave and a leave->invite transition in one sync response.
Transitions in the other order are only included once (in the leave
section) it seems, so this should work correctly in all cases.
Fixes https://github.com/famedly/product-management/issues/2283
Group chats with no user
avatar should return null for
the room.avatar getter and not
a random hero avatar. This could
otherwise lead to confusion as
it looks like this is a DM which
is not the case.
For the name we should also
not just display the name of
the invitor like in a DM even for
group chats, but some more
additional information. I found
a String for
invites quite useful here as
this would name rooms without
a m.room.name like this:
"Invited by $senderName"
which should be short enough.
The alternative
"You have been invited by $senderName" could be too
long IMO.
This makes no sense anymore.
In the past we tried to use this
Exception type to have a
unified exception for all
network errors. However, this
is only in use for the custom
request method and for every
other api call it is not. So to
have the same error messages
every time, we should just remove
it.
This completely redoes the requestUser function.
It now doesn't stop requesting a user forever just because of a network
error. But redundant calls are still deduplicated, however their
parameters are taken into account now.
It also now only calls onUpdate and onRoomState when there is actually
new state. This way apps can just listen to updates to rerender instead
of having to implement the deduplication themselves.
It also now doesn't treat member events without membership as "join"
anymore. And lookup errors don't cause an empty user to get inserted
into the room state.
In general this should still request the profile from the server, if the
displayname is unset in a leave event, but it should also allow the app
to actually settle in the tests.
This has been set to false
to prevent storing global
user profiles as member states
in the database. However
looks like this is already
solved below. We can
safely store the profile
in the local cache, otherwise
we cannot calc the body
for an event synchroniously.
canRequestHistory could become false, even though you didn't load all
events from the database yet. So you had to either rely on fetching
until the requestHistory method throws or rely on other workarounds.
This makes requestHistory not throw, when the prev_batch is null, but
also makes canRequestHistory return sane values (but might require an
extra request, that does nothing).
fix: only fire backend.onNewParticipant and backend.onLeftParticipant when it is not the local participant, this fixes the issue where onNewParticipant would get triggered when it detects a new call even though you were not in the call, as of now there is no code in those functions which needs to be triggered before you have joined the call so this should be fine
chore: also improve participants join leave tracking logic
with this you can now send the key before joining the call to the participants, make sure to call onMemberStateChanged first to ensure groupCall.participants is populated
This should highly increase the
performance as right now for every sync
ALL inbound group sessions are loaded
from the database and checked if
they need an upload. So if a user
has 10k stored sessions locally, this
would probably let the whole application
lag a lot. This stores the sessions which
need upload in a different table now,
similar how we do this with the to
device queue
The direct chat account data
content is a map from matrixId
to roomId(s). If we want to find
the roomId for a given userId,
then this is not a problem. But
the other way around, if we
want to check if a given roomId
is a direct chat or not, needs to
process all entries which can be
hundreds. Doing this very
often in an app costs a lot of
performance. This adds a simple
cache in the room object and
validates the cache every time
to make this more efficient.
This lead to the huge problem that there is no
user feedback between sending a message and
seeing it in the timeline as it is encrypted
before the first user feedback is shown. But
the encryption step is async and also includes
fetching devices if necessary so that can take
seconds or even forever on bad internet
connection.
This reverts commit 981c3ea94d.
This fixes several problems. First
sending a fake event through the
onEventUpdate stream was not a
good design and lead to problems
if you expect a timeline event but
then are unable to build the
event from json. This now uses
a new stream in the Client which
is listened to in the timeline to
delete an event which should be
much more reliable.
It also now throws an exception
if deleting the event fails
instead of returning true or false.
A deprecation note is added.
This brings more problems than it
helps. It leads to bugs like flickering
of sending images and also
confuses the user. This should
either be handled by the app
or the user.
Before we have used the Event class for all
state events while for invite rooms those
actually were StrippedStateEvent objects. This
created some problems like we needed to set a
fake originServerTs (usually to DateTime.now()).
Actually we don't need the additional keys for
state events most of the time so just using
StrippedStateEvent for all states and typecasting
them to event where needed is not much of a
hassle while we benefit from a more clear
structure.
This also now uses StrippedStateEvent as a base
class for the User class which makes the User
class more minimal as keys like event_id and
origin_server_ts are no longer necessary. As we
create a lot of fake User objects where we had to
put fake values in it, it brings more benefits
than problems to just get rid of those fields.
This makes sure that the
users for an invitation are
correctly loaded so that we
can display the avatar, the
room displayname and
wether the room is a direct
chat or not.
This fixes the bug that the
actual dart Map in the state
has been manipulated because
we have not worked with a
copy of the map. Also this
crashes if the powerlevelmap
would had a wrong type in
users.
When using the searchEvent()
method it was impossible to
paginate to the next
chunk when one chunk had
0 returned events. This
fixes it by returning the
prevBatch and makes it
possible to insert the prevBatch
again. sinceEventId is still
working but now deprecated.
Original issue and former solution by
The one with the braid <info@braid.business>
Special thanks for pointing out the problem.
This fixes that dart:io is imported into the
SDK database by moving it into it's own mixin which
makes it reusable and platform independent by
using conditional imports.
- removes `Directory` field in high-level `MatrixSdkDatabase`
- migrates `Directory fileStoragePath` to `Uri fileStorageLocation`
- makes file operations in `MatrixSdkDatabase` conditional on
`dart.libraries.js_util`
- implements a tiny stub of the file operations used in `MatrixSdkDatabase`
It seems like the Flutter tool can compile despite these imports. Sadly
the Dart standalone dart2js compiler doesn't reach there. While
refactorying the code, I decided it's likely cleaner to have a `Uri` as
storage location provider than using some fake directory or String as
relacement.
The advantage of a `Uri` at this place is the explicit `Uri.directory`
constructor available to ensure type and encoding safe directory
locations supporting both Windows and *nix.
Additionally, admitted, that's an edge-case, one could even
easily extend the use of a `Uri` based descriptor to support future
storage location accesses (e.g. IPFS or custom schemes for e.g. local
web browser based file system APIs). Using a `Uri`, one would only need
to override the three methods making use of the `fileStorageLocation`
property to handle different Uri schemes too.
Signed-off-by: The one with the braid <info@braid.business>
When user A invites user B to
a group chat, the avatar getter
should not return the
avatar of the inviting user A.
This is not intuitive. A client might
decide to do so but IMO it makes
no sense to do this by default.
If the
room is a DM invite, user A's
avatar is already used in the
code block before.
This makes use of dart
records to return three
different values for one
method. This makes the
special class no longer
necessary just for
returning data.
This changes the way how the last event is stored
for each room. It is now stored next to the
room event itself in the rooms box and no longer
stored like a room state. This way we need to
bump the database version which will cause an
inital sync for the client. Be aware of this when
updating the SDK!
This also makes sure that
the access token is
refreshed when calling
client.getEventByPushNotification()
which is porbably the most
common case for a client
with a stopped sync loop
doing network requests.
This fixes several problems with current soft logout
handling, as it now stores the refresh token correct and
only refreshs it 1 minute in advance instead of 5
minutes.
This was implicitly relying to the timestamp of state events getting
compared in the setState function. Fix this by using the helper
functions already used for invite and join rooms.
We used to add app the member counts of invited users and joined users,
which would make us assume the participants list is complete. Which
would mean we always return the wrong state.
Additionally there is no need to rely on if we have a cached response.
Instead we always only check for completeness instead of possibly
returning stale responses just because we fetched the members once.
We now handle state in the correct order in the sync handler. Using the
timestamp lead to false results when we still generated a default
timestamp of "now" for events, however even without that state events
can have an older timestamp like when accepting an invite on a server
with the clock behind by a minute and we should instead rely on the sync
handler giving us state in the right order.
This causes issues with state handling as we prefer the newer event. It
also has knock-on effects in other places. Instead set such events to
have an obviously invalid timestamp, which makes issues easier to
identify.
This may break invites showing a timestamp or the timestamps for just
sent events, if you rely on the timestamp getting set to "now".
This patch introduces a helper class for SQfLite encryption related operations.
Most matrix clients will encrypt their sqlite database at rest. Since
this is a quite fragmented task using the Flutter sqlite ecosystem, this
helper aims to simplify some more complex operations.
It in particular helps with the following tasks :
- loading the correct shared objects / dynamic libraries for sqlcipher
- check whether a database is encrypted
- migrate an unencrypted SQLite database to SQLCipher
- apply the cipher to a database while opening it and ensure it loads
This code is not exactly matrix related, though presumably any matrix
client will use parts of it.
Possible regressions :
- `package:sqlite3` became a direct dependency. As of now it already was a
transitive dependency of the SDK itself.
Signed-off-by: The one with the braid <info@braid.business>
This refactors the transaction
workaround with
"zone transactions" and
abstracts them in a mixin. Then
it just uses this mixin in the
HiveDatabase and the
sqflite_box and also applies
them on indexedDB to
fix transactions on web.
This creates a set before
requesting users from the
database. This prevents
doing the same check for
the same user multiple
times and also prevents
concurrent modifications
of the event list.
This changes the behavior
when client init fails. It
no longer calls logout and does
only clear local data while
returning all available
information in a new
exception type so that the
SDK consumer can decide
to logout or try again to init
with these information. This
should make it much more rare
that users loose their sessions.
This creates the timeline object
earlier in the Room.getTimeline() method.
This results to that the
Timeline object already starts
to listen on the event stream
while the getTimeline() method
requests users from the database
and tries to decrypt room
events. I assume that this
causes the problem that
on timeline creation new
events get lost because they
come in, while getTimeline() is
not yet completed but the
onEvent stream is not yet
connected at the same time.
This fixes the response
timeout for the initial
sync and sets it to 2
minutes instead of 10
seconds. This should increase
the speed for the initial
sync especially for large
accounts. This change
also adds some
documentation in the
code about what
timeout does what.
This refactors three methods
regarding powerlevels. It
makes them a little bit more
readable and removes
unnecessary checks. it
also changes the canSendDefaultMessage
method in a way that it also
checks the events map in the
powerlevels so that it returns
true if message events are
overwritten there. It also
improves the dart docs and
explains in more detail what it
does.
dynamic.copy returned a type
error so I reverted the previous
change of the copyMap
method to an extension. Also
I found out that we have used
two copyMap methods in the
SDK which did exactly the same.
I deleted the old one and
changed the tests.
Unfortunately we need to copy
all maps. I took the opportunity
and abstracted the copy map
method to utils. I kept the
copyMap method as a
reference in HiveCollections
database to not require a
huge refactoring there as we
are going to ditch it anyway.
BREAKING CHANGE: This replaces the old dehydrated devices
implementation, since there is no way to query what is supported easily
and supporting both would be complicated.
fixes https://github.com/famedly/matrix-dart-sdk/issues/1579
There were several issues here. Key uploads in general failed, because
the await caused a Future<dynamic> to be returned, which failed type
checking.
But also we never unset our future, which was used for the online key
backup uploads, which meant we would very quickly stop uploading any
keys at all.
This changes the behavior
of the markdown method to
only convert linebreaks inside
of p blocks. I found no better
solution yet for the problem
as otherwise also lists
will have linebreaks between
the list items. Unfortunately
the default linebreak syntax
seems not to fulfill our needs.
BREAKING CHANGE: This changes the runInRoot method to not return a
future. As a user, if you need the result of an async computation passed
to runInRoot, please await it directly. Also the KeyVerification start
and a few call methods now return a future.