From add19c73a0110b5aacc9947e731e3b7a8037c06a Mon Sep 17 00:00:00 2001 From: Sorunome Date: Wed, 30 Dec 2020 12:47:27 +0100 Subject: [PATCH] fix: Load multiple olm sessions from the database at once for increased performance --- lib/encryption/olm_manager.dart | 43 ++++++++++++++++++++++++++------ lib/src/database/database.dart | 23 ----------------- lib/src/database/database.g.dart | 17 +++++++++++++ lib/src/database/database.moor | 1 + 4 files changed, 53 insertions(+), 31 deletions(-) diff --git a/lib/encryption/olm_manager.dart b/lib/encryption/olm_manager.dart index cdae41b4..fe89a30b 100644 --- a/lib/encryption/olm_manager.dart +++ b/lib/encryption/olm_manager.dart @@ -358,15 +358,40 @@ class OlmManager { return res; } - Future> getOlmSessions(String senderKey) async { + Future getOlmSessionsForDevicesFromDatabase( + List senderKeys) async { + if (client.database == null) { + return; + } + final rows = await client.database + .dbGetOlmSessionsForDevices(client.id, senderKeys) + .get(); + final res = >{}; + for (final row in rows) { + res[row.identityKey] ??= []; + final sess = OlmSession.fromDb(row, client.userID); + if (sess.isValid) { + res[row.identityKey].add(sess); + } + } + for (final entry in res.entries) { + _olmSessions[entry.key] = entry.value; + } + } + + Future> getOlmSessions(String senderKey, + {bool getFromDb = true}) async { var sess = olmSessions[senderKey]; - if (sess == null || sess.isEmpty) { + if ((getFromDb ?? true) && (sess == null || sess.isEmpty)) { final sessions = await getOlmSessionsFromDatabase(senderKey); if (sessions.isEmpty) { return []; } sess = _olmSessions[senderKey] = sessions; } + if (sess == null) { + return []; + } sess.sort((a, b) => a.lastReceived == b.lastReceived ? a.sessionId.compareTo(b.sessionId) : b.lastReceived.compareTo(a.lastReceived)); @@ -475,8 +500,10 @@ class OlmManager { } Future> encryptToDeviceMessagePayload( - DeviceKeys device, String type, Map payload) async { - final sess = await getOlmSessions(device.curve25519Key); + DeviceKeys device, String type, Map payload, + {bool getFromDb}) async { + final sess = + await getOlmSessions(device.curve25519Key, getFromDb: getFromDb); if (sess.isEmpty) { throw ('No olm session found for ${device.userId}:${device.deviceId}'); } @@ -509,9 +536,8 @@ class OlmManager { var data = >>{}; // first check if any of our sessions we want to encrypt for are in the database if (client.database != null) { - for (final device in deviceKeys) { - await getOlmSessions(device.curve25519Key); - } + await getOlmSessionsForDevicesFromDatabase( + deviceKeys.map((d) => d.curve25519Key).toList()); } final deviceKeysWithoutSession = List.from(deviceKeys); deviceKeysWithoutSession.removeWhere((DeviceKeys deviceKeys) => @@ -526,7 +552,8 @@ class OlmManager { } try { data[device.userId][device.deviceId] = - await encryptToDeviceMessagePayload(device, type, payload); + await encryptToDeviceMessagePayload(device, type, payload, + getFromDb: false); } catch (e, s) { Logs().w('[LibOlm] Error encrypting to-device event', e, s); continue; diff --git a/lib/src/database/database.dart b/lib/src/database/database.dart index fc2a58df..446bcb7e 100644 --- a/lib/src/database/database.dart +++ b/lib/src/database/database.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'package:moor/moor.dart'; -import 'package:olm/olm.dart' as olm; import '../../famedlysdk.dart' as sdk; import '../../matrix_api.dart' as api; @@ -197,28 +196,6 @@ class Database extends _$Database { return res; } - Future>> getOlmSessions( - int clientId, String userId) async { - final raw = await getAllOlmSessions(clientId).get(); - if (raw.isEmpty) { - return {}; - } - final res = >{}; - for (final row in raw) { - if (!res.containsKey(row.identityKey)) { - res[row.identityKey] = []; - } - try { - var session = olm.Session(); - session.unpickle(userId, row.pickle); - res[row.identityKey].add(session); - } catch (e, s) { - Logs().e('[LibOlm] Could not unpickle olm session', e, s); - } - } - return res; - } - Future getDbOutboundGroupSession( int clientId, String roomId) async { final res = await dbGetOutboundGroupSession(clientId, roomId).get(); diff --git a/lib/src/database/database.g.dart b/lib/src/database/database.g.dart index 5eecc674..4c04816e 100644 --- a/lib/src/database/database.g.dart +++ b/lib/src/database/database.g.dart @@ -6281,6 +6281,23 @@ abstract class _$Database extends GeneratedDatabase { }).map(olmSessions.mapFromRow); } + Selectable dbGetOlmSessionsForDevices( + int client_id, List identity_keys) { + var $arrayStartIndex = 2; + final expandedidentity_keys = + $expandVar($arrayStartIndex, identity_keys.length); + $arrayStartIndex += identity_keys.length; + return customSelect( + 'SELECT * FROM olm_sessions WHERE client_id = :client_id AND identity_key IN ($expandedidentity_keys)', + variables: [ + Variable.withInt(client_id), + for (var $ in identity_keys) Variable.withString($) + ], + readsFrom: { + olmSessions + }).map(olmSessions.mapFromRow); + } + Future storeOlmSession(int client_id, String identitiy_key, String session_id, String pickle, int last_received) { return customInsert( diff --git a/lib/src/database/database.moor b/lib/src/database/database.moor index 4bddbc90..c2d4e04b 100644 --- a/lib/src/database/database.moor +++ b/lib/src/database/database.moor @@ -183,6 +183,7 @@ getAllUserDeviceKeysKeys: SELECT * FROM user_device_keys_key WHERE client_id = : getAllUserCrossSigningKeys: SELECT * FROM user_cross_signing_keys WHERE client_id = :client_id; getAllOlmSessions: SELECT * FROM olm_sessions WHERE client_id = :client_id; dbGetOlmSessions: SELECT * FROM olm_sessions WHERE client_id = :client_id AND identity_key = :identity_key; +dbGetOlmSessionsForDevices: SELECT * FROM olm_sessions WHERE client_id = :client_id AND identity_key IN :identity_keys; storeOlmSession: INSERT OR REPLACE INTO olm_sessions (client_id, identity_key, session_id, pickle, last_received) VALUES (:client_id, :identitiy_key, :session_id, :pickle, :last_received); getAllOutboundGroupSessions: SELECT * FROM outbound_group_sessions WHERE client_id = :client_id; dbGetOutboundGroupSession: SELECT * FROM outbound_group_sessions WHERE client_id = :client_id AND room_id = :room_id;