Merge pull request #1962 from famedly/krille/init-state

feat: (BREAKING) Replace onMigration with advanced callback onInitStateChanged
This commit is contained in:
Krille-chan 2024-12-09 12:36:06 +01:00 committed by GitHub
commit 3bfc5efdc6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 4 deletions

View File

@ -597,6 +597,7 @@ class Client extends MatrixApi {
bool? refreshToken, bool? refreshToken,
AuthenticationData? auth, AuthenticationData? auth,
AccountKind? kind, AccountKind? kind,
void Function(InitState)? onInitStateChanged,
}) async { }) async {
final response = await super.register( final response = await super.register(
kind: kind, kind: kind,
@ -632,6 +633,7 @@ class Client extends MatrixApi {
newHomeserver: homeserver, newHomeserver: homeserver,
newDeviceName: initialDeviceDisplayName ?? '', newDeviceName: initialDeviceDisplayName ?? '',
newDeviceID: deviceId_, newDeviceID: deviceId_,
onInitStateChanged: onInitStateChanged,
); );
return response; return response;
} }
@ -655,6 +657,7 @@ class Client extends MatrixApi {
@Deprecated('Deprecated in favour of identifier.') String? user, @Deprecated('Deprecated in favour of identifier.') String? user,
@Deprecated('Deprecated in favour of identifier.') String? medium, @Deprecated('Deprecated in favour of identifier.') String? medium,
@Deprecated('Deprecated in favour of identifier.') String? address, @Deprecated('Deprecated in favour of identifier.') String? address,
void Function(InitState)? onInitStateChanged,
}) async { }) async {
if (homeserver == null) { if (homeserver == null) {
final domain = identifier is AuthenticationUserIdentifier final domain = identifier is AuthenticationUserIdentifier
@ -704,6 +707,7 @@ class Client extends MatrixApi {
newHomeserver: homeserver_, newHomeserver: homeserver_,
newDeviceName: initialDeviceDisplayName ?? '', newDeviceName: initialDeviceDisplayName ?? '',
newDeviceID: deviceId_, newDeviceID: deviceId_,
onInitStateChanged: onInitStateChanged,
); );
return response; return response;
} }
@ -1931,7 +1935,11 @@ class Client extends MatrixApi {
bool waitUntilLoadCompletedLoaded = true, bool waitUntilLoadCompletedLoaded = true,
/// Will be called if the app performs a migration task from the [legacyDatabaseBuilder] /// Will be called if the app performs a migration task from the [legacyDatabaseBuilder]
@Deprecated('Use onInitStateChanged and listen to `InitState.migration`.')
void Function()? onMigration, void Function()? onMigration,
/// To track what actually happens you can set a callback here.
void Function(InitState)? onInitStateChanged,
}) async { }) async {
if ((newToken != null || if ((newToken != null ||
newUserID != null || newUserID != null ||
@ -1956,6 +1964,7 @@ class Client extends MatrixApi {
String? accessToken; String? accessToken;
String? userID; String? userID;
try { try {
onInitStateChanged?.call(InitState.initializing);
Logs().i('Initialize client $clientName'); Logs().i('Initialize client $clientName');
if (onLoginStateChanged.value == LoginState.loggedIn) { if (onLoginStateChanged.value == LoginState.loggedIn) {
throw ClientInitPreconditionError( throw ClientInitPreconditionError(
@ -2036,14 +2045,21 @@ class Client extends MatrixApi {
encryption?.pickledOlmAccount, encryption?.pickledOlmAccount,
); );
} }
onInitStateChanged?.call(InitState.finished);
onLoginStateChanged.add(LoginState.loggedIn); onLoginStateChanged.add(LoginState.loggedIn);
return; return;
} }
if (accessToken == null || homeserver == null || userID == null) { if (accessToken == null || homeserver == null || userID == null) {
if (legacyDatabaseBuilder != null) { if (legacyDatabaseBuilder != null) {
await _migrateFromLegacyDatabase(onMigration: onMigration); await _migrateFromLegacyDatabase(
if (isLogged()) return; onInitStateChanged: onInitStateChanged,
onMigration: onMigration,
);
if (isLogged()) {
onInitStateChanged?.call(InitState.finished);
return;
}
} }
// we aren't logged in // we aren't logged in
await encryption?.dispose(); await encryption?.dispose();
@ -2051,6 +2067,7 @@ class Client extends MatrixApi {
onLoginStateChanged.add(LoginState.loggedOut); onLoginStateChanged.add(LoginState.loggedOut);
Logs().i('User is not logged in.'); Logs().i('User is not logged in.');
_initLock = false; _initLock = false;
onInitStateChanged?.call(InitState.finished);
return; return;
} }
@ -2065,6 +2082,7 @@ class Client extends MatrixApi {
await encryption?.dispose(); await encryption?.dispose();
_encryption = null; _encryption = null;
} }
onInitStateChanged?.call(InitState.settingUpEncryption);
await encryption?.init(olmAccount); await encryption?.init(olmAccount);
final database = this.database; final database = this.database;
@ -2112,6 +2130,7 @@ class Client extends MatrixApi {
// ignore: deprecated_member_use_from_same_package // ignore: deprecated_member_use_from_same_package
presences.clear(); presences.clear();
if (waitUntilLoadCompletedLoaded) { if (waitUntilLoadCompletedLoaded) {
onInitStateChanged?.call(InitState.loadingData);
await userDeviceKeysLoading; await userDeviceKeysLoading;
await roomsLoading; await roomsLoading;
await _accountDataLoading; await _accountDataLoading;
@ -2127,14 +2146,18 @@ class Client extends MatrixApi {
/// Timeout of 0, so that we don't see a spinner for 30 seconds. /// Timeout of 0, so that we don't see a spinner for 30 seconds.
firstSyncReceived = _sync(timeout: Duration.zero); firstSyncReceived = _sync(timeout: Duration.zero);
if (waitForFirstSync) { if (waitForFirstSync) {
onInitStateChanged?.call(InitState.waitingForFirstSync);
await firstSyncReceived; await firstSyncReceived;
} }
onInitStateChanged?.call(InitState.finished);
return; return;
} on ClientInitPreconditionError { } on ClientInitPreconditionError {
onInitStateChanged?.call(InitState.error);
rethrow; rethrow;
} catch (e, s) { } catch (e, s) {
Logs().wtf('Client initialization failed', e, s); Logs().wtf('Client initialization failed', e, s);
onLoginStateChanged.addError(e, s); onLoginStateChanged.addError(e, s);
onInitStateChanged?.call(InitState.error);
final clientInitException = ClientInitException( final clientInitException = ClientInitException(
e, e,
homeserver: homeserver, homeserver: homeserver,
@ -3728,6 +3751,7 @@ class Client extends MatrixApi {
} }
Future<void> _migrateFromLegacyDatabase({ Future<void> _migrateFromLegacyDatabase({
void Function(InitState)? onInitStateChanged,
void Function()? onMigration, void Function()? onMigration,
}) async { }) async {
Logs().i('Check legacy database for migration data...'); Logs().i('Check legacy database for migration data...');
@ -3741,6 +3765,7 @@ class Client extends MatrixApi {
return; return;
} }
Logs().i('Found data in the legacy database!'); Logs().i('Found data in the legacy database!');
onInitStateChanged?.call(InitState.migratingDatabase);
onMigration?.call(); onMigration?.call();
_id = migrateClient['client_id']; _id = migrateClient['client_id'];
final tokenExpiresAtMs = final tokenExpiresAtMs =
@ -3858,6 +3883,7 @@ class Client extends MatrixApi {
return init( return init(
waitForFirstSync: false, waitForFirstSync: false,
waitUntilLoadCompletedLoaded: false, waitUntilLoadCompletedLoaded: false,
onInitStateChanged: onInitStateChanged,
); );
} }
} }
@ -3958,3 +3984,30 @@ class _EventPendingDecryption {
_EventPendingDecryption(this.event); _EventPendingDecryption(this.event);
} }
enum InitState {
/// Initialization has been started. Client fetches information from the database.
initializing,
/// The database has been updated. A migration is in progress.
migratingDatabase,
/// The encryption module will be set up now. For the first login this also
/// includes uploading keys to the server.
settingUpEncryption,
/// The client is loading rooms, device keys and account data from the
/// database.
loadingData,
/// The client waits now for the first sync before procceeding. Get more
/// information from `Client.onSyncUpdate`.
waitingForFirstSync,
/// Initialization is complete without errors. The client is now either
/// logged in or no active session was found.
finished,
/// Initialization has been completed with an error.
error,
}

View File

@ -82,15 +82,26 @@ void main() {
databaseBuilder: getDatabase, databaseBuilder: getDatabase,
); );
expect(client.isLogged(), false); expect(client.isLogged(), false);
await client.init(); final Set<InitState> initStates = {};
await client.init(onInitStateChanged: initStates.add);
expect(client.isLogged(), false); expect(client.isLogged(), false);
expect(initStates, {InitState.initializing, InitState.finished});
initStates.clear();
await client.login( await client.login(
LoginType.mLoginPassword, LoginType.mLoginPassword,
token: 'abcd', token: 'abcd',
identifier: identifier:
AuthenticationUserIdentifier(user: '@test:fakeServer.notExisting'), AuthenticationUserIdentifier(user: '@test:fakeServer.notExisting'),
deviceId: 'GHTYAJCE', deviceId: 'GHTYAJCE',
onInitStateChanged: initStates.add,
); );
expect(initStates, {
InitState.initializing,
InitState.settingUpEncryption,
InitState.loadingData,
InitState.waitingForFirstSync,
InitState.finished,
});
expect(client.isLogged(), true); expect(client.isLogged(), true);
@ -1439,7 +1450,14 @@ void main() {
databaseBuilder: getDatabase, databaseBuilder: getDatabase,
legacyDatabaseBuilder: (_) => database, legacyDatabaseBuilder: (_) => database,
); );
await hiveClient.init(); final Set<InitState> initStates = {};
await hiveClient.init(onInitStateChanged: initStates.add);
expect(initStates, {
InitState.initializing,
InitState.migratingDatabase,
InitState.settingUpEncryption,
InitState.finished,
});
await Future.delayed(Duration(milliseconds: 200)); await Future.delayed(Duration(milliseconds: 200));
expect(hiveClient.isLogged(), true); expect(hiveClient.isLogged(), true);
await hiveClient.dispose(closeDatabase: false); await hiveClient.dispose(closeDatabase: false);