refactor: (BREAKING) Make database required

This commit is contained in:
Christian Kußowski 2025-05-14 14:35:19 +02:00
parent 9af1c563f1
commit c618baae70
No known key found for this signature in database
GPG Key ID: E067ECD60F1A0652
32 changed files with 522 additions and 419 deletions

View File

@ -16,11 +16,30 @@ In your `pubspec.yaml` file add the following dependencies:
## Step 2: Create the client ## Step 2: Create the client
```dart ```dart
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:matrix/matrix.dart';
final client = Client( final client = Client(
'<Your Client Name>', '<Client Name>',
databaseBuilder: (client) => MatrixSdkDatabase( database: await MatrixSdkDatabase.init(
'<Database Name>', '<Database Name>',
database: await openDatabase('<path-to-store-database>'), database: await databaseFactoryFfi.openDatabase(':memory:'),
sqfliteFactory: databaseFactoryFfi,
),
);
```
### Alternative: Create a persistent database with SQFlite:
```dart
import 'package:sqflite/sqflite.dart';
import 'package:matrix/matrix.dart';
final client = Client(
'<Client Name>',
database: await MatrixSdkDatabase.init(
'<Database Name>',
database: await openDatabase('/path/to/database.sqlite'),
), ),
); );
``` ```

View File

@ -7,18 +7,18 @@ import 'package:sqflite/sqflite.dart' as sqlite;
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
// Build the database
final dbDirectory = await getApplicationSupportDirectory();
final client = Client( final client = Client(
'Matrix Example Chat', 'Matrix Example Chat',
databaseBuilder: (_) async { database: await MatrixSdkDatabase.init(
final dir = await getApplicationSupportDirectory(); c.name,
final db = MatrixSdkDatabase( database:
c.name, await sqlite.openDatabase(directory.toString() + '/database.sqlite'),
await sqlite.openDatabase(dir.toString() + '/database.sqlite'), ),
);
await db.open();
return db;
},
); );
await client.init(); await client.init();
runApp(MatrixExampleChat(client: client)); runApp(MatrixExampleChat(client: client));
} }

View File

@ -246,7 +246,7 @@ class Encryption {
// it un-awaited here, nothing happens, which is exactly the result we want // it un-awaited here, nothing happens, which is exactly the result we want
client.database client.database
// ignore: discarded_futures // ignore: discarded_futures
?.updateInboundGroupSessionIndexes( .updateInboundGroupSessionIndexes(
json.encode(inboundGroupSession.indexes), json.encode(inboundGroupSession.indexes),
event.room.id, event.room.id,
sessionId, sessionId,
@ -319,8 +319,7 @@ class Encryption {
} }
final content = event.parsedRoomEncryptedContent; final content = event.parsedRoomEncryptedContent;
final sessionId = content.sessionId; final sessionId = content.sessionId;
if (client.database != null && if (sessionId != null &&
sessionId != null &&
!(keyManager !(keyManager
.getInboundGroupSession( .getInboundGroupSession(
event.room.id, event.room.id,
@ -347,7 +346,7 @@ class Encryption {
if (updateType != EventUpdateType.history) { if (updateType != EventUpdateType.history) {
event.room.setState(event); event.room.setState(event);
} }
await client.database?.storeEventUpdate( await client.database.storeEventUpdate(
event.room.id, event.room.id,
event, event,
updateType, updateType,
@ -429,8 +428,7 @@ class Encryption {
// check if we can set our own master key as verified, if it isn't yet // check if we can set our own master key as verified, if it isn't yet
final userId = client.userID; final userId = client.userID;
final masterKey = client.userDeviceKeys[userId]?.masterKey; final masterKey = client.userDeviceKeys[userId]?.masterKey;
if (client.database != null && if (masterKey != null &&
masterKey != null &&
userId != null && userId != null &&
!masterKey.directVerified && !masterKey.directVerified &&
masterKey.hasValidSignatureChain(onlyValidateUserIds: {userId})) { masterKey.hasValidSignatureChain(onlyValidateUserIds: {userId})) {

View File

@ -166,7 +166,7 @@ class KeyManager {
} }
final storeFuture = client.database final storeFuture = client.database
?.storeInboundGroupSession( .storeInboundGroupSession(
roomId, roomId,
sessionId, sessionId,
inboundGroupSession.pickle(userId), inboundGroupSession.pickle(userId),
@ -182,7 +182,7 @@ class KeyManager {
} }
if (uploaded) { if (uploaded) {
await client.database await client.database
?.markInboundGroupSessionAsUploaded(roomId, sessionId); .markInboundGroupSessionAsUploaded(roomId, sessionId);
} }
}); });
final room = client.getRoomById(roomId); final room = client.getRoomById(roomId);
@ -198,7 +198,7 @@ class KeyManager {
room.lastEvent = decrypted; room.lastEvent = decrypted;
// To persist it in database and trigger UI updates: // To persist it in database and trigger UI updates:
await client.database?.transaction(() async { await client.database.transaction(() async {
await client.handleSync( await client.handleSync(
SyncUpdate( SyncUpdate(
nextBatch: '', nextBatch: '',
@ -222,7 +222,7 @@ class KeyManager {
room.onSessionKeyReceived.add(sessionId); room.onSessionKeyReceived.add(sessionId);
} }
return storeFuture ?? Future.value(); return storeFuture;
} }
SessionKey? getInboundGroupSession(String roomId, String sessionId) { SessionKey? getInboundGroupSession(String roomId, String sessionId) {
@ -277,7 +277,7 @@ class KeyManager {
return sess; // nothing to do return sess; // nothing to do
} }
final session = final session =
await client.database?.getInboundGroupSession(roomId, sessionId); await client.database.getInboundGroupSession(roomId, sessionId);
if (session == null) return null; if (session == null) return null;
final userID = client.userID; final userID = client.userID;
if (userID == null) return null; if (userID == null) return null;
@ -455,7 +455,7 @@ class KeyManager {
sess.outboundGroupSession!.message_index(); sess.outboundGroupSession!.message_index();
} }
} }
await client.database?.updateInboundGroupSessionAllowedAtIndex( await client.database.updateInboundGroupSessionAllowedAtIndex(
json.encode(inboundSess!.allowedAtIndex), json.encode(inboundSess!.allowedAtIndex),
room.id, room.id,
sess.outboundGroupSession!.session_id(), sess.outboundGroupSession!.session_id(),
@ -479,7 +479,7 @@ class KeyManager {
} }
sess.dispose(); sess.dispose();
_outboundGroupSessions.remove(roomId); _outboundGroupSessions.remove(roomId);
await client.database?.removeOutboundGroupSession(roomId); await client.database.removeOutboundGroupSession(roomId);
return true; return true;
} }
@ -490,7 +490,7 @@ class KeyManager {
) async { ) async {
final userID = client.userID; final userID = client.userID;
if (userID == null) return; if (userID == null) return;
await client.database?.storeOutboundGroupSession( await client.database.storeOutboundGroupSession(
roomId, roomId,
sess.outboundGroupSession!.pickle(userID), sess.outboundGroupSession!.pickle(userID),
json.encode(sess.devices), json.encode(sess.devices),
@ -621,7 +621,6 @@ class KeyManager {
final userID = client.userID; final userID = client.userID;
if (_loadedOutboundGroupSessions.contains(roomId) || if (_loadedOutboundGroupSessions.contains(roomId) ||
_outboundGroupSessions.containsKey(roomId) || _outboundGroupSessions.containsKey(roomId) ||
database == null ||
userID == null) { userID == null) {
return; // nothing to do return; // nothing to do
} }
@ -847,7 +846,7 @@ class KeyManager {
}) async { }) async {
final database = client.database; final database = client.database;
final userID = client.userID; final userID = client.userID;
if (database == null || userID == null) { if (userID == null) {
return; return;
} }

View File

@ -68,7 +68,7 @@ class SSSS {
// for testing // for testing
Future<void> clearCache() async { Future<void> clearCache() async {
await client.database?.clearSSSSCache(); await client.database.clearSSSSCache();
_cache.clear(); _cache.clear();
} }
@ -301,10 +301,6 @@ class SSSS {
client.accountData[type]?.content['encrypted'] is Map; client.accountData[type]?.content['encrypted'] is Map;
Future<String?> getCached(String type) async { Future<String?> getCached(String type) async {
if (client.database == null) {
return null;
}
// check if it is still valid
final keys = keyIdsFromType(type); final keys = keyIdsFromType(type);
if (keys == null) { if (keys == null) {
return null; return null;
@ -323,7 +319,7 @@ class SSSS {
if (fromCache != null && isValid(fromCache)) { if (fromCache != null && isValid(fromCache)) {
return fromCache.content; return fromCache.content;
} }
final ret = await client.database?.getSSSSCache(type); final ret = await client.database.getSSSSCache(type);
if (ret == null) { if (ret == null) {
return null; return null;
} }
@ -361,7 +357,7 @@ class SSSS {
); );
final decrypted = await decryptAes(encryptInfo, key, type); final decrypted = await decryptAes(encryptInfo, key, type);
final db = client.database; final db = client.database;
if (cacheTypes.contains(type) && db != null) { if (cacheTypes.contains(type)) {
// cache the thing // cache the thing
await db.storeSSSSCache(type, keyId, ciphertext, decrypted); await db.storeSSSSCache(type, keyId, ciphertext, decrypted);
onSecretStored.add(keyId); onSecretStored.add(keyId);
@ -398,7 +394,7 @@ class SSSS {
// store the thing in your account data // store the thing in your account data
await client.setAccountData(client.userID!, type, content); await client.setAccountData(client.userID!, type, content);
final db = client.database; final db = client.database;
if (cacheTypes.contains(type) && db != null) { if (cacheTypes.contains(type)) {
// cache the thing // cache the thing
await db.storeSSSSCache(type, keyId, encrypted.ciphertext, secret); await db.storeSSSSCache(type, keyId, encrypted.ciphertext, secret);
onSecretStored.add(keyId); onSecretStored.add(keyId);
@ -444,7 +440,7 @@ class SSSS {
if (ciphertext == null) { if (ciphertext == null) {
throw Exception('Wrong type for ciphertext!'); throw Exception('Wrong type for ciphertext!');
} }
await client.database?.storeSSSSCache(type, keyId, ciphertext, secret); await client.database.storeSSSSCache(type, keyId, ciphertext, secret);
onSecretStored.add(keyId); onSecretStored.add(keyId);
} }
} }
@ -611,23 +607,21 @@ class SSSS {
} }
Logs().i('[SSSS] Secret for type ${request.type} is ok, storing it'); Logs().i('[SSSS] Secret for type ${request.type} is ok, storing it');
final db = client.database; final db = client.database;
if (db != null) { final keyId = keyIdFromType(request.type);
final keyId = keyIdFromType(request.type); if (keyId != null) {
if (keyId != null) { final ciphertext = (client.accountData[request.type]!.content
final ciphertext = (client.accountData[request.type]!.content .tryGetMap<String, Object?>('encrypted'))
.tryGetMap<String, Object?>('encrypted')) ?.tryGetMap<String, Object?>(keyId)
?.tryGetMap<String, Object?>(keyId) ?.tryGet<String>('ciphertext');
?.tryGet<String>('ciphertext'); if (ciphertext == null) {
if (ciphertext == null) { Logs().i('[SSSS] Ciphertext is empty or not a String');
Logs().i('[SSSS] Ciphertext is empty or not a String'); return;
return;
}
await db.storeSSSSCache(request.type, keyId, ciphertext, secret);
if (_cacheCallbacks.containsKey(request.type)) {
_cacheCallbacks[request.type]!(secret);
}
onSecretStored.add(keyId);
} }
await db.storeSSSSCache(request.type, keyId, ciphertext, secret);
if (_cacheCallbacks.containsKey(request.type)) {
_cacheCallbacks[request.type]!(secret);
}
onSecretStored.add(keyId);
} }
} }
} }

View File

@ -583,7 +583,7 @@ class Bootstrap {
Logs().v( Logs().v(
'And finally set all megolm keys as needing to be uploaded again...', 'And finally set all megolm keys as needing to be uploaded again...',
); );
await client.database?.markInboundGroupSessionsAsNeedingUpload(); await client.database.markInboundGroupSessionsAsNeedingUpload();
Logs().v('And uploading keys...'); Logs().v('And uploading keys...');
await client.encryption?.keyManager.uploadInboundGroupSessions(); await client.encryption?.keyManager.uploadInboundGroupSessions();
} catch (e, s) { } catch (e, s) {

View File

@ -225,7 +225,7 @@ class FakeMatrixApi extends BaseClient {
accountData: [sdk.BasicEvent(content: decodeJson(data), type: type)], accountData: [sdk.BasicEvent(content: decodeJson(data), type: type)],
); );
if (_client?.database != null) { if (_client?.database != null) {
await _client?.database?.transaction(() async { await _client?.database.transaction(() async {
await _client?.handleSync(syncUpdate); await _client?.handleSync(syncUpdate);
}); });
} else { } else {
@ -255,7 +255,7 @@ class FakeMatrixApi extends BaseClient {
), ),
); );
if (_client?.database != null) { if (_client?.database != null) {
await _client?.database?.transaction(() async { await _client?.database.transaction(() async {
await _client?.handleSync(syncUpdate); await _client?.handleSync(syncUpdate);
}); });
} else { } else {

View File

@ -110,9 +110,8 @@ extension TimelineExportExtension on Timeline {
} }
// From the database // From the database
final eventsFromStore = await room.client.database final eventsFromStore =
?.getEventList(room, start: events.length) ?? await room.client.database.getEventList(room, start: events.length);
[];
if (eventsFromStore.isNotEmpty) { if (eventsFromStore.isNotEmpty) {
if (until == null || if (until == null ||
eventsFromStore.last.originServerTs.isBefore(until)) { eventsFromStore.last.originServerTs.isBefore(until)) {

View File

@ -67,11 +67,9 @@ class Client extends MatrixApi {
int? get id => _id; int? get id => _id;
final FutureOr<DatabaseApi> Function(Client)? databaseBuilder;
final FutureOr<DatabaseApi> Function(Client)? legacyDatabaseBuilder; final FutureOr<DatabaseApi> Function(Client)? legacyDatabaseBuilder;
DatabaseApi? _database;
DatabaseApi? get database => _database; final DatabaseApi database;
Encryption? get encryption => _encryption; Encryption? get encryption => _encryption;
Encryption? _encryption; Encryption? _encryption;
@ -141,7 +139,6 @@ class Client extends MatrixApi {
set homeserver(Uri? homeserver) { set homeserver(Uri? homeserver) {
if (this.homeserver != null && homeserver?.host != this.homeserver?.host) { if (this.homeserver != null && homeserver?.host != this.homeserver?.host) {
_wellKnown = null; _wellKnown = null;
unawaited(database?.storeWellKnown(null));
} }
super.homeserver = homeserver; super.homeserver = homeserver;
} }
@ -192,7 +189,7 @@ class Client extends MatrixApi {
/// Set [enableDehydratedDevices] to enable experimental support for enabling MSC3814 dehydrated devices. /// Set [enableDehydratedDevices] to enable experimental support for enabling MSC3814 dehydrated devices.
Client( Client(
this.clientName, { this.clientName, {
this.databaseBuilder, required this.database,
this.legacyDatabaseBuilder, this.legacyDatabaseBuilder,
Set<KeyVerificationMethod>? verificationMethods, Set<KeyVerificationMethod>? verificationMethods,
http.Client? httpClient, http.Client? httpClient,
@ -295,7 +292,7 @@ class Client extends MatrixApi {
/// Throws an Exception if there is no refresh token available or the /// Throws an Exception if there is no refresh token available or the
/// client is not logged in. /// client is not logged in.
Future<void> refreshAccessToken() async { Future<void> refreshAccessToken() async {
final storedClient = await database?.getClient(clientName); final storedClient = await database.getClient(clientName);
final refreshToken = storedClient?.tryGet<String>('refresh_token'); final refreshToken = storedClient?.tryGet<String>('refresh_token');
if (refreshToken == null) { if (refreshToken == null) {
throw Exception('No refresh token available'); throw Exception('No refresh token available');
@ -318,7 +315,7 @@ class Client extends MatrixApi {
? null ? null
: DateTime.now().add(Duration(milliseconds: expiresInMs)); : DateTime.now().add(Duration(milliseconds: expiresInMs));
_accessTokenExpiresAt = tokenExpiresAt; _accessTokenExpiresAt = tokenExpiresAt;
await database?.updateClient( await database.updateClient(
homeserverUrl, homeserverUrl,
tokenResponse.accessToken, tokenResponse.accessToken,
tokenExpiresAt, tokenExpiresAt,
@ -596,7 +593,7 @@ class Client extends MatrixApi {
// do not reset the well known here, so super call // do not reset the well known here, so super call
super.homeserver = wellKnown.mHomeserver.baseUrl.stripTrailingSlash(); super.homeserver = wellKnown.mHomeserver.baseUrl.stripTrailingSlash();
_wellKnown = wellKnown; _wellKnown = wellKnown;
await database?.storeWellKnown(wellKnown); await database.storeWellKnown(wellKnown);
return wellKnown; return wellKnown;
} }
@ -1060,7 +1057,7 @@ class Client extends MatrixApi {
Duration timeout = const Duration(seconds: 30), Duration timeout = const Duration(seconds: 30),
Duration maxCacheAge = const Duration(days: 1), Duration maxCacheAge = const Duration(days: 1),
}) async { }) async {
final cachedProfile = await database?.getUserProfile(userId); final cachedProfile = await database.getUserProfile(userId);
if (cachedProfile != null && if (cachedProfile != null &&
!cachedProfile.outdated && !cachedProfile.outdated &&
DateTime.now().difference(cachedProfile.updated) < maxCacheAge) { DateTime.now().difference(cachedProfile.updated) < maxCacheAge) {
@ -1085,7 +1082,7 @@ class Client extends MatrixApi {
updated: DateTime.now(), updated: DateTime.now(),
); );
await database?.storeUserProfile(userId, newCachedProfile); await database.storeUserProfile(userId, newCachedProfile);
return newCachedProfile; return newCachedProfile;
} }
@ -1540,7 +1537,7 @@ class Client extends MatrixApi {
.uploadContent(file, filename: filename, contentType: contentType); .uploadContent(file, filename: filename, contentType: contentType);
final database = this.database; final database = this.database;
if (database != null && file.length <= database.maxFileSize) { if (file.length <= database.maxFileSize) {
await database.storeFile( await database.storeFile(
mxc, mxc,
file, file,
@ -1572,16 +1569,13 @@ class Client extends MatrixApi {
/// ///
/// This can be useful to migrate a session from one device to a future one. /// This can be useful to migrate a session from one device to a future one.
Future<String?> exportDump() async { Future<String?> exportDump() async {
if (database != null) { await abortSync();
await abortSync(); await dispose(closeDatabase: false);
await dispose(closeDatabase: false);
final export = await database!.exportDump(); final export = await database.exportDump();
await clear(); await clear();
return export; return export;
}
return null;
} }
/// imports a dumped session /// imports a dumped session
@ -1595,9 +1589,7 @@ class Client extends MatrixApi {
// Client was probably not initialized yet. // Client was probably not initialized yet.
} }
_database ??= await databaseBuilder!.call(this); final success = await database.importDump(export);
final success = await database!.importDump(export);
if (success) { if (success) {
// closing including DB // closing including DB
@ -1790,13 +1782,7 @@ class Client extends MatrixApi {
bool returnNullIfSeen = true, bool returnNullIfSeen = true,
}) async { }) async {
// Get access token if necessary: // Get access token if necessary:
final database = _database ??= await databaseBuilder?.call(this);
if (!isLogged()) { if (!isLogged()) {
if (database == null) {
throw Exception(
'Can not execute getEventByPushNotification() without a database',
);
}
final clientInfoMap = await database.getClient(clientName); final clientInfoMap = await database.getClient(clientName);
final token = clientInfoMap?.tryGet<String>('token'); final token = clientInfoMap?.tryGet<String>('token');
if (token == null) { if (token == null) {
@ -1814,7 +1800,7 @@ class Client extends MatrixApi {
// Create the room object: // Create the room object:
final room = getRoomById(roomId) ?? final room = getRoomById(roomId) ??
await database?.getSingleRoom(this, roomId) ?? await database.getSingleRoom(this, roomId) ??
Room( Room(
id: roomId, id: roomId,
client: this, client: this,
@ -1864,7 +1850,7 @@ class Client extends MatrixApi {
); );
} }
matrixEvent ??= await database matrixEvent ??= await database
?.getEventById(eventId, room) .getEventById(eventId, room)
.timeout(timeoutForServerRequests); .timeout(timeoutForServerRequests);
try { try {
@ -1893,7 +1879,7 @@ class Client extends MatrixApi {
return null; return null;
} }
final readMarkerEvent = await database final readMarkerEvent = await database
?.getEventById(room.fullyRead, room) .getEventById(room.fullyRead, room)
.timeout(timeoutForServerRequests); .timeout(timeoutForServerRequests);
if (readMarkerEvent != null && if (readMarkerEvent != null &&
readMarkerEvent.originServerTs.isAfter( readMarkerEvent.originServerTs.isAfter(
@ -1940,7 +1926,7 @@ class Client extends MatrixApi {
} }
if (storeInDatabase) { if (storeInDatabase) {
await database?.transaction(() async { await database.transaction(() async {
await database.storeEventUpdate( await database.storeEventUpdate(
roomId, roomId,
event, event,
@ -2020,14 +2006,6 @@ class Client extends MatrixApi {
); );
} }
final databaseBuilder = this.databaseBuilder;
if (databaseBuilder != null) {
_database ??= await runBenchmarked<DatabaseApi>(
'Build database',
() async => await databaseBuilder(this),
);
}
_groupCallSessionId = randomAlpha(12); _groupCallSessionId = randomAlpha(12);
/// while I would like to move these to a onLoginStateChanged stream listener /// while I would like to move these to a onLoginStateChanged stream listener
@ -2036,7 +2014,7 @@ class Client extends MatrixApi {
_serverConfigCache.invalidate(); _serverConfigCache.invalidate();
_versionsCache.invalidate(); _versionsCache.invalidate();
final account = await this.database?.getClient(clientName); final account = await database.getClient(clientName);
newRefreshToken ??= account?.tryGet<String>('refresh_token'); newRefreshToken ??= account?.tryGet<String>('refresh_token');
// can have discovery_information so make sure it also has the proper // can have discovery_information so make sure it also has the proper
// account creds // account creds
@ -2081,7 +2059,7 @@ class Client extends MatrixApi {
if (onLoginStateChanged.value == LoginState.softLoggedOut) { if (onLoginStateChanged.value == LoginState.softLoggedOut) {
if (newRefreshToken != null && accessToken != null && userID != null) { if (newRefreshToken != null && accessToken != null && userID != null) {
// Store the new tokens: // Store the new tokens:
await _database?.updateClient( await database.updateClient(
homeserver.toString(), homeserver.toString(),
accessToken, accessToken,
accessTokenExpiresAt, accessTokenExpiresAt,
@ -2133,58 +2111,56 @@ class Client extends MatrixApi {
onInitStateChanged?.call(InitState.settingUpEncryption); onInitStateChanged?.call(InitState.settingUpEncryption);
await encryption?.init(olmAccount); await encryption?.init(olmAccount);
final database = this.database; if (id != null) {
if (database != null) { await database.updateClient(
if (id != null) { homeserver.toString(),
await database.updateClient( accessToken,
homeserver.toString(), accessTokenExpiresAt,
accessToken, newRefreshToken,
accessTokenExpiresAt, userID,
newRefreshToken, _deviceID,
userID, _deviceName,
_deviceID, prevBatch,
_deviceName, encryption?.pickledOlmAccount,
prevBatch, );
encryption?.pickledOlmAccount, } else {
); _id = await database.insertClient(
} else { clientName,
_id = await database.insertClient( homeserver.toString(),
clientName, accessToken,
homeserver.toString(), accessTokenExpiresAt,
accessToken, newRefreshToken,
accessTokenExpiresAt, userID,
newRefreshToken, _deviceID,
userID, _deviceName,
_deviceID, prevBatch,
_deviceName, encryption?.pickledOlmAccount,
prevBatch, );
encryption?.pickledOlmAccount,
);
}
userDeviceKeysLoading = database
.getUserDeviceKeys(this)
.then((keys) => _userDeviceKeys = keys);
roomsLoading = database.getRoomList(this).then((rooms) {
_rooms = rooms;
_sortRooms();
});
_accountDataLoading = database.getAccountData().then((data) {
_accountData = data;
_updatePushrules();
});
_discoveryDataLoading = database.getWellKnown().then((data) {
_wellKnown = data;
});
// ignore: deprecated_member_use_from_same_package
presences.clear();
if (waitUntilLoadCompletedLoaded) {
onInitStateChanged?.call(InitState.loadingData);
await userDeviceKeysLoading;
await roomsLoading;
await _accountDataLoading;
await _discoveryDataLoading;
}
} }
userDeviceKeysLoading = database
.getUserDeviceKeys(this)
.then((keys) => _userDeviceKeys = keys);
roomsLoading = database.getRoomList(this).then((rooms) {
_rooms = rooms;
_sortRooms();
});
_accountDataLoading = database.getAccountData().then((data) {
_accountData = data;
_updatePushrules();
});
_discoveryDataLoading = database.getWellKnown().then((data) {
_wellKnown = data;
});
// ignore: deprecated_member_use_from_same_package
presences.clear();
if (waitUntilLoadCompletedLoaded) {
onInitStateChanged?.call(InitState.loadingData);
await userDeviceKeysLoading;
await roomsLoading;
await _accountDataLoading;
await _discoveryDataLoading;
}
_initLock = false; _initLock = false;
onLoginStateChanged.add(LoginState.loggedIn); onLoginStateChanged.add(LoginState.loggedIn);
Logs().i( Logs().i(
@ -2238,15 +2214,15 @@ class Client extends MatrixApi {
} }
try { try {
await abortSync(); await abortSync();
await database?.clear(); await database.clear();
await legacyDatabase?.clear(); await legacyDatabase?.clear();
_backgroundSync = true; _backgroundSync = true;
} catch (e, s) { } catch (e, s) {
Logs().e('Unable to clear database', e, s); Logs().e('Unable to clear database', e, s);
} finally { } finally {
await database?.delete(); await database.delete();
await legacyDatabase?.delete(); await legacyDatabase?.delete();
_database = null; await dispose();
} }
_id = accessToken = _syncFilterId = _id = accessToken = _syncFilterId =
@ -2303,7 +2279,7 @@ class Client extends MatrixApi {
if (syncFilterId == null && userID != null) { if (syncFilterId == null && userID != null) {
final syncFilterId = final syncFilterId =
_syncFilterId = await defineFilter(userID, syncFilter); _syncFilterId = await defineFilter(userID, syncFilter);
await database?.storeSyncFilterId(syncFilterId); await database.storeSyncFilterId(syncFilterId);
} }
return; return;
} }
@ -2405,29 +2381,25 @@ class Client extends MatrixApi {
} }
final database = this.database; final database = this.database;
if (database != null) { await userDeviceKeysLoading;
await userDeviceKeysLoading; await roomsLoading;
await roomsLoading; await _accountDataLoading;
await _accountDataLoading; _currentTransaction = database.transaction(() async {
_currentTransaction = database.transaction(() async {
await _handleSync(syncResp, direction: Direction.f);
if (prevBatch != syncResp.nextBatch) {
await database.storePrevBatch(syncResp.nextBatch);
}
});
await runBenchmarked(
'Process sync',
() async => await _currentTransaction,
syncResp.itemCount,
);
} else {
await _handleSync(syncResp, direction: Direction.f); await _handleSync(syncResp, direction: Direction.f);
} if (prevBatch != syncResp.nextBatch) {
await database.storePrevBatch(syncResp.nextBatch);
}
});
await runBenchmarked(
'Process sync',
() async => await _currentTransaction,
syncResp.itemCount,
);
if (_disposed || _aborted) return; if (_disposed || _aborted) return;
_prevBatch = syncResp.nextBatch; _prevBatch = syncResp.nextBatch;
onSyncStatus.add(SyncStatusUpdate(SyncStatus.cleaningUp)); onSyncStatus.add(SyncStatusUpdate(SyncStatus.cleaningUp));
// ignore: unawaited_futures // ignore: unawaited_futures
database?.deleteOldFiles( database.deleteOldFiles(
DateTime.now().subtract(Duration(days: 30)).millisecondsSinceEpoch, DateTime.now().subtract(Duration(days: 30)).millisecondsSinceEpoch,
); );
await updateUserDeviceKeys(); await updateUserDeviceKeys();
@ -2523,10 +2495,10 @@ class Client extends MatrixApi {
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
onPresence.add(newPresence); onPresence.add(newPresence);
onPresenceChanged.add(cachedPresence); onPresenceChanged.add(cachedPresence);
await database?.storePresence(newPresence.senderId, cachedPresence); await database.storePresence(newPresence.senderId, cachedPresence);
} }
for (final newAccountData in sync.accountData ?? <BasicEvent>[]) { for (final newAccountData in sync.accountData ?? <BasicEvent>[]) {
await database?.storeAccountData( await database.storeAccountData(
newAccountData.type, newAccountData.type,
newAccountData.content, newAccountData.content,
); );
@ -2559,7 +2531,7 @@ class Client extends MatrixApi {
final userKeys = _userDeviceKeys[userId]; final userKeys = _userDeviceKeys[userId];
if (userKeys != null) { if (userKeys != null) {
userKeys.outdated = true; userKeys.outdated = true;
await database?.storeUserDeviceKeysInfo(userId, true); await database.storeUserDeviceKeysInfo(userId, true);
} }
} }
for (final userId in deviceLists.left ?? []) { for (final userId in deviceLists.left ?? []) {
@ -2663,7 +2635,7 @@ class Client extends MatrixApi {
// removed from the database! // removed from the database!
if (syncRoomUpdate is JoinedRoomUpdate && if (syncRoomUpdate is JoinedRoomUpdate &&
syncRoomUpdate.timeline?.limited == true) { syncRoomUpdate.timeline?.limited == true) {
await database?.deleteTimelineForRoom(id); await database.deleteTimelineForRoom(id);
} }
final room = await _updateRoomsByRoomUpdate(id, syncRoomUpdate); final room = await _updateRoomsByRoomUpdate(id, syncRoomUpdate);
@ -2722,7 +2694,7 @@ class Client extends MatrixApi {
final accountData = syncRoomUpdate.accountData; final accountData = syncRoomUpdate.accountData;
if (accountData != null && accountData.isNotEmpty) { if (accountData != null && accountData.isNotEmpty) {
for (final event in accountData) { for (final event in accountData) {
await database?.storeRoomAccountData(room.id, event); await database.storeRoomAccountData(room.id, event);
room.roomAccountData[event.type] = event; room.roomAccountData[event.type] = event;
} }
} }
@ -2761,7 +2733,7 @@ class Client extends MatrixApi {
await _handleRoomEvents(room, state, EventUpdateType.inviteState); await _handleRoomEvents(room, state, EventUpdateType.inviteState);
} }
} }
await database?.storeRoomUpdate(id, syncRoomUpdate, room.lastEvent, this); await database.storeRoomUpdate(id, syncRoomUpdate, room.lastEvent, this);
} }
} }
@ -2790,7 +2762,7 @@ class Client extends MatrixApi {
type: LatestReceiptState.eventType, type: LatestReceiptState.eventType,
content: receiptStateContent.toJson(), content: receiptStateContent.toJson(),
); );
await database?.storeRoomAccountData(room.id, event); await database.storeRoomAccountData(room.id, event);
room.roomAccountData[event.type] = event; room.roomAccountData[event.type] = event;
} }
} }
@ -2844,25 +2816,24 @@ class Client extends MatrixApi {
// We do not re-request the profile here as this would lead to // We do not re-request the profile here as this would lead to
// an unknown amount of network requests as we never know how many // an unknown amount of network requests as we never know how many
// member change events can come down in a single sync update. // member change events can come down in a single sync update.
await database?.markUserProfileAsOutdated(userId); await database.markUserProfileAsOutdated(userId);
onUserProfileUpdate.add(userId); onUserProfileUpdate.add(userId);
} }
} }
if (event.type == EventTypes.Message && if (event.type == EventTypes.Message &&
!room.isDirectChat && !room.isDirectChat &&
database != null &&
event is MatrixEvent && event is MatrixEvent &&
room.getState(EventTypes.RoomMember, event.senderId) == null) { 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.senderId, room); final user = await database.getUser(event.senderId, room);
if (user != null) { if (user != null) {
room.setState(user); room.setState(user);
} }
} }
await _updateRoomsByEventUpdate(room, event, type); await _updateRoomsByEventUpdate(room, event, type);
if (store) { if (store) {
await database?.storeEventUpdate(room.id, event, type, this); await database.storeEventUpdate(room.id, event, type, this);
} }
if (event is MatrixEvent && encryptionEnabled) { if (event is MatrixEvent && encryptionEnabled) {
await encryption?.handleEventUpdate( await encryption?.handleEventUpdate(
@ -3080,7 +3051,7 @@ class Client extends MatrixApi {
(event.redacts ?? event.content.tryGet<String>('redacts')) && (event.redacts ?? event.content.tryGet<String>('redacts')) &&
event.type == EventTypes.Redaction && event.type == EventTypes.Redaction &&
room.lastEvent?.relationshipType == RelationshipTypes.edit) { room.lastEvent?.relationshipType == RelationshipTypes.edit) {
final originalEvent = await database?.getEventById( final originalEvent = await database.getEventById(
relationshipEventId, relationshipEventId,
room, room,
) ?? ) ??
@ -3216,7 +3187,7 @@ class Client extends MatrixApi {
Future<void> updateUserDeviceKeys({Set<String>? additionalUsers}) async { Future<void> updateUserDeviceKeys({Set<String>? additionalUsers}) async {
try { try {
final database = this.database; final database = this.database;
if (!isLogged() || database == null) return; if (!isLogged()) return;
final dbActions = <Future<dynamic> Function()>[]; final dbActions = <Future<dynamic> Function()>[];
final trackedUserIds = await _getUserIdsInEncryptedRooms(); final trackedUserIds = await _getUserIdsInEncryptedRooms();
if (!isLogged()) return; if (!isLogged()) return;
@ -3464,7 +3435,7 @@ class Client extends MatrixApi {
/// proccessed all the way. /// proccessed all the way.
Future<void> processToDeviceQueue() async { Future<void> processToDeviceQueue() async {
final database = this.database; final database = this.database;
if (database == null || !_toDeviceQueueNeedsProcessing) { if (!_toDeviceQueueNeedsProcessing) {
return; return;
} }
final entries = await database.getToDeviceEventQueue(); final entries = await database.getToDeviceEventQueue();
@ -3518,14 +3489,12 @@ class Client extends MatrixApi {
s, s,
); );
final database = this.database; final database = this.database;
if (database != null) { _toDeviceQueueNeedsProcessing = true;
_toDeviceQueueNeedsProcessing = true; await database.insertIntoToDeviceQueue(
await database.insertIntoToDeviceQueue( eventType,
eventType, txnId,
txnId, json.encode(messages),
json.encode(messages), );
);
}
rethrow; rethrow;
} }
} }
@ -3762,7 +3731,7 @@ class Client extends MatrixApi {
await abortSync(); await abortSync();
_prevBatch = null; _prevBatch = null;
rooms.clear(); rooms.clear();
await database?.clearCache(); await database.clearCache();
encryption?.keyManager.clearOutboundGroupSessions(); encryption?.keyManager.clearOutboundGroupSessions();
_eventsPendingDecryption.clear(); _eventsPendingDecryption.clear();
onCacheCleared.add(true); onCacheCleared.add(true);
@ -3824,7 +3793,7 @@ class Client extends MatrixApi {
return cachedPresence; return cachedPresence;
} }
final dbPresence = await database?.getPresence(userId); final dbPresence = await database.getPresence(userId);
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
if (dbPresence != null) return presences[userId] = dbPresence; if (dbPresence != null) return presences[userId] = dbPresence;
@ -3833,12 +3802,12 @@ class Client extends MatrixApi {
try { try {
final result = await getPresence(userId); final result = await getPresence(userId);
final presence = CachedPresence.fromPresenceResponse(result, userId); final presence = CachedPresence.fromPresenceResponse(result, userId);
await database?.storePresence(userId, presence); await database.storePresence(userId, presence);
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
return presences[userId] = presence; return presences[userId] = presence;
} catch (e) { } catch (e) {
final presence = CachedPresence.neverSeen(userId); final presence = CachedPresence.neverSeen(userId);
await database?.storePresence(userId, presence); await database.storePresence(userId, presence);
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
return presences[userId] = presence; return presences[userId] = presence;
} }
@ -3873,10 +3842,8 @@ class Client extends MatrixApi {
_encryption = null; _encryption = null;
try { try {
if (closeDatabase) { if (closeDatabase) {
final database = _database;
_database = null;
await database await database
?.close() .close()
.catchError((e, s) => Logs().w('Failed to close database: ', e, s)); .catchError((e, s) => Logs().w('Failed to close database: ', e, s));
} }
} catch (error, stacktrace) { } catch (error, stacktrace) {
@ -3894,7 +3861,7 @@ class Client extends MatrixApi {
final migrateClient = await legacyDatabase?.getClient(clientName); final migrateClient = await legacyDatabase?.getClient(clientName);
final database = this.database; final database = this.database;
if (migrateClient == null || legacyDatabase == null || database == null) { if (migrateClient == null || legacyDatabase == null) {
await legacyDatabase?.close(); await legacyDatabase?.close();
_initLock = false; _initLock = false;
return; return;

View File

@ -176,23 +176,38 @@ class MatrixSdkDatabase extends DatabaseApi with DatabaseFileStorage {
/// like delete. Set it if you want to use sqlite FFI. /// like delete. Set it if you want to use sqlite FFI.
final DatabaseFactory? sqfliteFactory; final DatabaseFactory? sqfliteFactory;
MatrixSdkDatabase( static Future<MatrixSdkDatabase> init(
String name, {
Database? database,
dynamic idbFactory,
DatabaseFactory? sqfliteFactory,
int maxFileSize = 0,
Uri? fileStorageLocation,
Duration? deleteFilesAfterDuration,
}) async {
final matrixSdkDatabase = MatrixSdkDatabase._(
name,
database: database,
idbFactory: idbFactory,
sqfliteFactory: sqfliteFactory,
maxFileSize: maxFileSize,
fileStorageLocation: fileStorageLocation,
deleteFilesAfterDuration: deleteFilesAfterDuration,
);
await matrixSdkDatabase.open();
return matrixSdkDatabase;
}
MatrixSdkDatabase._(
this.name, { this.name, {
this.database, this.database,
this.idbFactory, this.idbFactory,
this.sqfliteFactory, this.sqfliteFactory,
this.maxFileSize = 0, this.maxFileSize = 0,
// TODO : remove deprecated member migration on next major release
@Deprecated(
'Breaks support for web standalone. Use [fileStorageLocation] instead.',
)
dynamic fileStoragePath,
Uri? fileStorageLocation, Uri? fileStorageLocation,
Duration? deleteFilesAfterDuration, Duration? deleteFilesAfterDuration,
}) { }) {
final legacyPath = fileStoragePath?.path; this.fileStorageLocation = fileStorageLocation;
this.fileStorageLocation = fileStorageLocation ??
(legacyPath is String ? Uri.tryParse(legacyPath) : null);
this.deleteFilesAfterDuration = deleteFilesAfterDuration; this.deleteFilesAfterDuration = deleteFilesAfterDuration;
} }

View File

@ -121,7 +121,7 @@ class Event extends MatrixEvent {
// Mark event as failed to send if status is `sending` and event is older // Mark event as failed to send if status is `sending` and event is older
// than the timeout. This should not happen with the deprecated Moor // than the timeout. This should not happen with the deprecated Moor
// database! // database!
if (status.isSending && room.client.database != null) { if (status.isSending) {
// Age of this event in milliseconds // Age of this event in milliseconds
final age = DateTime.now().millisecondsSinceEpoch - final age = DateTime.now().millisecondsSinceEpoch -
originServerTs.millisecondsSinceEpoch; originServerTs.millisecondsSinceEpoch;
@ -402,7 +402,7 @@ class Event extends MatrixEvent {
throw Exception('Can only delete events which are not sent yet!'); throw Exception('Can only delete events which are not sent yet!');
} }
await room.client.database?.removeEvent(eventId, room.id); await room.client.database.removeEvent(eventId, room.id);
if (room.lastEvent != null && room.lastEvent!.eventId == eventId) { if (room.lastEvent != null && room.lastEvent!.eventId == eventId) {
final redactedBecause = Event.fromMatrixEvent( final redactedBecause = Event.fromMatrixEvent(
@ -726,9 +726,6 @@ class Event extends MatrixEvent {
// Is this file storeable? // Is this file storeable?
final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap; final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap;
final database = room.client.database; final database = room.client.database;
if (database == null) {
return false;
}
final storeable = thisInfoMap['size'] is int && final storeable = thisInfoMap['size'] is int &&
thisInfoMap['size'] <= database.maxFileSize; thisInfoMap['size'] <= database.maxFileSize;
@ -772,13 +769,12 @@ class Event extends MatrixEvent {
// Is this file storeable? // Is this file storeable?
final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap; final thisInfoMap = getThumbnail ? thumbnailInfoMap : infoMap;
var storeable = database != null && var storeable = thisInfoMap['size'] is int &&
thisInfoMap['size'] is int &&
thisInfoMap['size'] <= database.maxFileSize; thisInfoMap['size'] <= database.maxFileSize;
Uint8List? uint8list; Uint8List? uint8list;
if (storeable) { if (storeable) {
uint8list = await room.client.database?.getFile(mxcUrl); uint8list = await room.client.database.getFile(mxcUrl);
} }
// Download the file // Download the file
@ -792,9 +788,7 @@ class Event extends MatrixEvent {
.bodyBytes; .bodyBytes;
uint8list = uint8list =
await downloadCallback(await mxcUrl.getDownloadUri(room.client)); await downloadCallback(await mxcUrl.getDownloadUri(room.client));
storeable = database != null && storeable = storeable && uint8list.lengthInBytes < database.maxFileSize;
storeable &&
uint8list.lengthInBytes < database.maxFileSize;
if (storeable) { if (storeable) {
await database.storeFile( await database.storeFile(
mxcUrl, mxcUrl,

View File

@ -284,7 +284,7 @@ class LatestReceiptState {
// set the latest receipt to the one furthest down in the timeline, or if we don't know that, the newest ts. // set the latest receipt to the one furthest down in the timeline, or if we don't know that, the newest ts.
if (updatedTimelines.isEmpty) return; if (updatedTimelines.isEmpty) return;
final eventOrder = await room.client.database?.getEventIdList(room) ?? []; final eventOrder = await room.client.database.getEventIdList(room);
for (final timeline in updatedTimelines) { for (final timeline in updatedTimelines) {
if (timeline.ownPrivate?.eventId == timeline.ownPublic?.eventId) { if (timeline.ownPrivate?.eventId == timeline.ownPublic?.eventId) {

View File

@ -121,15 +121,13 @@ class Room {
return; return;
} }
final allStates = final allStates =
await client.database?.getUnimportantRoomEventStatesForRoom( await client.database.getUnimportantRoomEventStatesForRoom(
client.importantStateEvents.toList(), client.importantStateEvents.toList(),
this, this,
); );
if (allStates != null) { for (final state in allStates) {
for (final state in allStates) { setState(state);
setState(state);
}
} }
partial = false; partial = false;
} }
@ -1237,7 +1235,7 @@ class Room {
/// Call the Matrix API to forget this room if you already left it. /// Call the Matrix API to forget this room if you already left it.
Future<void> forget() async { Future<void> forget() async {
await client.database?.forgetRoom(id); await client.database.forgetRoom(id);
await client.forgetRoom(id); await client.forgetRoom(id);
// Update archived rooms, otherwise an archived room may still be in the // Update archived rooms, otherwise an archived room may still be in the
// list after a forget room call // list after a forget room call
@ -1377,17 +1375,13 @@ class Room {
); );
} }
if (client.database != null) { await client.database.transaction(() async {
await client.database?.transaction(() async { if (storeInDatabase && direction == Direction.b) {
if (storeInDatabase && direction == Direction.b) { this.prev_batch = resp.end;
this.prev_batch = resp.end; await client.database.setRoomPrevBatch(resp.end, id, client);
await client.database?.setRoomPrevBatch(resp.end, id, client); }
}
await loadFn();
});
} else {
await loadFn(); await loadFn();
} });
return resp.chunk.length; return resp.chunk.length;
} }
@ -1478,7 +1472,7 @@ class Room {
].map((e) => Event.fromMatrixEvent(e, this)).toList(); ].map((e) => Event.fromMatrixEvent(e, this)).toList();
// Try again to decrypt encrypted events but don't update the database. // Try again to decrypt encrypted events but don't update the database.
if (encrypted && client.database != null && client.encryptionEnabled) { if (encrypted && client.encryptionEnabled) {
for (var i = 0; i < events.length; i++) { for (var i = 0; i < events.length; i++) {
if (events[i].type == EventTypes.Encrypted && if (events[i].type == EventTypes.Encrypted &&
events[i].content['can_request_session'] == true) { events[i].content['can_request_session'] == true) {
@ -1537,12 +1531,11 @@ class Room {
var events = <Event>[]; var events = <Event>[];
if (!isArchived) { if (!isArchived) {
await client.database?.transaction(() async { await client.database.transaction(() async {
events = await client.database?.getEventList( events = await client.database.getEventList(
this, this,
limit: limit, limit: limit,
) ?? );
<Event>[];
}); });
} else { } else {
final archive = client.getArchiveRoomFromCache(id); final archive = client.getArchiveRoomFromCache(id);
@ -1581,7 +1574,7 @@ class Room {
final userIds = events.map((event) => event.senderId).toSet(); final userIds = events.map((event) => event.senderId).toSet();
for (final userId in userIds) { for (final userId in userIds) {
if (getState(EventTypes.RoomMember, userId) != null) continue; if (getState(EventTypes.RoomMember, userId) != null) continue;
final dbUser = await client.database?.getUser(userId, this); final dbUser = await client.database.getUser(userId, this);
if (dbUser != null) setState(dbUser); if (dbUser != null) setState(dbUser);
} }
} }
@ -1597,9 +1590,9 @@ class Room {
chunk.events[i] = await client.encryption!.decryptRoomEvent( chunk.events[i] = await client.encryption!.decryptRoomEvent(
chunk.events[i], chunk.events[i],
); );
} else if (client.database != null) { } else {
// else, we need the database // else, we need the database
await client.database?.transaction(() async { await client.database.transaction(() async {
for (var i = 0; i < chunk.events.length; i++) { for (var i = 0; i < chunk.events.length; i++) {
if (chunk.events[i].content['can_request_session'] == true) { if (chunk.events[i].content['can_request_session'] == true) {
chunk.events[i] = await client.encryption!.decryptRoomEvent( chunk.events[i] = await client.encryption!.decryptRoomEvent(
@ -1666,7 +1659,7 @@ class Room {
// events won't get written to memory in this case and someone new could // events won't get written to memory in this case and someone new could
// have joined, while someone else left, which might lead to the same // have joined, while someone else left, which might lead to the same
// count in the completeness check. // count in the completeness check.
final users = await client.database?.getUsers(this) ?? []; final users = await client.database.getUsers(this);
for (final user in users) { for (final user in users) {
setState(user); setState(user);
} }
@ -1697,7 +1690,7 @@ class Room {
if (cache) { if (cache) {
for (final user in users) { for (final user in users) {
setState(user); // at *least* cache this in-memory setState(user); // at *least* cache this in-memory
await client.database?.storeEventUpdate( await client.database.storeEventUpdate(
id, id,
user, user,
EventUpdateType.state, EventUpdateType.state,
@ -1775,8 +1768,8 @@ class Room {
); );
// Store user in database: // Store user in database:
await client.database?.transaction(() async { await client.database.transaction(() async {
await client.database?.storeEventUpdate( await client.database.storeEventUpdate(
id, id,
foundUser, foundUser,
EventUpdateType.state, EventUpdateType.state,
@ -1812,7 +1805,7 @@ class Room {
// If the room is not postloaded, check the database // If the room is not postloaded, check the database
if (partial && foundUser == null) { if (partial && foundUser == null) {
foundUser = await client.database?.getUser(mxID, this); foundUser = await client.database.getUser(mxID, this);
} }
// If not in the database, try fetching the member from the server // If not in the database, try fetching the member from the server
@ -1920,7 +1913,7 @@ class Room {
/// found. Returns null if not found anywhere. /// found. Returns null if not found anywhere.
Future<Event?> getEventById(String eventID) async { Future<Event?> getEventById(String eventID) async {
try { try {
final dbEvent = await client.database?.getEventById(eventID, this); final dbEvent = await client.database.getEventById(eventID, this);
if (dbEvent != null) return dbEvent; if (dbEvent != null) return dbEvent;
final matrixEvent = await client.getOneRoomEvent(id, eventID); final matrixEvent = await client.getOneRoomEvent(id, eventID);
final event = Event.fromMatrixEvent(matrixEvent, this); final event = Event.fromMatrixEvent(matrixEvent, this);
@ -2393,13 +2386,9 @@ class Room {
SyncUpdate syncUpdate, { SyncUpdate syncUpdate, {
Direction? direction, Direction? direction,
}) async { }) async {
if (client.database != null) { await client.database.transaction(() async {
await client.database?.transaction(() async {
await client.handleSync(syncUpdate, direction: direction);
});
} else {
await client.handleSync(syncUpdate, direction: direction); await client.handleSync(syncUpdate, direction: direction);
} });
} }
/// Whether this is an extinct room which has been archived in favor of a new /// Whether this is an extinct room which has been archived in favor of a new

View File

@ -145,7 +145,7 @@ class Timeline {
// Look up for events in the database first. With fragmented view, we should delete the database cache // Look up for events in the database first. With fragmented view, we should delete the database cache
final eventsFromStore = isFragmentedTimeline final eventsFromStore = isFragmentedTimeline
? null ? null
: await room.client.database?.getEventList( : await room.client.database.getEventList(
room, room,
start: events.length, start: events.length,
limit: historyCount, limit: historyCount,
@ -161,7 +161,7 @@ class Timeline {
continue; continue;
} }
final dbUser = final dbUser =
await room.client.database?.getUser(event.senderId, room); await room.client.database.getUser(event.senderId, room);
if (dbUser != null) room.setState(dbUser); if (dbUser != null) room.setState(dbUser);
} }
@ -274,8 +274,7 @@ class Timeline {
if (allowNewEvent) { if (allowNewEvent) {
Logs().d('We now allow sync update into the timeline.'); Logs().d('We now allow sync update into the timeline.');
newEvents.addAll( newEvents.addAll(
await room.client.database?.getEventList(room, onlySending: true) ?? await room.client.database.getEventList(room, onlySending: true),
[],
); );
} }
} }
@ -419,11 +418,7 @@ class Timeline {
} }
} }
if (room.client.database != null) { await room.client.database.transaction(decryptFn);
await room.client.database?.transaction(decryptFn);
} else {
await decryptFn();
}
if (decryptAtLeastOneEvent) onUpdate?.call(); if (decryptAtLeastOneEvent) onUpdate?.call();
} }
@ -664,12 +659,11 @@ class Timeline {
// Search in database // Search in database
var start = events.length; var start = events.length;
while (true) { while (true) {
final eventsFromStore = await room.client.database?.getEventList( final eventsFromStore = await room.client.database.getEventList(
room, room,
start: start, start: start,
limit: requestHistoryCount, limit: requestHistoryCount,
) ?? );
[];
if (eventsFromStore.isEmpty) break; if (eventsFromStore.isEmpty) break;
start += eventsFromStore.length; start += eventsFromStore.length;
for (final event in eventsFromStore) { for (final event in eventsFromStore) {

View File

@ -426,7 +426,7 @@ class CrossSigningKey extends SignableKey {
} }
await super.setVerified(newVerified, sign); await super.setVerified(newVerified, sign);
await client.database await client.database
?.setVerifiedUserCrossSigningKey(newVerified, userId, publicKey!); .setVerifiedUserCrossSigningKey(newVerified, userId, publicKey!);
} }
@override @override
@ -436,7 +436,7 @@ class CrossSigningKey extends SignableKey {
} }
_blocked = newBlocked; _blocked = newBlocked;
await client.database await client.database
?.setBlockedUserCrossSigningKey(newBlocked, userId, publicKey!); .setBlockedUserCrossSigningKey(newBlocked, userId, publicKey!);
} }
CrossSigningKey.fromMatrixCrossSigningKey( CrossSigningKey.fromMatrixCrossSigningKey(
@ -513,7 +513,7 @@ class DeviceKeys extends SignableKey {
} }
await super.setVerified(newVerified, sign); await super.setVerified(newVerified, sign);
await client.database await client.database
?.setVerifiedUserDeviceKey(newVerified, userId, deviceId!); .setVerifiedUserDeviceKey(newVerified, userId, deviceId!);
} }
@override @override
@ -524,7 +524,7 @@ class DeviceKeys extends SignableKey {
} }
_blocked = newBlocked; _blocked = newBlocked;
await client.database await client.database
?.setBlockedUserDeviceKey(newBlocked, userId, deviceId!); .setBlockedUserDeviceKey(newBlocked, userId, deviceId!);
} }
DeviceKeys.fromMatrixDeviceKeys( DeviceKeys.fromMatrixDeviceKeys(

View File

@ -79,7 +79,7 @@ void main() {
final client = Client( final client = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
); );
expect(client.isLogged(), false); expect(client.isLogged(), false);
final Set<InitState> initStates = {}; final Set<InitState> initStates = {};
@ -112,7 +112,7 @@ void main() {
matrix = Client( matrix = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
); );
final eventUpdateListFuture = matrix.onTimelineEvent.stream.toList(); final eventUpdateListFuture = matrix.onTimelineEvent.stream.toList();
final toDeviceUpdateListFuture = matrix.onToDeviceEvent.stream.toList(); final toDeviceUpdateListFuture = matrix.onToDeviceEvent.stream.toList();
@ -369,10 +369,10 @@ void main() {
final key = 'abc def!/_-'; final key = 'abc def!/_-';
await matrix.setAccountData(matrix.userID!, key, content); await matrix.setAccountData(matrix.userID!, key, content);
final dbContent = await matrix.database?.getAccountData(); final dbContent = await matrix.database.getAccountData();
expect(matrix.accountData[key]?.content, content); expect(matrix.accountData[key]?.content, content);
expect(dbContent?[key]?.content, content); expect(dbContent[key]?.content, content);
}); });
test('roomAccountData', () async { test('roomAccountData', () async {
@ -383,15 +383,15 @@ void main() {
final key = 'abc def!/_-'; final key = 'abc def!/_-';
final roomId = '!726s6s6q:example.com'; final roomId = '!726s6s6q:example.com';
await matrix.setAccountDataPerRoom(matrix.userID!, roomId, key, content); await matrix.setAccountDataPerRoom(matrix.userID!, roomId, key, content);
final roomFromList = (await matrix.database?.getRoomList(matrix)) final roomFromList = (await matrix.database.getRoomList(matrix))
?.firstWhere((room) => room.id == roomId); .firstWhere((room) => room.id == roomId);
final roomFromDb = await matrix.database?.getSingleRoom(matrix, roomId); final roomFromDb = await matrix.database.getSingleRoom(matrix, roomId);
expect( expect(
matrix.getRoomById(roomId)?.roomAccountData[key]?.content, matrix.getRoomById(roomId)?.roomAccountData[key]?.content,
content, content,
); );
expect(roomFromList?.roomAccountData[key]?.content, content); expect(roomFromList.roomAccountData[key]?.content, content);
expect( expect(
roomFromDb?.roomAccountData[key]?.content, roomFromDb?.roomAccountData[key]?.content,
content, content,
@ -418,7 +418,7 @@ void main() {
matrix = Client( matrix = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
); );
expect(matrix.homeserver, null); expect(matrix.homeserver, null);
@ -504,7 +504,7 @@ void main() {
matrix = Client( matrix = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
); );
await matrix.checkHomeserver( await matrix.checkHomeserver(
@ -912,14 +912,14 @@ void main() {
); );
expect(matrix.onUserProfileUpdate.value, '@alice:example.com'); expect(matrix.onUserProfileUpdate.value, '@alice:example.com');
final cachedProfileFromDb = final cachedProfileFromDb =
await matrix.database?.getUserProfile('@alice:example.com'); await matrix.database.getUserProfile('@alice:example.com');
expect(cachedProfileFromDb?.outdated, true); expect(cachedProfileFromDb?.outdated, true);
}); });
test('joinAfterInviteMembership', () async { test('joinAfterInviteMembership', () async {
final client = await getClient(); final client = await getClient();
await client.abortSync(); await client.abortSync();
client.rooms.clear(); client.rooms.clear();
await client.database?.clearCache(); await client.database.clearCache();
await client.handleSync( await client.handleSync(
SyncUpdate.fromJson( SyncUpdate.fromJson(
@ -955,7 +955,7 @@ void main() {
await client.abortSync(); await client.abortSync();
client.rooms.clear(); client.rooms.clear();
await client.database?.clearCache(); await client.database.clearCache();
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);
}); });
test('leaveThenInvite should be invited', () async { test('leaveThenInvite should be invited', () async {
@ -967,7 +967,7 @@ void main() {
final client = await getClient(); final client = await getClient();
await client.abortSync(); await client.abortSync();
client.rooms.clear(); client.rooms.clear();
await client.database?.clearCache(); await client.database.clearCache();
final roomId = '!inviteLeaveRoom:example.com'; final roomId = '!inviteLeaveRoom:example.com';
await client.handleSync( await client.handleSync(
@ -1015,14 +1015,14 @@ void main() {
await client.abortSync(); await client.abortSync();
client.rooms.clear(); client.rooms.clear();
await client.database?.clearCache(); await client.database.clearCache();
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);
}); });
test('ownProfile', () async { test('ownProfile', () async {
final client = await getClient(); final client = await getClient();
await client.abortSync(); await client.abortSync();
client.rooms.clear(); client.rooms.clear();
await client.database?.clearCache(); await client.database.clearCache();
await client.handleSync( await client.handleSync(
SyncUpdate.fromJson( SyncUpdate.fromJson(
jsonDecode( jsonDecode(
@ -1394,11 +1394,11 @@ void main() {
); );
}); });
test('Test the fake store api', () async { test('Test the fake store api', () async {
final database = await getDatabase(null); final database = await getDatabase();
final client1 = Client( final client1 = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: (_) => database, database: database,
); );
await client1.init( await client1.init(
@ -1418,7 +1418,7 @@ void main() {
final client2 = Client( final client2 = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: (_) => database, database: database,
); );
await client2.init(); await client2.init();
@ -1470,8 +1470,8 @@ void main() {
await client.uploadContent(Uint8List(0), filename: 'file.jpeg'); await client.uploadContent(Uint8List(0), filename: 'file.jpeg');
expect(response.toString(), 'mxc://example.com/AQwafuaFswefuhsfAFAgsw'); expect(response.toString(), 'mxc://example.com/AQwafuaFswefuhsfAFAgsw');
expect( expect(
await client.database?.getFile(response) != null, await client.database.getFile(response) != null,
client.database?.supportsFileStoring, client.database.supportsFileStoring,
); );
await client.dispose(closeDatabase: true); await client.dispose(closeDatabase: true);
}); });
@ -1509,7 +1509,7 @@ void main() {
FakeMatrixApi.expectedAccessToken = null; FakeMatrixApi.expectedAccessToken = null;
expect(client.accessToken, 'a_new_token'); expect(client.accessToken, 'a_new_token');
expect(softLoggedOut, 1); expect(softLoggedOut, 1);
final storedClient = await client.database?.getClient(client.clientName); final storedClient = await client.database.getClient(client.clientName);
expect(storedClient?.tryGet<String>('token'), 'a_new_token'); expect(storedClient?.tryGet<String>('token'), 'a_new_token');
expect( expect(
storedClient?.tryGet<String>('refresh_token'), storedClient?.tryGet<String>('refresh_token'),
@ -1580,11 +1580,11 @@ void main() {
}); });
test('Database Migration', () async { test('Database Migration', () async {
final firstDatabase = await getDatabase(null); final firstDatabase = await getDatabase();
final firstClient = Client( final firstClient = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: (_) => firstDatabase, database: firstDatabase,
); );
FakeMatrixApi.client = firstClient; FakeMatrixApi.client = firstClient;
await firstClient.checkHomeserver( await firstClient.checkHomeserver(
@ -1605,7 +1605,7 @@ void main() {
final newClient = Client( final newClient = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
legacyDatabaseBuilder: (_) => firstDatabase, legacyDatabaseBuilder: (_) => firstDatabase,
); );
final Set<InitState> initStates = {}; final Set<InitState> initStates = {};
@ -1621,7 +1621,7 @@ void main() {
await newClient.dispose(closeDatabase: false); await newClient.dispose(closeDatabase: false);
await firstDatabase.close(); await firstDatabase.close();
final sameOldFirstDatabase = await getDatabase(null); final sameOldFirstDatabase = await getDatabase();
expect(await sameOldFirstDatabase.getClient('testclient'), null); expect(await sameOldFirstDatabase.getClient('testclient'), null);
}); });
@ -1629,7 +1629,7 @@ void main() {
final client = Client( final client = Client(
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
) )
..accessToken = '1234' ..accessToken = '1234'
..baseUri = Uri.parse('https://fakeserver.notexisting'); ..baseUri = Uri.parse('https://fakeserver.notexisting');
@ -1664,8 +1664,8 @@ void main() {
expect(event?.room.name, 'TestRoomName'); expect(event?.room.name, 'TestRoomName');
expect(event?.room.canonicalAlias, '#testalias:blaaa'); expect(event?.room.canonicalAlias, '#testalias:blaaa');
final storedEvent = final storedEvent =
await client.database?.getEventById('123', event!.room); await client.database.getEventById('123', event!.room);
expect(storedEvent?.eventId, event?.eventId); expect(storedEvent?.eventId, event.eventId);
event = await client.getEventByPushNotification( event = await client.getEventByPushNotification(
PushNotification( PushNotification(
@ -1680,8 +1680,8 @@ void main() {
expect(event?.messageType, 'm.text'); expect(event?.messageType, 'm.text');
expect(event?.type, 'm.room.message'); expect(event?.type, 'm.room.message');
final storedEvent2 = await client.database final storedEvent2 = await client.database
?.getEventById('143273582443PhrSn:example.org', event!.room); .getEventById('143273582443PhrSn:example.org', event!.room);
expect(storedEvent2?.eventId, event?.eventId); expect(storedEvent2?.eventId, event.eventId);
}); });
test('Rooms and archived rooms getter', () async { test('Rooms and archived rooms getter', () async {
@ -1738,7 +1738,7 @@ void main() {
() async { () async {
final customClient = Client( final customClient = Client(
'failclient', 'failclient',
databaseBuilder: getMatrixSdkDatabase, database: await getMatrixSdkDatabase(),
); );
try { try {
await customClient.init( await customClient.init(

View File

@ -44,7 +44,7 @@ void main() {
late int toDeviceQueueIndex; late int toDeviceQueueIndex;
test('Setup', () async { test('Setup', () async {
database = await databaseBuilder.value(null); database = await databaseBuilder.value();
}); });
test('transaction', () async { test('transaction', () async {
var counter = 0; var counter = 0;
@ -105,29 +105,50 @@ void main() {
'limited_timeline': false, 'limited_timeline': false,
'membership': Membership.join, 'membership': Membership.join,
}); });
final client = Client('testclient'); final client = Client(
'testclient',
database: await getMatrixSdkDatabase(),
);
await database.storeRoomUpdate('!testroom', roomUpdate, null, client); await database.storeRoomUpdate('!testroom', roomUpdate, null, client);
final rooms = await database.getRoomList(client); final rooms = await database.getRoomList(client);
expect(rooms.single.id, '!testroom'); expect(rooms.single.id, '!testroom');
}); });
test('getRoomList', () async { test('getRoomList', () async {
final room = final room = await database.getSingleRoom(
await database.getSingleRoom(Client('testclient'), '!testroom'); Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
'!testroom',
);
expect(room?.id, '!testroom'); expect(room?.id, '!testroom');
}); });
test('getRoomList', () async { test('getRoomList', () async {
final list = await database.getRoomList(Client('testclient')); final list = await database.getRoomList(
Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
);
expect(list.single.id, '!testroom'); expect(list.single.id, '!testroom');
}); });
test('setRoomPrevBatch', () async { test('setRoomPrevBatch', () async {
final client = Client('testclient'); final client = Client(
'testclient',
database: await getMatrixSdkDatabase(),
);
await database.setRoomPrevBatch('1234', '!testroom', client); await database.setRoomPrevBatch('1234', '!testroom', client);
final rooms = await database.getRoomList(client); final rooms = await database.getRoomList(client);
expect(rooms.single.prev_batch, '1234'); expect(rooms.single.prev_batch, '1234');
}); });
test('forgetRoom', () async { test('forgetRoom', () async {
await database.forgetRoom('!testroom'); await database.forgetRoom('!testroom');
final rooms = await database.getRoomList(Client('testclient')); final rooms = await database.getRoomList(
Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
);
expect(rooms.isEmpty, true); expect(rooms.isEmpty, true);
}); });
test('getClient', () async { test('getClient', () async {
@ -238,12 +259,18 @@ void main() {
}, },
), ),
EventUpdateType.timeline, EventUpdateType.timeline,
Client('testclient'), Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
); );
}); });
test('storeEventUpdate (state)', () async { test('storeEventUpdate (state)', () async {
final roomid = '!testrooma:example.com'; final roomid = '!testrooma:example.com';
final client = Client('testclient'); final client = Client(
'testclient',
database: await getMatrixSdkDatabase(),
);
await database.storeRoomUpdate( await database.storeRoomUpdate(
roomid, roomid,
@ -376,26 +403,50 @@ void main() {
test('getEventById', () async { test('getEventById', () async {
final event = await database.getEventById( final event = await database.getEventById(
'\$event:example.com', '\$event:example.com',
Room(id: '!testroom:example.com', client: Client('testclient')), Room(
id: '!testroom:example.com',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(event?.type, EventTypes.Message); expect(event?.type, EventTypes.Message);
}); });
test('getEventList', () async { test('getEventList', () async {
final events = await database.getEventList( final events = await database.getEventList(
Room(id: '!testroom:example.com', client: Client('testclient')), Room(
id: '!testroom:example.com',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(events.single.type, EventTypes.Message); expect(events.single.type, EventTypes.Message);
}); });
test('getUser', () async { test('getUser', () async {
final user = await database.getUser( final user = await database.getUser(
'@bob:example.org', '@bob:example.org',
Room(id: '!testroom:example.com', client: Client('testclient')), Room(
id: '!testroom:example.com',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(user, null); expect(user, null);
}); });
test('getUsers', () async { test('getUsers', () async {
final users = await database.getUsers( final users = await database.getUsers(
Room(id: '!testroom:example.com', client: Client('testclient')), Room(
id: '!testroom:example.com',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(users.isEmpty, true); expect(users.isEmpty, true);
}); });
@ -406,7 +457,13 @@ void main() {
); );
final event = await database.getEventById( final event = await database.getEventById(
'\$event:example.com', '\$event:example.com',
Room(id: '!testroom:example.com', client: Client('testclient')), Room(
id: '!testroom:example.com',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(event, null); expect(event, null);
}); });
@ -568,12 +625,23 @@ void main() {
test('getUnimportantRoomEventStatesForRoom', () async { test('getUnimportantRoomEventStatesForRoom', () async {
final events = await database.getUnimportantRoomEventStatesForRoom( final events = await database.getUnimportantRoomEventStatesForRoom(
['events'], ['events'],
Room(id: '!mep', client: Client('testclient')), Room(
id: '!mep',
client: Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
),
); );
expect(events.isEmpty, true); expect(events.isEmpty, true);
}); });
test('getUserDeviceKeys', () async { test('getUserDeviceKeys', () async {
await database.getUserDeviceKeys(Client('testclient')); await database.getUserDeviceKeys(
Client(
'testclient',
database: await getMatrixSdkDatabase(),
),
);
}); });
test('storeUserCrossSigningKey', () async { test('storeUserCrossSigningKey', () async {
await database.storeUserCrossSigningKey( await database.storeUserCrossSigningKey(
@ -695,7 +763,7 @@ void main() {
await database.close(); await database.close();
}); });
test('Delete', () async { test('Delete', () async {
final database = await getMatrixSdkDatabase(null); final database = await getMatrixSdkDatabase();
await database.storeAccountData( await database.storeAccountData(
'm.test.data', 'm.test.data',
{'foo': 'bar'}, {'foo': 'bar'},
@ -703,7 +771,7 @@ void main() {
await database.delete(); await database.delete();
// Check if previously stored data is gone: // Check if previously stored data is gone:
final reopenedDatabase = await getMatrixSdkDatabase(null); final reopenedDatabase = await getMatrixSdkDatabase();
final dump = await reopenedDatabase.getAccountData(); final dump = await reopenedDatabase.getAccountData();
expect(dump.isEmpty, true); expect(dump.isEmpty, true);
}); });

View File

@ -23,11 +23,11 @@ import 'package:matrix/matrix.dart';
import '../fake_client.dart'; import '../fake_client.dart';
import '../fake_database.dart'; import '../fake_database.dart';
void main() { void main() async {
// key @othertest:fakeServer.notExisting // key @othertest:fakeServer.notExisting
const otherPickledOlmAccount = const otherPickledOlmAccount =
'VWhVApbkcilKAEGppsPDf9nNVjaK8/IxT3asSR0sYg0S5KgbfE8vXEPwoiKBX2cEvwX3OessOBOkk+ZE7TTbjlrh/KEd31p8Wo+47qj0AP+Ky+pabnhi+/rTBvZy+gfzTqUfCxZrkzfXI9Op4JnP6gYmy7dVX2lMYIIs9WCO1jcmIXiXum5jnfXu1WLfc7PZtO2hH+k9CDKosOFaXRBmsu8k/BGXPSoWqUpvu6WpEG9t5STk4FeAzA'; 'VWhVApbkcilKAEGppsPDf9nNVjaK8/IxT3asSR0sYg0S5KgbfE8vXEPwoiKBX2cEvwX3OessOBOkk+ZE7TTbjlrh/KEd31p8Wo+47qj0AP+Ky+pabnhi+/rTBvZy+gfzTqUfCxZrkzfXI9Op4JnP6gYmy7dVX2lMYIIs9WCO1jcmIXiXum5jnfXu1WLfc7PZtO2hH+k9CDKosOFaXRBmsu8k/BGXPSoWqUpvu6WpEG9t5STk4FeAzA';
final database = await getDatabase();
group('Encrypt/Decrypt to-device messages', tags: 'olm', () { group('Encrypt/Decrypt to-device messages', tags: 'olm', () {
Logs().level = Level.error; Logs().level = Level.error;
@ -35,7 +35,7 @@ void main() {
final otherClient = Client( final otherClient = Client(
'othertestclient', 'othertestclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: database,
); );
late DeviceKeys device; late DeviceKeys device;
late Map<String, dynamic> payload; late Map<String, dynamic> payload;

View File

@ -67,7 +67,7 @@ void main() async {
client2 = Client( client2 = Client(
'othertestclient', 'othertestclient',
httpClient: FakeMatrixApi.currentApi!, httpClient: FakeMatrixApi.currentApi!,
databaseBuilder: getDatabase, database: await getDatabase(),
); );
await client2.checkHomeserver( await client2.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),

View File

@ -157,7 +157,7 @@ void main() {
final deviceId = 'JLAFKJWSCS'; final deviceId = 'JLAFKJWSCS';
final senderKey = 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8'; final senderKey = 'L+4+JCl8MD63dgo8z5Ta+9QAHXiANyOVSfgbHA5d3H8';
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
await client.database!.setLastSentMessageUserDeviceKey( await client.database.setLastSentMessageUserDeviceKey(
json.encode({ json.encode({
'type': 'm.foxies', 'type': 'm.foxies',
'content': { 'content': {
@ -187,7 +187,7 @@ void main() {
// not encrypted // not encrypted
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
await client.database!.setLastSentMessageUserDeviceKey( await client.database.setLastSentMessageUserDeviceKey(
json.encode({ json.encode({
'type': 'm.foxies', 'type': 'm.foxies',
'content': { 'content': {
@ -213,7 +213,7 @@ void main() {
// device not found // device not found
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
await client.database!.setLastSentMessageUserDeviceKey( await client.database.setLastSentMessageUserDeviceKey(
json.encode({ json.encode({
'type': 'm.foxies', 'type': 'm.foxies',
'content': { 'content': {
@ -241,7 +241,7 @@ void main() {
// don't replay if the last event is m.dummy itself // don't replay if the last event is m.dummy itself
FakeMatrixApi.calledEndpoints.clear(); FakeMatrixApi.calledEndpoints.clear();
await client.database!.setLastSentMessageUserDeviceKey( await client.database.setLastSentMessageUserDeviceKey(
json.encode({ json.encode({
'type': 'm.dummy', 'type': 'm.dummy',
'content': {}, 'content': {},

View File

@ -111,7 +111,7 @@ void main() {
sessionPayload, sessionPayload,
forwarded: true, forwarded: true,
); );
var dbSessions = await client.database!.getInboundGroupSessionsToUpload(); var dbSessions = await client.database.getInboundGroupSessionsToUpload();
expect(dbSessions.isNotEmpty, true); expect(dbSessions.isNotEmpty, true);
await client.encryption!.keyManager.uploadInboundGroupSessions(); await client.encryption!.keyManager.uploadInboundGroupSessions();
await FakeMatrixApi.firstWhereValue( await FakeMatrixApi.firstWhereValue(
@ -119,7 +119,7 @@ void main() {
); );
final payload = FakeMatrixApi final payload = FakeMatrixApi
.calledEndpoints['/client/v3/room_keys/keys?version=5']!.first; .calledEndpoints['/client/v3/room_keys/keys?version=5']!.first;
dbSessions = await client.database!.getInboundGroupSessionsToUpload(); dbSessions = await client.database.getInboundGroupSessionsToUpload();
expect(dbSessions.isEmpty, true); expect(dbSessions.isEmpty, true);
final onlineKeys = RoomKeys.fromJson(json.decode(payload)); final onlineKeys = RoomKeys.fromJson(json.decode(payload));

View File

@ -25,8 +25,15 @@ import 'package:matrix/encryption.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'package:matrix/src/models/timeline_chunk.dart'; import 'package:matrix/src/models/timeline_chunk.dart';
import 'fake_client.dart'; import 'fake_client.dart';
import 'fake_database.dart';
void main() async {
final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
void main() {
/// All Tests related to the Event /// All Tests related to the Event
group('Event', () { group('Event', () {
Logs().level = Level.error; Logs().level = Level.error;
@ -51,7 +58,6 @@ void main() {
'status': EventStatus.synced.intValue, 'status': EventStatus.synced.intValue,
'content': contentJson, 'content': contentJson,
}; };
final client = Client('testclient', httpClient: FakeMatrixApi());
final room = Room(id: '!testroom:example.abc', client: client); final room = Room(id: '!testroom:example.abc', client: client);
final event = Event.fromJson( final event = Event.fromJson(
jsonObj, jsonObj,
@ -221,7 +227,13 @@ void main() {
]; ];
for (final testType in testTypes) { for (final testType in testTypes) {
redactJsonObj['type'] = testType; redactJsonObj['type'] = testType;
final room = Room(id: '1234', client: Client('testclient')); final room = Room(
id: '1234',
client: Client(
'testclient',
database: await getDatabase(),
),
);
final redactionEventJson = { final redactionEventJson = {
'content': {'reason': 'Spamming'}, 'content': {'reason': 'Spamming'},
'event_id': '143273582443PhrSn:example.org', 'event_id': '143273582443PhrSn:example.org',
@ -248,7 +260,13 @@ void main() {
test('remove', () async { test('remove', () async {
final event = Event.fromJson( final event = Event.fromJson(
jsonObj, jsonObj,
Room(id: '1234', client: Client('testclient')), Room(
id: '1234',
client: Client(
'testclient',
database: await getDatabase(),
),
),
); );
expect(() async => await event.cancelSend(), throwsException); expect(() async => await event.cancelSend(), throwsException);
event.status = EventStatus.sending; event.status = EventStatus.sending;
@ -258,7 +276,11 @@ void main() {
}); });
test('sendAgain', () async { test('sendAgain', () async {
final matrix = Client('testclient', httpClient: FakeMatrixApi()); final matrix = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await matrix.checkHomeserver( await matrix.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -283,7 +305,11 @@ void main() {
}); });
test('requestKey', tags: 'olm', () async { test('requestKey', tags: 'olm', () async {
final matrix = Client('testclient', httpClient: FakeMatrixApi()); final matrix = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await matrix.checkHomeserver( await matrix.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -333,6 +359,7 @@ void main() {
await matrix.dispose(closeDatabase: true); await matrix.dispose(closeDatabase: true);
}); });
test('requestKey', tags: 'olm', () async { test('requestKey', tags: 'olm', () async {
final client = await getClient();
jsonObj['state_key'] = '@alice:example.com'; jsonObj['state_key'] = '@alice:example.com';
final event = Event.fromJson( final event = Event.fromJson(
jsonObj, jsonObj,
@ -355,7 +382,11 @@ void main() {
await client.dispose(); await client.dispose();
}); });
test('getLocalizedBody, isEventKnown', () async { test('getLocalizedBody, isEventKnown', () async {
final matrix = Client('testclient', httpClient: FakeMatrixApi()); final matrix = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
final room = Room(id: '!1234:example.com', client: matrix); final room = Room(id: '!1234:example.com', client: matrix);
var event = Event.fromJson( var event = Event.fromJson(
{ {
@ -1167,7 +1198,11 @@ void main() {
}); });
test('getLocalizedBody, parameters', () async { test('getLocalizedBody, parameters', () async {
final matrix = Client('testclient', httpClient: FakeMatrixApi()); final matrix = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
final room = Room(id: '!1234:example.com', client: matrix); final room = Room(id: '!1234:example.com', client: matrix);
var event = Event.fromJson( var event = Event.fromJson(
{ {
@ -2477,7 +2512,7 @@ void main() {
); );
expect( expect(
await event.isAttachmentInLocalStore(), await event.isAttachmentInLocalStore(),
event.room.client.database?.supportsFileStoring, event.room.client.database.supportsFileStoring,
); );
expect(buffer.bytes, FILE_BUFF); expect(buffer.bytes, FILE_BUFF);
expect(serverHits, 1); expect(serverHits, 1);
@ -2487,7 +2522,7 @@ void main() {
expect(buffer.bytes, FILE_BUFF); expect(buffer.bytes, FILE_BUFF);
expect( expect(
serverHits, serverHits,
event.room.client.database!.supportsFileStoring ? 1 : 2, event.room.client.database.supportsFileStoring ? 1 : 2,
); );
await room.client.dispose(closeDatabase: true); await room.client.dispose(closeDatabase: true);
@ -2530,12 +2565,12 @@ void main() {
); );
expect( expect(
await event.isAttachmentInLocalStore(), await event.isAttachmentInLocalStore(),
event.room.client.database?.supportsFileStoring, event.room.client.database.supportsFileStoring,
); );
expect(buffer.bytes, FILE_BUFF); expect(buffer.bytes, FILE_BUFF);
expect(serverHits, 1); expect(serverHits, 1);
if (event.room.client.database?.supportsFileStoring == true) { if (event.room.client.database.supportsFileStoring == true) {
buffer = await event.downloadAndDecryptAttachment( buffer = await event.downloadAndDecryptAttachment(
downloadCallback: downloadCallback, downloadCallback: downloadCallback,
fromLocalStoreOnly: true, fromLocalStoreOnly: true,

View File

@ -35,8 +35,7 @@ Future<Client> getClient({
logLevel: Level.verbose, logLevel: Level.verbose,
'testclient', 'testclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: (client) => database: await getDatabase(databasePath: databasePath),
getDatabase(client, databasePath: databasePath),
onSoftLogout: (client) => client.refreshAccessToken(), onSoftLogout: (client) => client.refreshAccessToken(),
sendTimelineEventTimeout: sendTimelineEventTimeout, sendTimelineEventTimeout: sendTimelineEventTimeout,
); );
@ -63,7 +62,7 @@ Future<Client> getOtherClient() async {
final client = Client( final client = Client(
'othertestclient', 'othertestclient',
httpClient: FakeMatrixApi(), httpClient: FakeMatrixApi(),
databaseBuilder: getDatabase, database: await getDatabase(),
); );
FakeMatrixApi.client = client; FakeMatrixApi.client = client;
await client.checkHomeserver( await client.checkHomeserver(

View File

@ -20,23 +20,18 @@ import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
Future<DatabaseApi> getDatabase(Client? c, {String? databasePath}) => Future<DatabaseApi> getDatabase({String? databasePath}) =>
getMatrixSdkDatabase(c, path: databasePath); getMatrixSdkDatabase(path: databasePath);
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
Future<MatrixSdkDatabase> getMatrixSdkDatabase( Future<MatrixSdkDatabase> getMatrixSdkDatabase({
Client? c, {
String? path, String? path,
}) async { }) async =>
final database = await databaseFactoryFfi.openDatabase( MatrixSdkDatabase.init(
path ?? ':memory:', 'unit_test.${DateTime.now().millisecondsSinceEpoch}',
options: OpenDatabaseOptions(singleInstance: false), database: await databaseFactoryFfi.openDatabase(
); path ?? ':memory:',
final db = MatrixSdkDatabase( options: OpenDatabaseOptions(singleInstance: false),
'unit_test.${c?.hashCode}', ),
database: database, sqfliteFactory: databaseFactoryFfi,
sqfliteFactory: databaseFactoryFfi, );
);
await db.open();
return db;
}

View File

@ -25,9 +25,16 @@ import 'fake_database.dart';
void main() { void main() {
group('Databse', () { group('Databse', () {
Logs().level = Level.error; Logs().level = Level.error;
final room = Room(id: '!room:blubb', client: Client('testclient')); late final Room room;
test('setupDatabase', () async { test('setupDatabase', () async {
final database = await getDatabase(null); final database = await getDatabase();
room = Room(
id: '!room:blubb',
client: Client(
'testclient',
database: database,
),
);
await database.insertClient( await database.insertClient(
'testclient', 'testclient',
'https://example.org', 'https://example.org',
@ -43,8 +50,8 @@ void main() {
}); });
test('storeEventUpdate', () async { test('storeEventUpdate', () async {
final client = Client('testclient'); final database = await getDatabase();
final database = await getDatabase(client); final client = Client('testclient', database: database);
// store a simple update // store a simple update
await database.storeEventUpdate( await database.storeEventUpdate(
room.id, room.id,

View File

@ -17,7 +17,7 @@ class MockClient extends Client {
this.serverEvents = const [], this.serverEvents = const [],
this.dbEvents = const [], this.dbEvents = const [],
this.throwError = false, this.throwError = false,
}); }) : super(database: MockDatabase(dbEvents));
@override @override
Future<GetRoomEventsResponse> getRoomEvents( Future<GetRoomEventsResponse> getRoomEvents(
@ -47,7 +47,7 @@ class MockClient extends Client {
} }
@override @override
DatabaseApi? get database => MockDatabase(dbEvents); DatabaseApi get database => MockDatabase(dbEvents);
} }
// MockDatabase: Simulates database access for the `TimelineExportExtension.export` // MockDatabase: Simulates database access for the `TimelineExportExtension.export`

View File

@ -19,13 +19,18 @@
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'fake_database.dart';
void main() { void main() {
/// All Tests related to the MxContent /// All Tests related to the MxContent
group('MxContent', () { group('MxContent', () {
Logs().level = Level.error; Logs().level = Level.error;
test('Formatting', () async { test('Formatting', () async {
final client = Client('testclient', httpClient: FakeMatrixApi()); final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -56,7 +61,11 @@ void main() {
); );
}); });
test('other port', () async { test('other port', () async {
final client = Client('testclient', httpClient: FakeMatrixApi()); final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -88,7 +97,11 @@ void main() {
); );
}); });
test('other remote port', () async { test('other remote port', () async {
final client = Client('testclient', httpClient: FakeMatrixApi()); final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -108,7 +121,11 @@ void main() {
); );
}); });
test('Wrong scheme throw exception', () async { test('Wrong scheme throw exception', () async {
final client = Client('testclient', httpClient: FakeMatrixApi()); final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,
@ -119,7 +136,11 @@ void main() {
}); });
test('auth media fallback', () async { test('auth media fallback', () async {
final client = Client('testclient', httpClient: FakeMatrixApi()); final client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserverpriortoauthmedia.notexisting'), Uri.parse('https://fakeserverpriortoauthmedia.notexisting'),
checkWellKnown: false, checkWellKnown: false,

View File

@ -98,12 +98,12 @@ void main() async {
final archiveRoom = client.getRoomById('!5345234234:example.com'); final archiveRoom = client.getRoomById('!5345234234:example.com');
expect(archiveRoom != null, true); expect(archiveRoom != null, true);
final eventsFromStore = await client.database?.getEventList( final eventsFromStore = await client.database.getEventList(
archiveRoom!, archiveRoom!,
start: 0, start: 0,
limit: Room.defaultHistoryCount, limit: Room.defaultHistoryCount,
); );
expect(eventsFromStore?.isEmpty, true); expect(eventsFromStore.isEmpty, true);
}); });
test('discard room from archives when membership change', () async { test('discard room from archives when membership change', () async {

View File

@ -1677,11 +1677,11 @@ void main() {
// check if persisted in db // check if persisted in db
final sentEventFromDB = final sentEventFromDB =
await matrix.database?.getEventById('older_event', room); await matrix.database.getEventById('older_event', room);
expect(sentEventFromDB?.eventId, 'older_event'); expect(sentEventFromDB?.eventId, 'older_event');
Room? roomFromDB; Room? roomFromDB;
roomFromDB = await matrix.database?.getSingleRoom(matrix, room.id); roomFromDB = await matrix.database.getSingleRoom(matrix, room.id);
expect(roomFromDB?.lastEvent?.eventId, 'older_event'); expect(roomFromDB?.lastEvent?.eventId, 'older_event');
expect(room.lastEvent?.body, 'older_event'); expect(room.lastEvent?.body, 'older_event');
@ -1702,7 +1702,7 @@ void main() {
expect(room.lastEvent?.eventId, 'event_too_large'); expect(room.lastEvent?.eventId, 'event_too_large');
expect(room.lastEvent?.status, EventStatus.error); expect(room.lastEvent?.status, EventStatus.error);
roomFromDB = await matrix.database?.getSingleRoom(matrix, room.id); roomFromDB = await matrix.database.getSingleRoom(matrix, room.id);
expect(roomFromDB?.lastEvent?.eventId, 'event_too_large'); expect(roomFromDB?.lastEvent?.eventId, 'event_too_large');
// force null because except would have caught it anyway // force null because except would have caught it anyway
@ -1718,12 +1718,12 @@ void main() {
// check if persisted in db // check if persisted in db
final lastEventFromDB = final lastEventFromDB =
await matrix.database?.getEventById('event_too_large', room); await matrix.database.getEventById('event_too_large', room);
// null here because cancelSend removes event. // null here because cancelSend removes event.
expect(lastEventFromDB, null); expect(lastEventFromDB, null);
roomFromDB = await matrix.database?.getSingleRoom(matrix, room.id); roomFromDB = await matrix.database.getSingleRoom(matrix, room.id);
expect(roomFromDB?.partial, true); expect(roomFromDB?.partial, true);
@ -1733,7 +1733,7 @@ void main() {
'Cancelled sending message', 'Cancelled sending message',
); );
roomFromDB = await matrix.database?.getSingleRoom(matrix, room.id); roomFromDB = await matrix.database.getSingleRoom(matrix, room.id);
await roomFromDB?.postLoad(); await roomFromDB?.postLoad();
expect(roomFromDB?.partial, false); expect(roomFromDB?.partial, false);

View File

@ -19,30 +19,37 @@
import 'package:test/test.dart'; import 'package:test/test.dart';
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
import 'fake_database.dart';
void main() { void main() async {
/// All Tests related to the Event /// All Tests related to the Event
group('User', () { group('User', () {
Logs().level = Level.error; late Client client;
final client = Client('testclient', httpClient: FakeMatrixApi()); late Room room;
final room = Room(id: '!localpart:server.abc', client: client); late User user1, user2;
final user1 = User(
'@alice:example.com',
membership: 'join',
displayName: 'Alice M',
avatarUrl: 'mxc://bla',
room: room,
);
final user2 = User(
'@bob:example.com',
membership: 'join',
displayName: 'Bob',
avatarUrl: 'mxc://bla',
room: room,
);
room.setState(user1);
room.setState(user2);
setUp(() async { setUp(() async {
client = Client(
'testclient',
httpClient: FakeMatrixApi(),
database: await getDatabase(),
);
room = Room(id: '!localpart:server.abc', client: client);
user1 = User(
'@alice:example.com',
membership: 'join',
displayName: 'Alice M',
avatarUrl: 'mxc://bla',
room: room,
);
user2 = User(
'@bob:example.com',
membership: 'join',
displayName: 'Bob',
avatarUrl: 'mxc://bla',
room: room,
);
room.setState(user1);
room.setState(user2);
await client.checkHomeserver( await client.checkHomeserver(
Uri.parse('https://fakeserver.notexisting'), Uri.parse('https://fakeserver.notexisting'),
checkWellKnown: false, checkWellKnown: false,

View File

@ -47,7 +47,7 @@ void main() => group(
Logs().i('++++ Using homeserver $homeserverUri ++++'); Logs().i('++++ Using homeserver $homeserverUri ++++');
Logs().i('++++ Login Alice at ++++'); Logs().i('++++ Login Alice at ++++');
testClientA = Client('TestClientA', databaseBuilder: getDatabase); testClientA = Client('TestClientA', database: await getDatabase());
await testClientA.checkHomeserver(homeserverUri); await testClientA.checkHomeserver(homeserverUri);
await testClientA.login( await testClientA.login(
LoginType.mLoginPassword, LoginType.mLoginPassword,
@ -57,7 +57,7 @@ void main() => group(
expect(testClientA.encryptionEnabled, true); expect(testClientA.encryptionEnabled, true);
Logs().i('++++ Login Bob ++++'); Logs().i('++++ Login Bob ++++');
testClientB = Client('TestClientB', databaseBuilder: getDatabase); testClientB = Client('TestClientB', database: await getDatabase());
await testClientB.checkHomeserver(homeserverUri); await testClientB.checkHomeserver(homeserverUri);
await testClientB.login( await testClientB.login(
LoginType.mLoginPassword, LoginType.mLoginPassword,
@ -341,7 +341,7 @@ void main() => group(
Logs().i('++++ Login Bob in another client ++++'); Logs().i('++++ Login Bob in another client ++++');
final testClientC = final testClientC =
Client('TestClientC', databaseBuilder: getDatabase); Client('TestClientC', database: await getDatabase());
await testClientC.checkHomeserver(homeserverUri); await testClientC.checkHomeserver(homeserverUri);
// We can't sign in using the displayname, since that breaks e2ee on dendrite: https://github.com/matrix-org/dendrite/issues/2914 // We can't sign in using the displayname, since that breaks e2ee on dendrite: https://github.com/matrix-org/dendrite/issues/2914
await testClientC.login( await testClientC.login(
@ -493,7 +493,7 @@ void main() => group(
Logs().i('++++ Using homeserver $homeserverUri ++++'); Logs().i('++++ Using homeserver $homeserverUri ++++');
Logs().i('++++ Login Alice at ++++'); Logs().i('++++ Login Alice at ++++');
testClientA = Client('TestClientA', databaseBuilder: getDatabase); testClientA = Client('TestClientA', database: await getDatabase());
await testClientA.checkHomeserver(homeserverUri); await testClientA.checkHomeserver(homeserverUri);
await testClientA.login( await testClientA.login(
LoginType.mLoginPassword, LoginType.mLoginPassword,
@ -503,7 +503,7 @@ void main() => group(
expect(testClientA.encryptionEnabled, true); expect(testClientA.encryptionEnabled, true);
Logs().i('++++ Login Bob ++++'); Logs().i('++++ Login Bob ++++');
testClientB = Client('TestClientB', databaseBuilder: getDatabase); testClientB = Client('TestClientB', database: await getDatabase());
await testClientB.checkHomeserver(homeserverUri); await testClientB.checkHomeserver(homeserverUri);
await testClientB.login( await testClientB.login(
LoginType.mLoginPassword, LoginType.mLoginPassword,

View File

@ -1,6 +1,9 @@
import 'package:matrix/matrix.dart'; import 'package:matrix/matrix.dart';
Future<void> main() async { Future<void> main() async {
final client = Client('web_test'); final client = Client(
'web_test',
database: await MatrixSdkDatabase.init('web_test'),
);
await client.init(); await client.init();
} }