From 3d8c5d2fe4a7108305b684318948ecb5e7b81fb8 Mon Sep 17 00:00:00 2001 From: Matthew Fennell Date: Sat, 28 Dec 2024 23:50:52 +0000 Subject: [PATCH 1/2] Post error notification on stale rejected promise In general, when we use a promise, we want to perform different UI actions depending on whether the promise is fulfilled or rejected. For instance, if a promise is rejected with an error from the server, we may want to show an alert to the user detailing the error, so they know whatever action they took wasn't successful. In a regular scenario (already working), the UI would be notified of the error like so: 1) user triggers some action which creates a handler and MLPromise 2) user puts the app into the background 3) server responds with an error - app extension is awoken 4) handler gets run in app extension, resolving the promise with error 5) user opens the app (restoring the state from before) 6) the promise is consumed, calling the AnyPromise that notifies the UI However, before this commit, it was possible for an error from the server to be silently dropped without alerting the user, if the user closed the app after the promise was resolved. Consider the following scenario (fixed by this commit): 1) user triggers some action which creates a handler and MLPromise 2) user puts the app into the background 3) server responds with an error - app extension is awoken 4) handler gets run in app extension, resolving the promise with error 5) user closes the app 6) user opens the app (fresh start: resolvers map is gone) Now, the promise created in 1) is stale (since the AnyPromise returned to the UI in 1) is not around anymore), so no popup is shown to the user. But, the action the user took was not successful, and without an error they may not be aware that the change did not go through, causing confusion when they realise this. Therefore: if we attempt to consume a stale, rejected promise, post an error so that a banner can be shown to the user with the error details. --- Monal/Classes/MLPromise.m | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Monal/Classes/MLPromise.m b/Monal/Classes/MLPromise.m index 05019841b6..0c7f8b2598 100644 --- a/Monal/Classes/MLPromise.m +++ b/Monal/Classes/MLPromise.m @@ -11,6 +11,7 @@ #import "DataLayer.h" #import "HelperTools.h" #import "MLPromise.h" +#import "MLXMPPManager.h" NS_ASSUME_NONNULL_BEGIN @@ -206,7 +207,13 @@ -(void) attemptConsume return; } - if(!self.isStale) + if(self.isStale && self.state == PromiseResolutionStateRejected) + { + DDLogDebug(@"Promise %@ with uuid %@ is both stale and rejected - posting error", self, self.uuid); + xmpp* account = [[MLXMPPManager sharedInstance] getEnabledAccountForID:self.rejection.accountID]; + [HelperTools postError:self.rejection.errorDescription withNode:self.rejection.node andAccount:account andIsSevere:NO]; + } + else if(!self.isStale) { DDLogDebug(@"Resolving promise %@ with uuid %@ and argument %@", self, self.uuid, self.resolvedArgument); resolve(self.resolvedArgument); From b38459ddac0be08fb4c71917e6ba795067fbedcc Mon Sep 17 00:00:00 2001 From: Matthew Fennell Date: Sat, 28 Dec 2024 23:51:02 +0000 Subject: [PATCH 2/2] DON'T MERGE: test popup with hacky workaround --- Monal/Classes/MonalAppDelegate.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Monal/Classes/MonalAppDelegate.m b/Monal/Classes/MonalAppDelegate.m index d8ce8e9422..66c5fb3feb 100644 --- a/Monal/Classes/MonalAppDelegate.m +++ b/Monal/Classes/MonalAppDelegate.m @@ -393,9 +393,6 @@ -(BOOL) application:(UIApplication*) application willFinishLaunchingWithOptions: dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ [[MLImageManager sharedInstance] cleanupHashes]; }); - - // Remove stale promises left in the DB that weren't consumed last time we ran the app - [MLPromise consumeStalePromises]; //only proceed with launching if the NotificationServiceExtension is *not* running if([MLProcessLock checkRemoteRunning:@"NotificationServiceExtension"]) @@ -558,6 +555,9 @@ -(BOOL) application:(UIApplication*) application didFinishLaunchingWithOptions:( //should any accounts connect? [self connectIfNecessaryWithOptions:launchOptions]; + + // Consume stale promises left in the DB that weren't consumed last time we ran the app + [MLPromise consumeStalePromises]; //handle IPC messages (this should be done *after* calling connectIfNecessary to make sure any disconnectAll messages are handled properly [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incomingIPC:) name:kMonalIncomingIPC object:nil];