diff --git a/lib/src/database/matrix_sdk_database.dart b/lib/src/database/matrix_sdk_database.dart index 5c1d4d7eb..3114d461b 100644 --- a/lib/src/database/matrix_sdk_database.dart +++ b/lib/src/database/matrix_sdk_database.dart @@ -19,6 +19,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:math'; +import 'dart:isolate'; import 'package:sqflite_common/sqflite.dart'; @@ -798,52 +799,28 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage { if (deviceKeysOutdated.isEmpty) { return {}; } - final res = {}; + final userDeviceKeys = await _userDeviceKeysBox.getAllValues(); final userCrossSigningKeys = await _userCrossSigningKeysBox.getAllValues(); - for (final userId in deviceKeysOutdated.keys) { - final deviceKeysBoxKeys = userDeviceKeys.keys.where((tuple) { - final tupleKey = TupleKey.fromString(tuple); - return tupleKey.parts.first == userId; - }); - final crossSigningKeysBoxKeys = - userCrossSigningKeys.keys.where((tuple) { - final tupleKey = TupleKey.fromString(tuple); - return tupleKey.parts.first == userId; - }); - final childEntries = deviceKeysBoxKeys.map( - (key) { - final userDeviceKey = userDeviceKeys[key]; - if (userDeviceKey == null) return null; - return copyMap(userDeviceKey); - }, - ); - final crossSigningEntries = crossSigningKeysBoxKeys.map( - (key) { - final crossSigningKey = userCrossSigningKeys[key]; - if (crossSigningKey == null) return null; - return copyMap(crossSigningKey); - }, - ); - res[userId] = DeviceKeysList.fromDbJson( - { - 'client_id': client.id, - 'user_id': userId, - 'outdated': deviceKeysOutdated[userId], - }, - childEntries - .where((c) => c != null) - .toList() - .cast>(), - crossSigningEntries - .where((c) => c != null) - .toList() - .cast>(), - client, - ); - } - return res; + + final result = await _runParseUserDeviceKeys( + client.id, + deviceKeysOutdated, + userDeviceKeys, + userCrossSigningKeys, + ); + return result.map( + (userId, json) => MapEntry( + userId, + DeviceKeysList.fromDbJson( + json['meta'] as Map, + (json['devices'] as List).cast>(), + (json['crossSigning'] as List).cast>(), + client, + ), + ), + ); }); @override @@ -1913,3 +1890,83 @@ class TupleKey { @override int get hashCode => Object.hashAll(parts); } + +Future>> _runParseUserDeviceKeys( + dynamic clientId, + Map deviceKeysOutdated, + Map userDeviceKeys, + Map userCrossSigningKeys, +) async { + final payload = { + 'clientId': clientId, + 'deviceKeysOutdated': Map.from(deviceKeysOutdated), + 'userDeviceKeys': Map.from(userDeviceKeys), + 'userCrossSigningKeys': Map.from(userCrossSigningKeys), + }; + return Isolate.run(() => _parseUserDeviceKeys(payload)); +} + +Map> _parseUserDeviceKeys( + Map payload, +) { + final deviceKeysOutdated = + payload['deviceKeysOutdated'] as Map; + final userDeviceKeys = payload['userDeviceKeys'] as Map; + final userCrossSigningKeys = + payload['userCrossSigningKeys'] as Map; + final clientId = payload['clientId']; + + Map inlineCopyMap(Map map) { + return map.map((k, v) { + if (v is Map) return MapEntry(k, inlineCopyMap(v)); + if (v is List) return MapEntry(k, List.from(v)); + return MapEntry(k, v); + }); + } + + final res = >{}; + + for (final userId in deviceKeysOutdated.keys) { + final deviceKeysBoxKeys = userDeviceKeys.keys.where((tuple) { + final parts = tuple.split('\u0000'); + return parts.isNotEmpty && parts.first == userId; + }); + + final crossSigningKeysBoxKeys = userCrossSigningKeys.keys.where((tuple) { + final parts = tuple.split('\u0000'); + return parts.isNotEmpty && parts.first == userId; + }); + + final childEntries = deviceKeysBoxKeys + .map((key) { + final userDeviceKey = userDeviceKeys[key]; + if (userDeviceKey == null) return null; + return inlineCopyMap(userDeviceKey as Map); + }) + .where((c) => c != null) + .toList() + .cast>(); + + final crossSigningEntries = crossSigningKeysBoxKeys + .map((key) { + final crossSigningKey = userCrossSigningKeys[key]; + if (crossSigningKey == null) return null; + return inlineCopyMap(crossSigningKey as Map); + }) + .where((c) => c != null) + .toList() + .cast>(); + + res[userId] = { + 'meta': { + 'client_id': clientId, + 'user_id': userId, + 'outdated': deviceKeysOutdated[userId], + }, + 'devices': childEntries, + 'crossSigning': crossSigningEntries, + }; + } + + return res; +}