fix: Only save state events from sync processing in-memory if needed

If we dump all state events from sync into memory then we needlessly
clog up our memory, potentially running out of ram. This is useless
as when opening the timeline we post-load the unimportant state events
anyways. So, this PR makes sure that only the state events of post-loaded
rooms and important state events land in-memory when processing a sync
request.
This commit is contained in:
Sorunome 2021-12-06 11:09:50 +01:00
parent 86f99bdef5
commit e3bd0cf139
No known key found for this signature in database
GPG Key ID: B19471D07FC9BE9C
2 changed files with 162 additions and 5 deletions

View File

@ -1706,12 +1706,23 @@ class Client extends MatrixApi {
),
);
} else {
if (stateEvent.type != EventTypes.Message ||
stateEvent.relationshipType != RelationshipTypes.edit ||
stateEvent.relationshipEventId == room.lastEvent?.eventId ||
((room.lastEvent?.relationshipType == RelationshipTypes.edit &&
// We want to set state the in-memory cache for the room with the new event.
// To do this, we have to respect to not save edits, unless they edit the
// current last event.
// Additionally, we only store the event in-memory if the room has either been
// post-loaded or the event is animportant state event.
final noMessageOrNoEdit = stateEvent.type != EventTypes.Message ||
stateEvent.relationshipType != RelationshipTypes.edit;
final editingLastEvent =
stateEvent.relationshipEventId == room.lastEvent?.eventId;
final consecutiveEdit =
room.lastEvent?.relationshipType == RelationshipTypes.edit &&
stateEvent.relationshipEventId ==
room.lastEvent?.relationshipEventId))) {
room.lastEvent?.relationshipEventId;
final importantOrRoomLoaded =
!room.partial || importantStateEvents.contains(stateEvent.type);
if ((noMessageOrNoEdit || editingLastEvent || consecutiveEdit) &&
importantOrRoomLoaded) {
room.setState(stateEvent);
}
}

View File

@ -348,6 +348,152 @@ void main() {
expect(archive[1].name, 'The room name 2');
});
test('sync state event in-memory handling', () async {
final roomId = '!726s6s6q:example.com';
final room = matrix.getRoomById(roomId)!;
// put an important state event in-memory
await matrix.handleSync(SyncUpdate.fromJson({
'next_batch': 'fakesync',
'rooms': {
'join': {
roomId: {
'state': {
'events': [
<String, dynamic>{
'sender': '@alice:example.com',
'type': 'm.room.name',
'content': <String, dynamic>{'name': 'foxies'},
'state_key': '',
'origin_server_ts': 1417731086799,
'event_id': '66697273743033:example.com'
}
]
}
}
}
}
}));
expect(room.getState('m.room.name')?.content['name'], 'foxies');
// drop an unimportant state event from in-memory handling
await matrix.handleSync(SyncUpdate.fromJson({
'next_batch': 'fakesync',
'rooms': {
'join': {
roomId: {
'state': {
'events': [
<String, dynamic>{
'sender': '@alice:example.com',
'type': 'com.famedly.custom',
'content': <String, dynamic>{'name': 'foxies'},
'state_key': '',
'origin_server_ts': 1417731086799,
'event_id': '66697273743033:example.com'
}
]
}
}
}
}
}));
expect(room.getState('com.famedly.custom'), null);
// persist normal room messages
await matrix.handleSync(SyncUpdate.fromJson({
'next_batch': 'fakesync',
'rooms': {
'join': {
roomId: {
'timeline': {
'events': [
<String, dynamic>{
'sender': '@alice:example.com',
'type': 'm.room.message',
'content': <String, dynamic>{
'msgtype': 'm.text',
'body': 'meow'
},
'origin_server_ts': 1417731086799,
'event_id': '\$last:example.com'
}
]
}
}
}
}
}));
expect(room.getState('m.room.message')!.content['body'], 'meow');
// ignore edits
await matrix.handleSync(SyncUpdate.fromJson({
'next_batch': 'fakesync',
'rooms': {
'join': {
roomId: {
'timeline': {
'events': [
<String, dynamic>{
'sender': '@alice:example.com',
'type': 'm.room.message',
'content': <String, dynamic>{
'msgtype': 'm.text',
'body': '* floooof',
'm.new_content': <String, dynamic>{
'msgtype': 'm.text',
'body': 'floooof',
},
'm.relates_to': <String, dynamic>{
'rel_type': 'm.replace',
'event_id': '\$other:example.com'
},
},
'origin_server_ts': 1417731086799,
'event_id': '\$edit:example.com'
}
]
}
}
}
}
}));
expect(room.getState('m.room.message')!.content['body'], 'meow');
// accept edits to the last event
await matrix.handleSync(SyncUpdate.fromJson({
'next_batch': 'fakesync',
'rooms': {
'join': {
roomId: {
'timeline': {
'events': [
<String, dynamic>{
'sender': '@alice:example.com',
'type': 'm.room.message',
'content': <String, dynamic>{
'msgtype': 'm.text',
'body': '* floooof',
'm.new_content': <String, dynamic>{
'msgtype': 'm.text',
'body': 'floooof',
},
'm.relates_to': <String, dynamic>{
'rel_type': 'm.replace',
'event_id': '\$last:example.com'
},
},
'origin_server_ts': 1417731086799,
'event_id': '\$edit:example.com'
}
]
}
}
}
}
}));
expect(room.getState('m.room.message')!.content['body'], '* floooof');
});
test('getProfileFromUserId', () async {
final profile = await matrix.getProfileFromUserId('@getme:example.com',
getFromRooms: false);