From 2272b77b536f0a49ce9957f2de72407ea038f01e Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin Date: Mon, 1 Apr 2024 13:52:28 +0100 Subject: [PATCH] ios: refactor notifications (#3976) * ios: refactor notifications * refactor --- .../ios/SimpleX NSE/NotificationService.swift | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/apps/ios/SimpleX NSE/NotificationService.swift b/apps/ios/SimpleX NSE/NotificationService.swift index 3da4775382..efd8f33dd8 100644 --- a/apps/ios/SimpleX NSE/NotificationService.swift +++ b/apps/ios/SimpleX NSE/NotificationService.swift @@ -65,20 +65,24 @@ class NSEThreads { } func processNotification(_ id: ChatId, _ ntf: NSENotification) async -> Void { - var timeoutOfWaiting: Int64 = 5_000_000000 - while timeoutOfWaiting > 0 { - let activeThread = NSEThreads.queue.sync { - activeThreads.first(where: { (_, nse) in nse.receiveEntityId == id }) - } - if activeThread?.1.processReceivedNtf?(ntf) == true { + var waitTime: Int64 = 5_000_000000 + while waitTime > 0 { + if let (_, nse) = rcvEntityThread(id), + nse.shouldProcessNtf && nse.processReceivedNtf(ntf) { break } else { try? await Task.sleep(nanoseconds: 10_000000) - timeoutOfWaiting -= 10_000000 + waitTime -= 10_000000 } } } + private func rcvEntityThread(_ id: ChatId) -> (UUID, NotificationService)? { + NSEThreads.queue.sync { + activeThreads.first(where: { (_, nse) in nse.receiveEntityId == id }) + } + } + func endThread(_ t: UUID) -> Bool { NSEThreads.queue.sync { let tActive: UUID? = if let index = activeThreads.firstIndex(where: { $0.0 == t }) { @@ -113,9 +117,11 @@ class NotificationService: UNNotificationServiceExtension { // thread is added to allThreads here - if thread did not start chat, // chat does not need to be suspended but NSE state still needs to be set to "suspended". var threadId: UUID? = NSEThreads.shared.newThread() + var notificationInfo: NtfMessages? var receiveEntityId: String? + var expectedMessages: Set = [] // return true if the message is taken - it prevents sending it to another NotificationService instance for processing - var processReceivedNtf: ((NSENotification) -> Bool)? + var shouldProcessNtf = false var appSubscriber: AppSubscriber? var returnedSuspension = false @@ -192,39 +198,11 @@ class NotificationService: UNNotificationServiceExtension { ? .nse(createConnectionEventNtf(ntfInfo.user, connEntity)) : .empty ) - if let id = connEntity.id, let msgTs = ntfInfo.msgTs { - var expected = Set(ntfInfo.ntfMessages.map { $0.msgId }) - processReceivedNtf = { ntf in - if !ntfInfo.user.showNotifications { - self.setBestAttemptNtf(.empty) - } - if case let .msgInfo(info) = ntf { - let found = expected.remove(info.msgId) - if found != nil { - logger.debug("NotificationService processNtf: msgInfo, last: \(expected.isEmpty)") - if expected.isEmpty { - self.deliverBestAttemptNtf() - } - return true - } else if info.msgTs > msgTs { - logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one") - self.deliverBestAttemptNtf() - return false - } else { - logger.debug("NotificationService processNtf: unknown message, let other instance to process it") - return false - } - } else if ntfInfo.user.showNotifications { - logger.debug("NotificationService processNtf: setting best attempt") - self.setBestAttemptNtf(ntf) - if ntf.isCallInvitation { - self.deliverBestAttemptNtf() - } - return true - } - return false - } + if let id = connEntity.id, ntfInfo.msgTs != nil { + notificationInfo = ntfInfo receiveEntityId = id + expectedMessages = Set(ntfInfo.ntfMessages.map { $0.msgId }) + shouldProcessNtf = true return } } @@ -240,6 +218,38 @@ class NotificationService: UNNotificationServiceExtension { deliverBestAttemptNtf(urgent: true) } + func processReceivedNtf(_ ntf: NSENotification) -> Bool { + guard let ntfInfo = notificationInfo, let msgTs = ntfInfo.msgTs else { return false } + if !ntfInfo.user.showNotifications { + self.setBestAttemptNtf(.empty) + } + if case let .msgInfo(info) = ntf { + let found = expectedMessages.remove(info.msgId) + if found != nil { + logger.debug("NotificationService processNtf: msgInfo, last: \(self.expectedMessages.isEmpty)") + if expectedMessages.isEmpty { + self.deliverBestAttemptNtf() + } + return true + } else if info.msgTs > msgTs { + logger.debug("NotificationService processNtf: unexpected msgInfo, let other instance to process it, stopping this one") + self.deliverBestAttemptNtf() + return false + } else { + logger.debug("NotificationService processNtf: unknown message, let other instance to process it") + return false + } + } else if ntfInfo.user.showNotifications { + logger.debug("NotificationService processNtf: setting best attempt") + self.setBestAttemptNtf(ntf) + if ntf.isCallInvitation { + self.deliverBestAttemptNtf() + } + return true + } + return false + } + func setBadgeCount() { badgeCount = ntfBadgeCountGroupDefault.get() + 1 ntfBadgeCountGroupDefault.set(badgeCount) @@ -262,7 +272,7 @@ class NotificationService: UNNotificationServiceExtension { private func deliverBestAttemptNtf(urgent: Bool = false) { logger.debug("NotificationService.deliverBestAttemptNtf") // stop processing other messages - processReceivedNtf = nil + shouldProcessNtf = false let suspend: Bool if let t = threadId {