From f5dd2d4811e7a2605a88746d91ff6788770693c1 Mon Sep 17 00:00:00 2001 From: Chris Ballinger Date: Thu, 12 Aug 2021 20:05:32 -0700 Subject: [PATCH] Attempting to fix background fetch crash --- .../Classes/Controllers/OTRProtocolManager.m | 46 +++---------------- .../Controllers/OTRProtocolManager.swift | 33 +++++++++++++ ChatSecureCore/Classes/OTRAppDelegate.swift | 2 +- ChatSecureCore/Public/OTRProtocolManager.h | 3 +- 4 files changed, 43 insertions(+), 41 deletions(-) diff --git a/ChatSecureCore/Classes/Controllers/OTRProtocolManager.m b/ChatSecureCore/Classes/Controllers/OTRProtocolManager.m index 4ea6ab392..7e292676f 100644 --- a/ChatSecureCore/Classes/Controllers/OTRProtocolManager.m +++ b/ChatSecureCore/Classes/Controllers/OTRProtocolManager.m @@ -57,6 +57,12 @@ -(instancetype)init return self; } +- (NSArray>*) allProtocols { + @synchronized (self) { + return [self.protocolManagers allValues]; + } +} + - (void)removeProtocolForAccount:(OTRAccount *)account { NSParameterAssert(account); @@ -159,47 +165,9 @@ - (void)goAwayForAllAccounts { } } -- (void)disconnectAllAccountsSocketOnly:(BOOL)socketOnly timeout:(NSTimeInterval)timeout completionBlock:(nullable void (^)())completionBlock -{ - @synchronized (self) { - dispatch_group_t group = dispatch_group_create(); - NSMutableDictionary*> *observingManagersForTokens = [NSMutableDictionary new]; - for (NSObject *manager in self.protocolManagers.allValues) { - OTRXMPPManager *xmpp = (OTRXMPPManager*)manager; - NSParameterAssert([xmpp isKindOfClass:OTRXMPPManager.class]); - if (![xmpp isKindOfClass:OTRXMPPManager.class]) { - DDLogError(@"Wrong protocol class for manager %@", manager); - continue; - } - - if (xmpp.loginStatus != OTRLoginStatusDisconnected) { - dispatch_group_enter(group); - NSString *token = [xmpp addObserverForKeyPath:NSStringFromSelector(@selector(loginStatus)) - options:0 - block:^(NSString *keyPath, OTRXMPPManager *mgr, NSDictionary *change) { - if (mgr.loginStatus == OTRLoginStatusDisconnected) { - dispatch_group_leave(group); - } - }]; - observingManagersForTokens[token] = manager; - [manager disconnectSocketOnly:socketOnly]; - } - } - if (timeout > 0) { - dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t) (timeout * NSEC_PER_SEC))); - } - for (NSString *token in observingManagersForTokens.allKeys) { - [observingManagersForTokens[token] removeObserverForToken:token]; - } - if (completionBlock != nil) { - completionBlock(); - } - } -} - - (void)disconnectAllAccounts { - [self disconnectAllAccountsSocketOnly:NO timeout:0 completionBlock:nil]; + [self disconnectAllAccountsSocketOnly:NO timeout:1 completionBlock:nil]; } - (void)protocolDidChange:(NSDictionary *)change diff --git a/ChatSecureCore/Classes/Controllers/OTRProtocolManager.swift b/ChatSecureCore/Classes/Controllers/OTRProtocolManager.swift index 5b465a399..6c6f88947 100644 --- a/ChatSecureCore/Classes/Controllers/OTRProtocolManager.swift +++ b/ChatSecureCore/Classes/Controllers/OTRProtocolManager.swift @@ -21,3 +21,36 @@ extension OTRProtocolManager { @objc public static let pushController = PushController(baseURL: OTRProtocolManager.pushApiEndpoint, sessionConfiguration: URLSessionConfiguration.ephemeral) } + +extension OTRProtocolManager { + @objc(disconnectAllAccountsSocketOnly:timeout:completionBlock:) + public func disconnectAllAccounts(socketOnly: Bool, timeout: TimeInterval, completion: (()->Void)? = nil) { + let group = DispatchGroup() + let tokens: [NSKeyValueObservation] = allProtocols + .compactMap { $0 as? XMPPManager } + .filter { $0.loginStatus != .disconnected } + .map { + group.enter() + let token = $0.observe(\.loginStatus) { xmppManager, change in + if xmppManager.loginStatus == .disconnected { + group.leave() + } + } + $0.disconnectSocketOnly(socketOnly) + return token + } + DispatchQueue.global(qos: .default).async { + let result = group.wait(timeout: .now() + timeout) + switch result { + case .success: + break + case .timedOut: + DDLogWarn("Exceeded max time for disconnect") + } + tokens.forEach { $0.invalidate() } + DispatchQueue.main.async { + completion?() + } + } + } +} diff --git a/ChatSecureCore/Classes/OTRAppDelegate.swift b/ChatSecureCore/Classes/OTRAppDelegate.swift index 5cee17eb6..1d6cb54eb 100644 --- a/ChatSecureCore/Classes/OTRAppDelegate.swift +++ b/ChatSecureCore/Classes/OTRAppDelegate.swift @@ -60,7 +60,7 @@ extension OTRAppDelegate { OTRProtocolManager.shared.loginAccounts(OTRAccountsManager.allAutoLoginAccounts()) DispatchQueue.main.asyncAfter(deadline: .now() + 8, execute: { let timeout = 1.0 - OTRProtocolManager.shared.disconnectAllAccountsSocketOnly(true, timeout: timeout) { + OTRProtocolManager.shared.disconnectAllAccounts(socketOnly: true, timeout: timeout) { DispatchQueue.main.async { UIApplication.shared.removeExtraForegroundNotifications() switch type { diff --git a/ChatSecureCore/Public/OTRProtocolManager.h b/ChatSecureCore/Public/OTRProtocolManager.h index 440aa0451..fcc188252 100644 --- a/ChatSecureCore/Public/OTRProtocolManager.h +++ b/ChatSecureCore/Public/OTRProtocolManager.h @@ -35,6 +35,8 @@ NS_ASSUME_NONNULL_BEGIN @property (atomic, readonly) NSUInteger numberOfConnectedProtocols; @property (atomic, readonly) NSUInteger numberOfConnectingProtocols; +@property (atomic, readonly) NSArray>* allProtocols; + - (BOOL)existsProtocolForAccount:(OTRAccount *)account; - (nullable id )protocolForAccount:(OTRAccount *)account; - (nullable OTRXMPPManager*)xmppManagerForAccount:(OTRAccount *)account; @@ -48,7 +50,6 @@ NS_ASSUME_NONNULL_BEGIN - (void)loginAccounts:(NSArray *)accounts; - (void)goAwayForAllAccounts; - (void)disconnectAllAccounts; -- (void)disconnectAllAccountsSocketOnly:(BOOL)socketOnly timeout:(NSTimeInterval)timeout completionBlock:(nullable void (^)())completionBlock; - (void)sendMessage:(OTROutgoingMessage *)message;