Skip to content

Commit

Permalink
refactor: Use Event instead of EventUpdate for storing in db
Browse files Browse the repository at this point in the history
  • Loading branch information
krille-chan committed Jan 7, 2025
1 parent 5ac6c94 commit bc328aa
Show file tree
Hide file tree
Showing 14 changed files with 534 additions and 528 deletions.
8 changes: 3 additions & 5 deletions lib/encryption/encryption.dart
Original file line number Diff line number Diff line change
Expand Up @@ -348,11 +348,9 @@ class Encryption {
event.room.setState(event);
}
await client.database?.storeEventUpdate(
EventUpdate(
content: event.toJson(),
roomID: event.room.id,
type: updateType,
),
event.room.id,
event,
updateType,
client,
);
}
Expand Down
86 changes: 72 additions & 14 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1647,8 +1647,28 @@ class Client extends MatrixApi {
/// the app receives a new synchronization, this event is called for every signal
/// to update the GUI. For example, for a new message, it is called:
/// onRoomEvent( "m.room.message", "!chat_id:server.com", "timeline", {sender: "@bob:server.com", body: "Hello world"} )
// ignore: deprecated_member_use_from_same_package
@Deprecated(
'Use `onTimelineEvent`, `onHistoryEvent` or `onNotification` instead.',
)
final CachedStreamController<EventUpdate> onEvent = CachedStreamController();

/// A stream of all incoming timeline events for all rooms **after**
/// decryption. The events are coming in the same order as they come down from
/// the sync.
final CachedStreamController<Event> onTimelineEvent =
CachedStreamController();

/// A stream for all incoming historical timeline events **after** decryption
/// triggered by a `Room.requestHistory()` call or a method which calls it.
final CachedStreamController<Event> onHistoryEvent = CachedStreamController();

/// A stream of incoming Events **after** decryption which **should** trigger
/// a (local) notification. This includes timeline events but also
/// invite states. Excluded events are those sent by the user themself or
/// not matching the push rules.
final CachedStreamController<Event> onNotification = CachedStreamController();

/// The onToDeviceEvent is called when there comes a new to device event. It is
/// already decrypted if necessary.
final CachedStreamController<ToDeviceEvent> onToDeviceEvent =
Expand Down Expand Up @@ -1889,11 +1909,9 @@ class Client extends MatrixApi {
if (storeInDatabase) {
await database?.transaction(() async {
await database.storeEventUpdate(
EventUpdate(
roomID: roomId,
type: EventUpdateType.timeline,
content: event.toJson(),
),
roomId,
event,
EventUpdateType.timeline,
this,
);
});
Expand Down Expand Up @@ -2768,12 +2786,6 @@ class Client extends MatrixApi {
}
}

final update = EventUpdate(
roomID: room.id,
type: type,
content: event.toJson(),
);

// Any kind of member change? We should invalidate the profile then:
if (event.type == EventTypes.RoomMember) {
final userId = event.stateKey;
Expand All @@ -2799,15 +2811,61 @@ class Client extends MatrixApi {
}
_updateRoomsByEventUpdate(room, event, type);
if (store) {
await database?.storeEventUpdate(update, this);
await database?.storeEventUpdate(room.id, event, type, this);
}
if (event is MatrixEvent && encryptionEnabled) {
await encryption?.handleEventUpdate(
Event.fromMatrixEvent(event, room),
type,
);
}
onEvent.add(update);

// ignore: deprecated_member_use_from_same_package
onEvent.add(
// ignore: deprecated_member_use_from_same_package
EventUpdate(
roomID: room.id,
type: type,
content: event.toJson(),
),
);
if (event is MatrixEvent) {
final timelineEvent = Event.fromMatrixEvent(event, room);
switch (type) {
case EventUpdateType.timeline:
onTimelineEvent.add(timelineEvent);
if (prevBatch != null &&
timelineEvent.senderId != userID &&
room.notificationCount > 0 &&
pushruleEvaluator.match(timelineEvent).notify) {
onNotification.add(timelineEvent);
}
break;
case EventUpdateType.history:
onHistoryEvent.add(timelineEvent);
break;
default:
break;
}
}

// Trigger local notification for a new invite:
if (prevBatch != null &&
type == EventUpdateType.inviteState &&
event.type == EventTypes.RoomMember &&
event.stateKey == userID) {
onNotification.add(
Event(
type: event.type,
eventId: 'invite_for_${room.id}',
senderId: event.senderId,
originServerTs: DateTime.now(),
stateKey: event.stateKey,
content: event.content,
room: room,
),
);
}

if (prevBatch != null &&
(type == EventUpdateType.timeline ||
Expand Down Expand Up @@ -2931,7 +2989,7 @@ class Client extends MatrixApi {
Logs().wtf(
'Passed in a ${eventUpdate.runtimeType} with $type to _updateRoomsByEventUpdate(). This should never happen!',
);
assert(true);
assert(eventUpdate is! MatrixEvent);
return;
}
final event = Event.fromMatrixEvent(eventUpdate, room);
Expand Down
7 changes: 6 additions & 1 deletion lib/src/database/database_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,12 @@ abstract class DatabaseApi {

/// Stores an EventUpdate object in the database. Must be called inside of
/// [transaction].
Future<void> storeEventUpdate(EventUpdate eventUpdate, Client client);
Future<void> storeEventUpdate(
String roomId,
StrippedStateEvent event,
EventUpdateType type,
Client client,
);

Future<Event?> getEventById(String eventId, Room room);

Expand Down
12 changes: 11 additions & 1 deletion lib/src/database/hive_collections_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,17 @@ class HiveCollectionsDatabase extends DatabaseApi {
}

@override
Future<void> storeEventUpdate(EventUpdate eventUpdate, Client client) async {
Future<void> storeEventUpdate(
String roomId,
StrippedStateEvent event,
EventUpdateType type,
Client client,
) async {
final eventUpdate = EventUpdate(
roomID: roomId,
content: event.toJson(),
type: type,
);
final tmpRoom = client.getRoomById(eventUpdate.roomID) ??
Room(id: eventUpdate.roomID, client: client);

Expand Down
111 changes: 47 additions & 64 deletions lib/src/database/matrix_sdk_database.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1093,45 +1093,37 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
}

@override
Future<void> storeEventUpdate(EventUpdate eventUpdate, Client client) async {
final tmpRoom = client.getRoomById(eventUpdate.roomID) ??
Room(id: eventUpdate.roomID, client: client);
Future<void> storeEventUpdate(
String roomId,
StrippedStateEvent event,
EventUpdateType type,
Client client,
) async {
final tmpRoom =
client.getRoomById(roomId) ?? Room(id: roomId, client: client);

// In case of this is a redaction event
if (eventUpdate.content['type'] == EventTypes.Redaction) {
final eventId = eventUpdate.content.tryGet<String>('redacts');
final event =
if (event.type == EventTypes.Redaction && event is MatrixEvent) {
final redactionEvent = Event.fromMatrixEvent(event, tmpRoom);
final eventId = redactionEvent.redacts;
final redactedEvent =
eventId != null ? await getEventById(eventId, tmpRoom) : null;
if (event != null) {
event.setRedactionEvent(Event.fromJson(eventUpdate.content, tmpRoom));
if (redactedEvent != null) {
redactedEvent.setRedactionEvent(redactionEvent);
await _eventsBox.put(
TupleKey(eventUpdate.roomID, event.eventId).toString(),
event.toJson(),
TupleKey(roomId, redactedEvent.eventId).toString(),
redactedEvent.toJson(),
);

if (tmpRoom.lastEvent?.eventId == event.eventId) {
if (client.importantStateEvents.contains(event.type)) {
await _preloadRoomStateBox.put(
TupleKey(eventUpdate.roomID, event.type, '').toString(),
event.toJson(),
);
} else {
await _nonPreloadRoomStateBox.put(
TupleKey(eventUpdate.roomID, event.type, '').toString(),
event.toJson(),
);
}
}
}
}

// Store a common message event
if ({EventUpdateType.timeline, EventUpdateType.history}
.contains(eventUpdate.type)) {
final eventId = eventUpdate.content['event_id'];
if ({EventUpdateType.timeline, EventUpdateType.history}.contains(type) &&
event is MatrixEvent) {
final timelineEvent = Event.fromMatrixEvent(event, tmpRoom);
// Is this ID already in the store?
final prevEvent = await _eventsBox
.get(TupleKey(eventUpdate.roomID, eventId).toString());
final prevEvent =
await _eventsBox.get(TupleKey(roomId, event.eventId).toString());
final prevStatus = prevEvent == null
? null
: () {
Expand All @@ -1144,13 +1136,7 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
}();

// calculate the status
final newStatus = eventStatusFromInt(
eventUpdate.content.tryGet<int>('status') ??
eventUpdate.content
.tryGetMap<String, dynamic>('unsigned')
?.tryGet<int>(messageSendingStatusKey) ??
EventStatus.synced.intValue,
);
final newStatus = timelineEvent.status;

// Is this the response to a sending event which is already synced? Then
// there is nothing to do here.
Expand All @@ -1165,29 +1151,25 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
newStatus,
);

// Add the status and the sort order to the content so it get stored
eventUpdate.content['unsigned'] ??= <String, dynamic>{};
eventUpdate.content['unsigned'][messageSendingStatusKey] =
eventUpdate.content['status'] = status.intValue;
timelineEvent.status = status;

final eventId = timelineEvent.eventId;
// In case this event has sent from this account we have a transaction ID
final transactionId = eventUpdate.content
.tryGetMap<String, dynamic>('unsigned')
?.tryGet<String>('transaction_id');
final transactionId =
timelineEvent.unsigned?.tryGet<String>('transaction_id');
await _eventsBox.put(
TupleKey(eventUpdate.roomID, eventId).toString(),
eventUpdate.content,
TupleKey(roomId, eventId).toString(),
timelineEvent.toJson(),
);

// Update timeline fragments
final key = TupleKey(eventUpdate.roomID, status.isSent ? '' : 'SENDING')
.toString();
final key = TupleKey(roomId, status.isSent ? '' : 'SENDING').toString();

final eventIds =
List<String>.from(await _timelineFragmentsBox.get(key) ?? []);

if (!eventIds.contains(eventId)) {
if (eventUpdate.type == EventUpdateType.history) {
if (type == EventUpdateType.history) {
eventIds.add(eventId);
} else {
eventIds.insert(0, eventId);
Expand All @@ -1196,15 +1178,15 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
} else if (status.isSynced &&
prevStatus != null &&
prevStatus.isSent &&
eventUpdate.type != EventUpdateType.history) {
type != EventUpdateType.history) {
// Status changes from 1 -> 2? Make sure event is correctly sorted.
eventIds.remove(eventId);
eventIds.insert(0, eventId);
}

// If event comes from server timeline, remove sending events with this ID
if (status.isSent) {
final key = TupleKey(eventUpdate.roomID, 'SENDING').toString();
final key = TupleKey(roomId, 'SENDING').toString();
final eventIds =
List<String>.from(await _timelineFragmentsBox.get(key) ?? []);
final i = eventIds.indexWhere((id) => id == eventId);
Expand All @@ -1215,37 +1197,38 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {

// Is there a transaction id? Then delete the event with this id.
if (!status.isError && !status.isSending && transactionId != null) {
await removeEvent(transactionId, eventUpdate.roomID);
await removeEvent(transactionId, roomId);
}
}

final stateKey = eventUpdate.content['state_key'];
final stateKey = event.stateKey;
// Store a common state event
if (stateKey != null &&
// Don't store events as state updates when paginating backwards.
(eventUpdate.type == EventUpdateType.timeline ||
eventUpdate.type == EventUpdateType.state ||
eventUpdate.type == EventUpdateType.inviteState)) {
if (eventUpdate.content['type'] == EventTypes.RoomMember) {
{
EventUpdateType.timeline,
EventUpdateType.state,
EventUpdateType.inviteState,
}.contains(type)) {
if (event.type == EventTypes.RoomMember) {
await _roomMembersBox.put(
TupleKey(
eventUpdate.roomID,
eventUpdate.content['state_key'],
roomId,
stateKey,
).toString(),
eventUpdate.content,
event.toJson(),
);
} else {
final type = eventUpdate.content['type'] as String;
final roomStateBox = client.importantStateEvents.contains(type)
final roomStateBox = client.importantStateEvents.contains(event.type)
? _preloadRoomStateBox
: _nonPreloadRoomStateBox;
final key = TupleKey(
eventUpdate.roomID,
type,
roomId,
event.type,
stateKey,
).toString();

await roomStateBox.put(key, eventUpdate.content);
await roomStateBox.put(key, event.toJson());
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions lib/src/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ class Event extends MatrixEvent {
Map<String, dynamic>? unsigned,
Map<String, dynamic>? prevContent,
String? stateKey,
super.redacts,
required this.room,
MatrixEvent? originalSource,
}) : _originalSource = originalSource,
Expand Down Expand Up @@ -212,6 +213,7 @@ class Event extends MatrixEvent {
),
unsigned: unsigned,
room: room,
redacts: jsonPayload['redacts'],
originalSource:
originalSource.isEmpty ? null : MatrixEvent.fromJson(originalSource),
);
Expand Down
Loading

0 comments on commit bc328aa

Please sign in to comment.