Merge branch 'krille/refactor-sync-function' into 'main'
Refactor Sync and remove pure JSON usage See merge request famedly/company/frontend/famedlysdk!1062
This commit is contained in:
commit
248aba1199
|
|
@ -1666,29 +1666,29 @@ class Client extends MatrixApi {
|
||||||
progress: ++handledRooms / rooms.length,
|
progress: ++handledRooms / rooms.length,
|
||||||
));
|
));
|
||||||
final id = entry.key;
|
final id = entry.key;
|
||||||
final room = entry.value;
|
final syncRoomUpdate = entry.value;
|
||||||
|
|
||||||
await database?.storeRoomUpdate(id, room, this);
|
await database?.storeRoomUpdate(id, syncRoomUpdate, this);
|
||||||
_updateRoomsByRoomUpdate(id, room);
|
final room = _updateRoomsByRoomUpdate(id, syncRoomUpdate);
|
||||||
|
|
||||||
/// Handle now all room events and save them in the database
|
/// Handle now all room events and save them in the database
|
||||||
if (room is JoinedRoomUpdate) {
|
if (syncRoomUpdate is JoinedRoomUpdate) {
|
||||||
final state = room.state;
|
final state = syncRoomUpdate.state;
|
||||||
|
|
||||||
if (state != null && state.isNotEmpty) {
|
if (state != null && state.isNotEmpty) {
|
||||||
// TODO: This method seems to be comperatively slow for some updates
|
// TODO: This method seems to be comperatively slow for some updates
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(
|
||||||
id,
|
room,
|
||||||
state.map((i) => i.toJson()).toList(),
|
state,
|
||||||
EventUpdateType.state,
|
EventUpdateType.state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final timelineEvents = room.timeline?.events;
|
final timelineEvents = syncRoomUpdate.timeline?.events;
|
||||||
if (timelineEvents != null && timelineEvents.isNotEmpty) {
|
if (timelineEvents != null && timelineEvents.isNotEmpty) {
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(
|
||||||
id,
|
room,
|
||||||
timelineEvents.map((i) => i.toJson()).toList(),
|
timelineEvents,
|
||||||
direction != null
|
direction != null
|
||||||
? (direction == Direction.b
|
? (direction == Direction.b
|
||||||
? EventUpdateType.history
|
? EventUpdateType.history
|
||||||
|
|
@ -1696,73 +1696,72 @@ class Client extends MatrixApi {
|
||||||
: EventUpdateType.timeline);
|
: EventUpdateType.timeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
final ephemeral = room.ephemeral;
|
final ephemeral = syncRoomUpdate.ephemeral;
|
||||||
if (ephemeral != null && ephemeral.isNotEmpty) {
|
if (ephemeral != null && ephemeral.isNotEmpty) {
|
||||||
// TODO: This method seems to be comperatively slow for some updates
|
// TODO: This method seems to be comperatively slow for some updates
|
||||||
await _handleEphemerals(
|
await _handleEphemerals(
|
||||||
id, ephemeral.map((i) => i.toJson()).toList());
|
room,
|
||||||
|
ephemeral,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final accountData = room.accountData;
|
final accountData = syncRoomUpdate.accountData;
|
||||||
if (accountData != null && accountData.isNotEmpty) {
|
if (accountData != null && accountData.isNotEmpty) {
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(
|
||||||
id,
|
room,
|
||||||
accountData.map((i) => i.toJson()).toList(),
|
accountData,
|
||||||
EventUpdateType.accountData);
|
EventUpdateType.accountData,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room is LeftRoomUpdate) {
|
if (syncRoomUpdate is LeftRoomUpdate) {
|
||||||
final timelineEvents = room.timeline?.events;
|
final timelineEvents = syncRoomUpdate.timeline?.events;
|
||||||
if (timelineEvents != null && timelineEvents.isNotEmpty) {
|
if (timelineEvents != null && timelineEvents.isNotEmpty) {
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(
|
||||||
id,
|
room,
|
||||||
timelineEvents.map((i) => i.toJson()).toList(),
|
timelineEvents,
|
||||||
EventUpdateType.timeline,
|
EventUpdateType.timeline,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final accountData = room.accountData;
|
final accountData = syncRoomUpdate.accountData;
|
||||||
if (accountData != null && accountData.isNotEmpty) {
|
if (accountData != null && accountData.isNotEmpty) {
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(
|
||||||
id,
|
room,
|
||||||
accountData.map((i) => i.toJson()).toList(),
|
accountData,
|
||||||
EventUpdateType.accountData);
|
EventUpdateType.accountData,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
final state = room.state;
|
final state = syncRoomUpdate.state;
|
||||||
if (state != null && state.isNotEmpty) {
|
if (state != null && state.isNotEmpty) {
|
||||||
await _handleRoomEvents(
|
await _handleRoomEvents(room, state, EventUpdateType.state);
|
||||||
id, state.map((i) => i.toJson()).toList(), EventUpdateType.state);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (room is InvitedRoomUpdate) {
|
if (syncRoomUpdate is InvitedRoomUpdate) {
|
||||||
final state = room.inviteState;
|
final state = syncRoomUpdate.inviteState;
|
||||||
if (state != null && state.isNotEmpty) {
|
if (state != null && state.isNotEmpty) {
|
||||||
await _handleRoomEvents(id, state.map((i) => i.toJson()).toList(),
|
await _handleRoomEvents(room, state, EventUpdateType.inviteState);
|
||||||
EventUpdateType.inviteState);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleEphemerals(String id, List<dynamic> events) async {
|
Future<void> _handleEphemerals(Room room, List<BasicRoomEvent> events) async {
|
||||||
for (final event in events) {
|
for (final event in events) {
|
||||||
await _handleEvent(event, id, EventUpdateType.ephemeral);
|
await _handleRoomEvents(room, [event], EventUpdateType.ephemeral);
|
||||||
|
|
||||||
// Receipt events are deltas between two states. We will create a
|
// Receipt events are deltas between two states. We will create a
|
||||||
// fake room account data event for this and store the difference
|
// fake room account data event for this and store the difference
|
||||||
// there.
|
// there.
|
||||||
if (event['type'] == 'm.receipt') {
|
if (event.type == 'm.receipt') {
|
||||||
var room = getRoomById(id);
|
|
||||||
room ??= Room(id: id, client: this);
|
|
||||||
|
|
||||||
final receiptStateContent =
|
final receiptStateContent =
|
||||||
room.roomAccountData['m.receipt']?.content ?? {};
|
room.roomAccountData['m.receipt']?.content ?? {};
|
||||||
for (final eventEntry in event['content'].entries) {
|
for (final eventEntry in event.content.entries) {
|
||||||
final String eventID = eventEntry.key;
|
final eventID = eventEntry.key;
|
||||||
if (event['content'][eventID]['m.read'] != null) {
|
if (event.content[eventID]['m.read'] != null) {
|
||||||
final Map<String, dynamic> userTimestampMap =
|
final Map<String, dynamic> userTimestampMap =
|
||||||
event['content'][eventID]['m.read'];
|
event.content[eventID]['m.read'];
|
||||||
for (final userTimestampMapEntry in userTimestampMap.entries) {
|
for (final userTimestampMapEntry in userTimestampMap.entries) {
|
||||||
final mxid = userTimestampMapEntry.key;
|
final mxid = userTimestampMapEntry.key;
|
||||||
|
|
||||||
|
|
@ -1783,48 +1782,48 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event['content'] = receiptStateContent;
|
event.content = receiptStateContent;
|
||||||
await _handleEvent(event, id, EventUpdateType.accountData);
|
await _handleRoomEvents(room, [event], EventUpdateType.accountData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleRoomEvents(
|
Future<void> _handleRoomEvents(
|
||||||
String chat_id, List<dynamic> events, EventUpdateType type) async {
|
Room room,
|
||||||
for (final event in events) {
|
List<BasicEvent> events,
|
||||||
await _handleEvent(event, chat_id, type);
|
EventUpdateType type,
|
||||||
}
|
) async {
|
||||||
}
|
// Calling events can be omitted if they are outdated from the same sync. So
|
||||||
|
// we collect them first before we handle them.
|
||||||
|
final callEvents = <Event>{};
|
||||||
|
|
||||||
Future<void> _handleEvent(
|
for (final event in events) {
|
||||||
Map<String, dynamic> event, String roomID, EventUpdateType type) async {
|
|
||||||
if (event['type'] is String && event['content'] is Map<String, dynamic>) {
|
|
||||||
// The client must ignore any new m.room.encryption event to prevent
|
// The client must ignore any new m.room.encryption event to prevent
|
||||||
// man-in-the-middle attacks!
|
// man-in-the-middle attacks!
|
||||||
final room = getRoomById(roomID);
|
if ((event.type == EventTypes.Encryption &&
|
||||||
if (room == null ||
|
room.encrypted &&
|
||||||
(event['type'] == EventTypes.Encryption &&
|
event.content['algorithm'] !=
|
||||||
room.encrypted &&
|
room.getState(EventTypes.Encryption)?.content['algorithm'])) {
|
||||||
event['content']['algorithm'] !=
|
|
||||||
room.getState(EventTypes.Encryption)?.content['algorithm'])) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var update = EventUpdate(roomID: roomID, type: type, content: event);
|
var update =
|
||||||
if (event['type'] == EventTypes.Encrypted && encryptionEnabled) {
|
EventUpdate(roomID: room.id, type: type, content: event.toJson());
|
||||||
|
if (event.type == EventTypes.Encrypted && encryptionEnabled) {
|
||||||
update = await update.decrypt(room);
|
update = await update.decrypt(room);
|
||||||
}
|
}
|
||||||
if (event['type'] == EventTypes.Message &&
|
if (event.type == EventTypes.Message &&
|
||||||
!room.isDirectChat &&
|
!room.isDirectChat &&
|
||||||
database != null &&
|
database != null &&
|
||||||
room.getState(EventTypes.RoomMember, event['sender']) == null) {
|
event is MatrixEvent &&
|
||||||
|
room.getState(EventTypes.RoomMember, event.senderId) == null) {
|
||||||
// In order to correctly render room list previews we need to fetch the member from the database
|
// In order to correctly render room list previews we need to fetch the member from the database
|
||||||
final user = await database?.getUser(event['sender'], room);
|
final user = await database?.getUser(event.senderId, room);
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
room.setState(user);
|
room.setState(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_updateRoomsByEventUpdate(update);
|
_updateRoomsByEventUpdate(room, update);
|
||||||
if (type != EventUpdateType.ephemeral) {
|
if (type != EventUpdateType.ephemeral) {
|
||||||
await database?.storeEventUpdate(update, this);
|
await database?.storeEventUpdate(update, this);
|
||||||
}
|
}
|
||||||
|
|
@ -1833,47 +1832,78 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
onEvent.add(update);
|
onEvent.add(update);
|
||||||
|
|
||||||
final rawUnencryptedEvent = update.content;
|
|
||||||
|
|
||||||
if (prevBatch != null && type == EventUpdateType.timeline) {
|
if (prevBatch != null && type == EventUpdateType.timeline) {
|
||||||
if (rawUnencryptedEvent['type'] == EventTypes.CallInvite) {
|
if (update.content.tryGet<String>('type')?.startsWith('m.call.') ??
|
||||||
onCallInvite.add(Event.fromJson(rawUnencryptedEvent, room));
|
false) {
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallHangup) {
|
final callEvent = Event.fromJson(update.content, room);
|
||||||
onCallHangup.add(Event.fromJson(rawUnencryptedEvent, room));
|
final callId = callEvent.content.tryGet<String>('call_id');
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallAnswer) {
|
callEvents.add(callEvent);
|
||||||
onCallAnswer.add(Event.fromJson(rawUnencryptedEvent, room));
|
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallCandidates) {
|
// Call Invites should be omitted for a call that is already answered,
|
||||||
onCallCandidates.add(Event.fromJson(rawUnencryptedEvent, room));
|
// has ended, is rejectd or replaced.
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallSelectAnswer) {
|
const callEndedEventTypes = {
|
||||||
onCallSelectAnswer.add(Event.fromJson(rawUnencryptedEvent, room));
|
EventTypes.CallAnswer,
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallReject) {
|
EventTypes.CallHangup,
|
||||||
onCallReject.add(Event.fromJson(rawUnencryptedEvent, room));
|
EventTypes.CallReject,
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallNegotiate) {
|
EventTypes.CallReplaces,
|
||||||
onCallNegotiate.add(Event.fromJson(rawUnencryptedEvent, room));
|
};
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.CallReplaces) {
|
const ommitWhenCallEndedTypes = {
|
||||||
onCallReplaces.add(Event.fromJson(rawUnencryptedEvent, room));
|
EventTypes.CallInvite,
|
||||||
} else if (rawUnencryptedEvent['type'] ==
|
EventTypes.CallCandidates,
|
||||||
EventTypes.CallAssertedIdentity ||
|
EventTypes.CallNegotiate,
|
||||||
rawUnencryptedEvent['type'] ==
|
EventTypes.CallSDPStreamMetadataChanged,
|
||||||
EventTypes.CallAssertedIdentityPrefix) {
|
EventTypes.CallSDPStreamMetadataChangedPrefix,
|
||||||
onAssertedIdentityReceived
|
};
|
||||||
.add(Event.fromJson(rawUnencryptedEvent, room));
|
|
||||||
} else if (rawUnencryptedEvent['type'] ==
|
if (callEndedEventTypes.contains(callEvent.type)) {
|
||||||
EventTypes.CallSDPStreamMetadataChanged ||
|
callEvents.removeWhere((event) {
|
||||||
rawUnencryptedEvent['type'] ==
|
if (ommitWhenCallEndedTypes.contains(event.type) &&
|
||||||
EventTypes.CallSDPStreamMetadataChangedPrefix) {
|
event.content.tryGet<String>('call_id') == callId) {
|
||||||
onSDPStreamMetadataChangedReceived
|
Logs().v(
|
||||||
.add(Event.fromJson(rawUnencryptedEvent, room));
|
'Ommit "${event.type}" event for an already terminated call');
|
||||||
// TODO(duan): Only used (org.matrix.msc3401.call) during the current test,
|
return true;
|
||||||
// need to add GroupCallPrefix in matrix_api_lite
|
}
|
||||||
} else if (rawUnencryptedEvent['type'] == EventTypes.GroupCallPrefix) {
|
return false;
|
||||||
onGroupCallRequest.add(Event.fromJson(rawUnencryptedEvent, room));
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
callEvents.forEach(_callStreamByCallEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) {
|
void _callStreamByCallEvent(Event event) {
|
||||||
|
if (event.type == EventTypes.CallInvite) {
|
||||||
|
onCallInvite.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallHangup) {
|
||||||
|
onCallHangup.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallAnswer) {
|
||||||
|
onCallAnswer.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallCandidates) {
|
||||||
|
onCallCandidates.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallSelectAnswer) {
|
||||||
|
onCallSelectAnswer.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallReject) {
|
||||||
|
onCallReject.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallNegotiate) {
|
||||||
|
onCallNegotiate.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallReplaces) {
|
||||||
|
onCallReplaces.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallAssertedIdentity ||
|
||||||
|
event.type == EventTypes.CallAssertedIdentityPrefix) {
|
||||||
|
onAssertedIdentityReceived.add(event);
|
||||||
|
} else if (event.type == EventTypes.CallSDPStreamMetadataChanged ||
|
||||||
|
event.type == EventTypes.CallSDPStreamMetadataChangedPrefix) {
|
||||||
|
onSDPStreamMetadataChangedReceived.add(event);
|
||||||
|
// TODO(duan): Only used (org.matrix.msc3401.call) during the current test,
|
||||||
|
// need to add GroupCallPrefix in matrix_api_lite
|
||||||
|
} else if (event.type == EventTypes.GroupCallPrefix) {
|
||||||
|
onGroupCallRequest.add(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Room _updateRoomsByRoomUpdate(String roomId, SyncRoomUpdate chatUpdate) {
|
||||||
// Update the chat list item.
|
// Update the chat list item.
|
||||||
// Search the room in the rooms
|
// Search the room in the rooms
|
||||||
final roomIndex = rooms.indexWhere((r) => r.id == roomId);
|
final roomIndex = rooms.indexWhere((r) => r.id == roomId);
|
||||||
|
|
@ -1884,24 +1914,27 @@ class Client extends MatrixApi {
|
||||||
? Membership.invite
|
? Membership.invite
|
||||||
: Membership.join;
|
: Membership.join;
|
||||||
|
|
||||||
|
final room = found
|
||||||
|
? rooms[roomIndex]
|
||||||
|
: (chatUpdate is JoinedRoomUpdate
|
||||||
|
? Room(
|
||||||
|
id: roomId,
|
||||||
|
membership: membership,
|
||||||
|
prev_batch: chatUpdate.timeline?.prevBatch,
|
||||||
|
highlightCount:
|
||||||
|
chatUpdate.unreadNotifications?.highlightCount ?? 0,
|
||||||
|
notificationCount:
|
||||||
|
chatUpdate.unreadNotifications?.notificationCount ?? 0,
|
||||||
|
summary: chatUpdate.summary,
|
||||||
|
client: this,
|
||||||
|
)
|
||||||
|
: Room(id: roomId, membership: membership, client: this));
|
||||||
|
|
||||||
// Does the chat already exist in the list rooms?
|
// Does the chat already exist in the list rooms?
|
||||||
if (!found && membership != Membership.leave) {
|
if (!found && membership != Membership.leave) {
|
||||||
final position = membership == Membership.invite ? 0 : rooms.length;
|
final position = membership == Membership.invite ? 0 : rooms.length;
|
||||||
// Add the new chat to the list
|
// Add the new chat to the list
|
||||||
final newRoom = chatUpdate is JoinedRoomUpdate
|
rooms.insert(position, room);
|
||||||
? Room(
|
|
||||||
id: roomId,
|
|
||||||
membership: membership,
|
|
||||||
prev_batch: chatUpdate.timeline?.prevBatch,
|
|
||||||
highlightCount:
|
|
||||||
chatUpdate.unreadNotifications?.highlightCount ?? 0,
|
|
||||||
notificationCount:
|
|
||||||
chatUpdate.unreadNotifications?.notificationCount ?? 0,
|
|
||||||
summary: chatUpdate.summary,
|
|
||||||
client: this,
|
|
||||||
)
|
|
||||||
: Room(id: roomId, membership: membership, client: this);
|
|
||||||
rooms.insert(position, newRoom);
|
|
||||||
}
|
}
|
||||||
// If the membership is "leave" then remove the item and stop here
|
// If the membership is "leave" then remove the item and stop here
|
||||||
else if (found && membership == Membership.leave) {
|
else if (found && membership == Membership.leave) {
|
||||||
|
|
@ -1940,14 +1973,12 @@ class Client extends MatrixApi {
|
||||||
runInRoot(rooms[roomIndex].requestHistory);
|
runInRoot(rooms[roomIndex].requestHistory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return room;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateRoomsByEventUpdate(EventUpdate eventUpdate) {
|
void _updateRoomsByEventUpdate(Room room, EventUpdate eventUpdate) {
|
||||||
if (eventUpdate.type == EventUpdateType.history) return;
|
if (eventUpdate.type == EventUpdateType.history) return;
|
||||||
|
|
||||||
final room = getRoomById(eventUpdate.roomID);
|
|
||||||
if (room == null) return;
|
|
||||||
|
|
||||||
switch (eventUpdate.type) {
|
switch (eventUpdate.type) {
|
||||||
case EventUpdateType.timeline:
|
case EventUpdateType.timeline:
|
||||||
case EventUpdateType.state:
|
case EventUpdateType.state:
|
||||||
|
|
|
||||||
|
|
@ -239,7 +239,7 @@ void main() {
|
||||||
|
|
||||||
final eventUpdateList = await eventUpdateListFuture;
|
final eventUpdateList = await eventUpdateListFuture;
|
||||||
|
|
||||||
expect(eventUpdateList.length, 14);
|
expect(eventUpdateList.length, 18);
|
||||||
|
|
||||||
expect(eventUpdateList[0].content['type'], 'm.room.member');
|
expect(eventUpdateList[0].content['type'], 'm.room.member');
|
||||||
expect(eventUpdateList[0].roomID, '!726s6s6q:example.com');
|
expect(eventUpdateList[0].roomID, '!726s6s6q:example.com');
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue