Fix: Complete setup would sometimes get stuck
Some checks failed
Flutter analyze & test / flutter_analyze_and_test (push) Has been cancelled

This commit is contained in:
otsmr 2026-05-05 10:57:59 +02:00
parent dc044ee0d2
commit 8c15a95165
6 changed files with 76 additions and 40 deletions

View file

@ -2,7 +2,9 @@
## 0.2.9 ## 0.2.9
- Improved: Make contact avatars clickable
- Fix: Messages occasionally not received until app restart - Fix: Messages occasionally not received until app restart
- Fix: Complete setup would sometimes get stuck
## 0.2.8 ## 0.2.8

View file

@ -193,6 +193,21 @@ Future<void> postStartupTasks() async {
unawaited(finishStartedPreprocessing()); unawaited(finishStartedPreprocessing());
unawaited(createPushAvatars()); unawaited(createPushAvatars());
if (userService.currentUser.userDiscoveryInitializationError) {
unawaited(() async {
try {
await UserDiscoveryService.initializeOrUpdate(
threshold: userService.currentUser.userDiscoveryThreshold,
sharePromotion: userService.currentUser.userDiscoverySharePromotion,
);
} catch (e) {
Log.error(
'Failed to retry UserDiscovery initialization on startup: $e',
);
}
}());
}
await Future.delayed(const Duration(seconds: 10)); await Future.delayed(const Duration(seconds: 10));
unawaited(initializeBackgroundTaskManager()); unawaited(initializeBackgroundTaskManager());
// 3. Delayed tasks (Wait for app to settle) // 3. Delayed tasks (Wait for app to settle)

View file

@ -109,6 +109,9 @@ class UserData {
@JsonKey(defaultValue: true) @JsonKey(defaultValue: true)
bool userDiscoverySharePromotion = true; bool userDiscoverySharePromotion = true;
@JsonKey(defaultValue: false)
bool userDiscoveryInitializationError = false;
// -- Custom DATA -- // -- Custom DATA --
@JsonKey(defaultValue: 100_000) @JsonKey(defaultValue: 100_000)

View file

@ -75,30 +75,27 @@ class UserDiscoveryService {
required int threshold, required int threshold,
required bool sharePromotion, required bool sharePromotion,
}) async { }) async {
try { Log.info('UserDiscoveryService: initializeOrUpdate started');
Log.info('UserDiscoveryService: initializeOrUpdate started'); final userId = userService.currentUser.userId;
final userId = userService.currentUser.userId; final publicKey = await getUserPublicKey();
final publicKey = await getUserPublicKey(); Log.info('UserDiscoveryService: initializing Rust bridge');
Log.info('UserDiscoveryService: initializing Rust bridge'); await FlutterUserDiscovery.initializeOrUpdate(
await FlutterUserDiscovery.initializeOrUpdate( threshold: threshold,
threshold: threshold, userId: userId,
userId: userId, publicKey: publicKey,
publicKey: publicKey, sharePromotion: sharePromotion,
sharePromotion: sharePromotion, ).timeout(const Duration(seconds: 8));
); Log.info(
Log.info( 'UserDiscoveryService: Rust bridge initialized, updating UserService',
'UserDiscoveryService: Rust bridge initialized, updating UserService', );
); await UserService.update(
await UserService.update( (u) => u
(u) => u ..isUserDiscoveryEnabled = true
..isUserDiscoveryEnabled = true ..userDiscoverySharePromotion = sharePromotion
..userDiscoverySharePromotion = sharePromotion ..userDiscoveryThreshold = threshold
..userDiscoveryThreshold = threshold, ..userDiscoveryInitializationError = false,
); );
Log.info('UserDiscoveryService: initializeOrUpdate finished'); Log.info('UserDiscoveryService: initializeOrUpdate finished');
} catch (e) {
Log.error('UserDiscoveryService: initializeOrUpdate error: $e');
}
} }
static Future<Uint8List?> getCurrentVersion() async { static Future<Uint8List?> getCurrentVersion() async {

View file

@ -55,12 +55,20 @@ class UserDiscoverySetupState {
Future<bool> initializeOrUpdate() async { Future<bool> initializeOrUpdate() async {
try { try {
Log.info('UserDiscoverySetupState: initializeOrUpdate started'); Log.info('UserDiscoverySetupState: initializeOrUpdate started');
var hasError = false;
if (isUserDiscoveryEnabled) { if (isUserDiscoveryEnabled) {
Log.info('UserDiscoverySetupState: initializing UserDiscoveryService'); Log.info('UserDiscoverySetupState: initializing UserDiscoveryService');
await UserDiscoveryService.initializeOrUpdate( try {
threshold: threshold, await UserDiscoveryService.initializeOrUpdate(
sharePromotion: sharePromotion, threshold: threshold,
); sharePromotion: sharePromotion,
);
} catch (e) {
Log.error(
'UserDiscoverySetupState: UserDiscoveryService failed or timed out: $e',
);
hasError = true;
}
} }
Log.info('UserDiscoverySetupState: updating UserService'); Log.info('UserDiscoverySetupState: updating UserService');
@ -68,7 +76,8 @@ class UserDiscoverySetupState {
u u
..isUserDiscoveryEnabled = isUserDiscoveryEnabled ..isUserDiscoveryEnabled = isUserDiscoveryEnabled
..requiredSendImages = requiredSendImages ..requiredSendImages = requiredSendImages
..userDiscoveryRequiresManualApproval = isManualApprovalEnabled; ..userDiscoveryRequiresManualApproval = isManualApprovalEnabled
..userDiscoveryInitializationError = hasError;
}); });
Log.info('UserDiscoverySetupState: initializeOrUpdate finished'); Log.info('UserDiscoverySetupState: initializeOrUpdate finished');
@ -474,7 +483,7 @@ class _ExampleLabel extends StatelessWidget {
), ),
child: Text( child: Text(
context.lang.onboardingExampleLabel, context.lang.onboardingExampleLabel,
style: const TextStyle(fontSize: 10, color: Colors.white), style: const TextStyle(fontSize: 10),
), ),
), ),
), ),

View file

@ -91,10 +91,8 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
public_key: Vec<u8>, public_key: Vec<u8>,
share_promotion: bool, share_promotion: bool,
) -> Result<()> { ) -> Result<()> {
tracing::info!("Protocols: initialize_or_update started, getting config_lock"); tracing::info!("Protocols: initialize_or_update started, getting config from store");
let config_lock = self.config_lock.lock().await; let config = match self.store.get_config().await {
tracing::info!("Protocols: got config_lock, getting config from store");
let mut config = match self.store.get_config().await {
Ok(config) => { Ok(config) => {
let mut config: UserDiscoveryConfig = serde_json::from_str(&config)?; let mut config: UserDiscoveryConfig = serde_json::from_str(&config)?;
config.threshold = threshold; config.threshold = threshold;
@ -127,13 +125,25 @@ impl<Store: UserDiscoveryStore, Utils: UserDiscoveryUtils> UserDiscovery<Store,
debug_assert_eq!(verification_shares.len(), threshold as usize - 1); debug_assert_eq!(verification_shares.len(), threshold as usize - 1);
config.public_id = public_id;
config.announcement_version += 1;
config.verification_shares = verification_shares;
config.share_promotion = share_promotion;
tracing::info!("Protocols: updating config in store"); tracing::info!("Protocols: updating config in store");
self.update_config(config, config_lock).await?;
let config_lock = self.config_lock.lock().await;
let mut final_config = match self.store.get_config().await {
Ok(c) => serde_json::from_str(&c)?,
Err(_) => UserDiscoveryConfig {
threshold,
user_id,
..Default::default()
},
};
final_config.public_id = public_id;
final_config.announcement_version += 1;
final_config.verification_shares = verification_shares;
final_config.share_promotion = share_promotion;
final_config.threshold = threshold;
self.update_config(final_config, config_lock).await?;
tracing::info!("Protocols: initialize_or_update finished"); tracing::info!("Protocols: initialize_or_update finished");
Ok(()) Ok(())