diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index ef5475669..abf1f1f27 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -5142,7 +5142,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5163,7 +5163,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5211,7 +5211,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5237,7 +5237,7 @@ INFOPLIST_FILE = SessionShareExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -5272,7 +5272,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -5291,7 +5291,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -5342,7 +5342,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -5366,7 +5366,7 @@ INFOPLIST_FILE = SessionNotificationServiceExtension/Meta/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension"; @@ -6227,7 +6227,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6263,7 +6263,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -6295,7 +6295,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 248; + CURRENT_PROJECT_VERSION = 249; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -6331,7 +6331,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.11.1; + MARKETING_VERSION = 1.11.2; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; diff --git a/Session/Utilities/BackgroundPoller.swift b/Session/Utilities/BackgroundPoller.swift index d16570ae1..3a79a7450 100644 --- a/Session/Utilities/BackgroundPoller.swift +++ b/Session/Utilities/BackgroundPoller.swift @@ -13,12 +13,6 @@ public final class BackgroundPoller : NSObject { promises = [] promises.append(pollForMessages()) promises.append(contentsOf: pollForClosedGroupMessages()) - let openGroups: [String:OpenGroup] = Storage.shared.getAllUserOpenGroups() - openGroups.values.forEach { openGroup in - let poller = OpenGroupPoller(for: openGroup) - poller.stop() - promises.append(poller.pollForNewMessages(isBackgroundPoll: true)) - } let v2OpenGroupServers = Set(Storage.shared.getAllV2OpenGroups().values.map { $0.server }) v2OpenGroupServers.forEach { server in let poller = OpenGroupPollerV2(for: server) @@ -27,7 +21,8 @@ public final class BackgroundPoller : NSObject { } when(resolved: promises).done { _ in completionHandler(.newData) - }.catch { _ in + }.catch { error in + SNLog("Background poll failed due to error: \(error)") completionHandler(.failed) } } @@ -43,19 +38,21 @@ public final class BackgroundPoller : NSObject { } private static func getMessages(for publicKey: String) -> Promise { - return SnodeAPI.getSwarm(for: publicKey).then2 { swarm -> Promise in + return SnodeAPI.getSwarm(for: publicKey).then(on: DispatchQueue.main) { swarm -> Promise in guard let snode = swarm.randomElement() else { throw SnodeAPI.Error.generic } - return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise in - let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) - let promises = messages.compactMap { json -> Promise? in - // Use a best attempt approach here; we don't want to fail the entire process if one of the - // messages failed to parse. - guard let envelope = SNProtoEnvelope.from(json), - let data = try? envelope.serializedData() else { return nil } - let job = MessageReceiveJob(data: data, isBackgroundPoll: true) - return job.execute() + return attempt(maxRetryCount: 4, recoveringOn: DispatchQueue.main) { + return SnodeAPI.getRawMessages(from: snode, associatedWith: publicKey).then(on: DispatchQueue.main) { rawResponse -> Promise in + let messages = SnodeAPI.parseRawMessagesResponse(rawResponse, from: snode, associatedWith: publicKey) + let promises = messages.compactMap { json -> Promise? in + // Use a best attempt approach here; we don't want to fail the entire process if one of the + // messages failed to parse. + guard let envelope = SNProtoEnvelope.from(json), + let data = try? envelope.serializedData() else { return nil } + let job = MessageReceiveJob(data: data, isBackgroundPoll: true) + return job.execute() + } + return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects } - return when(fulfilled: promises) // The promise returned by MessageReceiveJob never rejects } } } diff --git a/SessionMessagingKit/Database/OWSPrimaryStorage.m b/SessionMessagingKit/Database/OWSPrimaryStorage.m index d35635cae..ae897bf48 100644 --- a/SessionMessagingKit/Database/OWSPrimaryStorage.m +++ b/SessionMessagingKit/Database/OWSPrimaryStorage.m @@ -69,9 +69,6 @@ void VerifyRegistrationsForPrimaryStorage(OWSStorage *storage) _dbReadPool = [[YapDatabaseConnectionPool alloc] initWithDatabase:self.database]; _dbReadWriteConnection = [self newDatabaseConnection]; _uiDatabaseConnection = [self newDatabaseConnection]; - - // Vacuum the database - [self.dbReadWriteConnection vacuum]; // Increase object cache limit. Default is 250. _uiDatabaseConnection.objectCacheLimit = 500; diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index cf724fe9f..8e6e53bca 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -54,11 +54,6 @@ public enum MessageReceiver { // Parse the envelope let envelope = try SNProtoEnvelope.parseData(data) let storage = SNMessagingKitConfiguration.shared.storage - // If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp - // will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround - // for this issue. - guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage } - storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction) // Decrypt the contents guard let ciphertext = envelope.content else { throw Error.noData } var plaintext: Data! @@ -159,6 +154,19 @@ public enum MessageReceiver { guard isValid else { throw Error.invalidMessage } + // If the message failed to process the first time around we retry it later (if the error is retryable). In this case the timestamp + // will already be in the database but we don't want to treat the message as a duplicate. The isRetry flag is a simple workaround + // for this issue. + if let message = message as? ClosedGroupControlMessage, case .new = message.kind { + // Allow duplicates in this case to avoid the following situation: + // • The app performed a background poll or received a push notification + // • This method was invoked and the received message timestamps table was updated + // • Processing wasn't finished + // • The user doesn't see the new closed group + } else { + guard !Set(storage.getReceivedMessageTimestamps(using: transaction)).contains(envelope.timestamp) || isRetry else { throw Error.duplicateMessage } + storage.addReceivedMessageTimestamp(envelope.timestamp, using: transaction) + } // Return return (message, proto) } else {