refactor: BREAKING Migrate database to new lastEvent storage method
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 commit is contained in:
parent
20073ddd49
commit
b90b902218
|
|
@ -216,8 +216,6 @@ class Client extends MatrixApi {
|
|||
importantStateEvents.addAll([
|
||||
EventTypes.RoomName,
|
||||
EventTypes.RoomAvatar,
|
||||
EventTypes.Message,
|
||||
EventTypes.Encrypted,
|
||||
EventTypes.Encryption,
|
||||
EventTypes.RoomCanonicalAlias,
|
||||
EventTypes.RoomTombstone,
|
||||
|
|
@ -2507,7 +2505,8 @@ class Client extends MatrixApi {
|
|||
|
||||
// Is this event redacting the last event?
|
||||
if (event.type == EventTypes.Redaction &&
|
||||
event.redacts == room.lastEvent?.eventId) {
|
||||
(event.content.tryGet<String>('redacts') ?? event.redacts) ==
|
||||
room.lastEvent?.eventId) {
|
||||
room.lastEvent?.setRedactionEvent(event);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import 'package:matrix/src/utils/run_benchmarked.dart';
|
|||
|
||||
/// This database does not support file caching!
|
||||
class HiveCollectionsDatabase extends DatabaseApi {
|
||||
static const int version = 6;
|
||||
static const int version = 7;
|
||||
final String name;
|
||||
final String? path;
|
||||
final HiveCipher? key;
|
||||
|
|
@ -1125,10 +1125,8 @@ class HiveCollectionsDatabase extends DatabaseApi {
|
|||
await removeEvent(transactionId, eventUpdate.roomID);
|
||||
}
|
||||
}
|
||||
final stateKey =
|
||||
client.roomPreviewLastEvents.contains(eventUpdate.content['type'])
|
||||
? ''
|
||||
: eventUpdate.content['state_key'];
|
||||
|
||||
final stateKey = eventUpdate.content['state_key'];
|
||||
// Store a common state event
|
||||
if (stateKey != null) {
|
||||
if (eventUpdate.content['type'] == EventTypes.RoomMember) {
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ import 'package:matrix/src/utils/run_benchmarked.dart';
|
|||
@Deprecated(
|
||||
'Use [HiveCollectionsDatabase] instead. Don\'t forget to properly migrate!')
|
||||
class FamedlySdkHiveDatabase extends DatabaseApi with ZoneTransactionMixin {
|
||||
static const int version = 5;
|
||||
static const int version = 6;
|
||||
final String name;
|
||||
late Box _clientBox;
|
||||
late Box _accountDataBox;
|
||||
|
|
@ -1057,10 +1057,7 @@ class FamedlySdkHiveDatabase extends DatabaseApi with ZoneTransactionMixin {
|
|||
}
|
||||
}
|
||||
|
||||
final stateKey =
|
||||
client.roomPreviewLastEvents.contains(eventUpdate.content['type'])
|
||||
? ''
|
||||
: eventUpdate.content['state_key'];
|
||||
final stateKey = eventUpdate.content['state_key'];
|
||||
// Store a common state event
|
||||
if (stateKey != null) {
|
||||
if (eventUpdate.content['type'] == EventTypes.RoomMember) {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ import 'package:matrix/src/database/indexeddb_box.dart'
|
|||
if (dart.library.io) 'package:matrix/src/database/sqflite_box.dart';
|
||||
|
||||
class MatrixSdkDatabase extends DatabaseApi {
|
||||
static const int version = 6;
|
||||
static const int version = 7;
|
||||
final String name;
|
||||
late BoxCollection _collection;
|
||||
late Box<String> _clientBox;
|
||||
|
|
@ -1084,10 +1084,7 @@ class MatrixSdkDatabase extends DatabaseApi {
|
|||
}
|
||||
}
|
||||
|
||||
final stateKey =
|
||||
client.roomPreviewLastEvents.contains(eventUpdate.content['type'])
|
||||
? ''
|
||||
: eventUpdate.content['state_key'];
|
||||
final stateKey = eventUpdate.content['state_key'];
|
||||
// Store a common state event
|
||||
if (stateKey != null) {
|
||||
if (eventUpdate.content['type'] == EventTypes.RoomMember) {
|
||||
|
|
|
|||
|
|
@ -170,18 +170,14 @@ class Room {
|
|||
Logs().w('Tried to set state event for wrong room!');
|
||||
return;
|
||||
}
|
||||
if (stateKey == null && !client.importantStateEvents.contains(state.type)) {
|
||||
if (stateKey == null) {
|
||||
Logs().w(
|
||||
'Tried to set a non state event with type "${state.type}" as state event for a room',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// We still store events without a state key to load legacy lastEvent
|
||||
// candidates from the database. This can be changed once we either
|
||||
// implemented a database migration for legacy lastEvent candidates or
|
||||
// we just waited some time (written at March 13th 2024).
|
||||
(states[state.type] ??= {})[stateKey ?? ''] = state;
|
||||
(states[state.type] ??= {})[stateKey] = state;
|
||||
|
||||
client.onRoomState.add(state);
|
||||
}
|
||||
|
|
@ -374,43 +370,21 @@ class Room {
|
|||
Event? get lastEvent {
|
||||
if (_lastEvent != null) return _lastEvent;
|
||||
|
||||
// !Everything below is the deprecated way of fetching the last event!
|
||||
|
||||
// as lastEvent calculation is based on the state events we unfortunately cannot
|
||||
// use sortOrder here: With many state events we just know which ones are the
|
||||
// newest ones, without knowing in which order they actually happened. As such,
|
||||
// using the origin_server_ts is the best guess for this algorithm. While not
|
||||
// perfect, it is only used for the room preview in the room list and sorting
|
||||
// said room list, so it should be good enough.
|
||||
// Just pick the newest state event as an indicator for when the last
|
||||
// activity was in this room. This is better than nothing:
|
||||
var lastTime = DateTime.fromMillisecondsSinceEpoch(0);
|
||||
final lastEvents =
|
||||
client.roomPreviewLastEvents.map(getState).whereType<Event>();
|
||||
Event? lastEvent;
|
||||
|
||||
states.forEach((final String key, final entry) {
|
||||
final state = entry[''];
|
||||
if (state == null) return;
|
||||
if (state.originServerTs.millisecondsSinceEpoch >
|
||||
lastTime.millisecondsSinceEpoch) {
|
||||
lastTime = state.originServerTs;
|
||||
lastEvent = state;
|
||||
}
|
||||
});
|
||||
|
||||
var lastEvent = lastEvents.isEmpty
|
||||
? null
|
||||
: lastEvents.reduce((a, b) {
|
||||
if (a.originServerTs == b.originServerTs) {
|
||||
// if two events have the same sort order we want to give encrypted events a lower priority
|
||||
// This is so that if the same event exists in the state both encrypted *and* unencrypted,
|
||||
// the unencrypted one is picked
|
||||
return a.type == EventTypes.Encrypted ? b : a;
|
||||
}
|
||||
return a.originServerTs.millisecondsSinceEpoch >
|
||||
b.originServerTs.millisecondsSinceEpoch
|
||||
? a
|
||||
: b;
|
||||
});
|
||||
if (lastEvent == null) {
|
||||
states.forEach((final String key, final entry) {
|
||||
final state = entry[''];
|
||||
if (state == null) return;
|
||||
if (state.originServerTs.millisecondsSinceEpoch >
|
||||
lastTime.millisecondsSinceEpoch) {
|
||||
lastTime = state.originServerTs;
|
||||
lastEvent = state;
|
||||
}
|
||||
});
|
||||
}
|
||||
return lastEvent;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1292,7 +1292,7 @@ void main() {
|
|||
},
|
||||
room,
|
||||
));
|
||||
expect(room.getState('m.room.message') == null, false);
|
||||
expect(room.getState('m.room.message') == null, true);
|
||||
});
|
||||
|
||||
test('Widgets', () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue