init method
Sets the user credentials and starts the synchronisation.
Before you can connect you need at least an accessToken, a node, a userID, a deviceID, and a deviceName.
Usually you don't need to call this method yourself because login(), register() and even the constructor calls it.
Sends LoginState.loggedIn to onLoginStateChanged.
If one of newToken
, newUserID
, newDeviceID
, newDeviceName
is set then
all of them must be set! If you don't set them, this method will try to
get them from the database.
Set waitForFirstSync
and waitUntilLoadCompletedLoaded
to false to speed this
up. You can then wait for roomsLoading
, _accountDataLoading
and
userDeviceKeysLoading
where it is necessary.
Implementation
Future<void> init({
String? newToken,
Uri? newNode,
String? newUserID,
String? newDeviceName,
String? newDeviceID,
String? newOlmAccount,
bool waitForFirstSync = true,
bool waitUntilLoadCompletedLoaded = true,
/// Will be called if the app performs a migration task from the [legacyDatabaseBuilder]
void Function()? onMigration,
}) async {
if ((newToken != null ||
newUserID != null ||
newDeviceID != null /*||
newDeviceName != null*/
) &&
(newToken == null ||
newUserID == null ||
newDeviceID == null /*||
newDeviceName == null*/
)) {
throw Exception(
'If one of [newToken, newUserID, newDeviceID] is set then all of them must be set!');
}
print('init newNode :$newNode');
if (_initLock) throw Exception('[init()] has been called multiple times!');
_initLock = true;
try {
Logs().i('Initialize client $clientName');
if (isLogged()) {
throw Exception('User is already logged in! Call [logout()] first!');
}
final databaseBuilder = this.databaseBuilder;
if (databaseBuilder != null) {
_database ??= await runBenchmarked<DatabaseApi>(
'Build database',
() async => await databaseBuilder(this),
);
}
_groupCallSessionId = randomAlpha(12);
String? olmAccount;
String? accessToken;
String? userID;
final account = await this.database?.getClient(clientName);
if (account != null) {
_id = account['client_id'];
node = Uri.parse(account['node_url']);
accessToken = this.accessToken = account['token'];
userID = _userID = account['user_id'];
_deviceID = account['device_id'];
_deviceName = account['device_name'];
syncFilterId = account['sync_filter_id'];
prevBatch = account['prev_batch'];
olmAccount = account['olm_account'];
}
if (newToken != null) {
accessToken = this.accessToken = newToken;
node = newNode;
userID = _userID = newUserID;
_deviceID = newDeviceID;
_deviceName = newDeviceName;
olmAccount = newOlmAccount;
} else {
accessToken = this.accessToken = newToken ?? accessToken;
node = newNode ?? node;
userID = _userID = newUserID ?? userID;
_deviceID = newDeviceID ?? _deviceID;
_deviceName = newDeviceName ?? _deviceName;
olmAccount = newOlmAccount ?? olmAccount;
}
if (accessToken == null || node == null || userID == null) {
if (legacyDatabaseBuilder != null) {
await _migrateFromLegacyDatabase(onMigration: onMigration);
if (isLogged()) return;
}
// we aren't logged in
await encryption?.dispose();
encryption = null;
onLoginStateChanged.add(LoginState.loggedOut);
Logs().i('User is not logged in.');
_initLock = false;
return;
}
await encryption?.dispose();
try {
// make sure to throw an exception if libolm doesn't exist
await olm.init();
olm.get_library_version();
encryption = Encryption(client: this);
} catch (e) {
Logs().e('Error initializing encryption $e');
await encryption?.dispose();
encryption = null;
}
await encryption?.init(olmAccount);
final database = this.database;
if (database != null) {
if (id != null) {
await database.updateClient(
node.toString(),
accessToken,
userID,
_deviceID,
_deviceName,
prevBatch,
encryption?.pickledOlmAccount,
);
} else {
_id = await database.insertClient(
clientName,
node.toString(),
accessToken,
userID,
_deviceID,
_deviceName,
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();
});
presences.clear();
if (waitUntilLoadCompletedLoaded) {
await userDeviceKeysLoading;
await roomsLoading;
await _accountDataLoading;
}
}
_initLock = false;
onLoginStateChanged.add(LoginState.loggedIn);
Logs().i(
'Successfully connected as ${userID.localpart} with ${node.toString()}',
);
/// Timeout of 0, so that we don't see a spinner for 30 seconds.
final syncFuture = _sync(timeout: Duration.zero);
if (waitForFirstSync) {
await syncFuture;
}
return;
} catch (e, s) {
Logs().e('Initialization failed', e, s);
await logout().catchError((_) => null);
onLoginStateChanged.addError(e, s);
_initLock = false;
rethrow;
}
}