ios: delay suspendChat in NSE, background schedule depends on notifications mode (#3561)
* ios: delay suspendChat in NSE * different background refresh interval depending on the settings * simplify * comment * reduce NSE suspend interval * space
This commit is contained in:
parent
974fa448b4
commit
6fa0001ea7
@ -81,7 +81,7 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
|||||||
}
|
}
|
||||||
} else if let checkMessages = ntfData["checkMessages"] as? Bool, checkMessages {
|
} else if let checkMessages = ntfData["checkMessages"] as? Bool, checkMessages {
|
||||||
logger.debug("AppDelegate: didReceiveRemoteNotification: checkMessages")
|
logger.debug("AppDelegate: didReceiveRemoteNotification: checkMessages")
|
||||||
if m.ntfEnablePeriodic && allowBackgroundRefresh() {
|
if m.ntfEnablePeriodic && allowBackgroundRefresh() && BGManager.shared.lastRanLongAgo {
|
||||||
receiveMessages(completionHandler)
|
receiveMessages(completionHandler)
|
||||||
} else {
|
} else {
|
||||||
completionHandler(.noData)
|
completionHandler(.noData)
|
||||||
|
@ -16,7 +16,12 @@ private let receiveTaskId = "chat.simplex.app.receive"
|
|||||||
private let waitForMessages: TimeInterval = 6
|
private let waitForMessages: TimeInterval = 6
|
||||||
|
|
||||||
// This is the smallest interval between refreshes, and also target interval in "off" mode
|
// This is the smallest interval between refreshes, and also target interval in "off" mode
|
||||||
private let bgRefreshInterval: TimeInterval = 600
|
private let bgRefreshInterval: TimeInterval = 600 // 10 minutes
|
||||||
|
|
||||||
|
// This intervals are used for background refresh in instant and periodic modes
|
||||||
|
private let periodicBgRefreshInterval: TimeInterval = 1200 // 20 minutes
|
||||||
|
|
||||||
|
private let maxBgRefreshInterval: TimeInterval = 2400 // 40 minutes
|
||||||
|
|
||||||
private let maxTimerCount = 9
|
private let maxTimerCount = 9
|
||||||
|
|
||||||
@ -34,14 +39,14 @@ class BGManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func schedule() {
|
func schedule(interval: TimeInterval? = nil) {
|
||||||
if !ChatModel.shared.ntfEnableLocal {
|
if !ChatModel.shared.ntfEnableLocal {
|
||||||
logger.debug("BGManager.schedule: disabled")
|
logger.debug("BGManager.schedule: disabled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.debug("BGManager.schedule")
|
logger.debug("BGManager.schedule")
|
||||||
let request = BGAppRefreshTaskRequest(identifier: receiveTaskId)
|
let request = BGAppRefreshTaskRequest(identifier: receiveTaskId)
|
||||||
request.earliestBeginDate = Date(timeIntervalSinceNow: bgRefreshInterval)
|
request.earliestBeginDate = Date(timeIntervalSinceNow: interval ?? runInterval)
|
||||||
do {
|
do {
|
||||||
try BGTaskScheduler.shared.submit(request)
|
try BGTaskScheduler.shared.submit(request)
|
||||||
} catch {
|
} catch {
|
||||||
@ -49,20 +54,34 @@ class BGManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var runInterval: TimeInterval {
|
||||||
|
switch ChatModel.shared.notificationMode {
|
||||||
|
case .instant: maxBgRefreshInterval
|
||||||
|
case .periodic: periodicBgRefreshInterval
|
||||||
|
case .off: bgRefreshInterval
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var lastRanLongAgo: Bool {
|
||||||
|
Date.now.timeIntervalSince(chatLastBackgroundRunGroupDefault.get()) > runInterval
|
||||||
|
}
|
||||||
|
|
||||||
private func handleRefresh(_ task: BGAppRefreshTask) {
|
private func handleRefresh(_ task: BGAppRefreshTask) {
|
||||||
if !ChatModel.shared.ntfEnableLocal {
|
if !ChatModel.shared.ntfEnableLocal {
|
||||||
logger.debug("BGManager.handleRefresh: disabled")
|
logger.debug("BGManager.handleRefresh: disabled")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
logger.debug("BGManager.handleRefresh")
|
logger.debug("BGManager.handleRefresh")
|
||||||
schedule()
|
let shouldRun_ = lastRanLongAgo
|
||||||
if allowBackgroundRefresh() {
|
if allowBackgroundRefresh() && shouldRun_ {
|
||||||
|
schedule()
|
||||||
let completeRefresh = completionHandler {
|
let completeRefresh = completionHandler {
|
||||||
task.setTaskCompleted(success: true)
|
task.setTaskCompleted(success: true)
|
||||||
}
|
}
|
||||||
task.expirationHandler = { completeRefresh("expirationHandler") }
|
task.expirationHandler = { completeRefresh("expirationHandler") }
|
||||||
receiveMessages(completeRefresh)
|
receiveMessages(completeRefresh)
|
||||||
} else {
|
} else {
|
||||||
|
schedule(interval: shouldRun_ ? bgRefreshInterval : runInterval)
|
||||||
logger.debug("BGManager.completionHandler: already active, not started")
|
logger.debug("BGManager.completionHandler: already active, not started")
|
||||||
task.setTaskCompleted(success: true)
|
task.setTaskCompleted(success: true)
|
||||||
}
|
}
|
||||||
@ -91,6 +110,7 @@ class BGManager {
|
|||||||
}
|
}
|
||||||
self.completed = false
|
self.completed = false
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
|
chatLastBackgroundRunGroupDefault.set(Date.now)
|
||||||
let m = ChatModel.shared
|
let m = ChatModel.shared
|
||||||
if (!m.chatInitialized) {
|
if (!m.chatInitialized) {
|
||||||
setAppState(.bgRefresh)
|
setAppState(.bgRefresh)
|
||||||
|
@ -14,9 +14,11 @@ import SimpleXChat
|
|||||||
|
|
||||||
let logger = Logger()
|
let logger = Logger()
|
||||||
|
|
||||||
let suspendingDelay: UInt64 = 2_500_000_000
|
let appSuspendingDelay: UInt64 = 2_500_000_000
|
||||||
|
|
||||||
let nseSuspendTimeout: Int = 10
|
let nseSuspendDelay: TimeInterval = 2
|
||||||
|
|
||||||
|
let nseSuspendTimeout: Int = 5
|
||||||
|
|
||||||
typealias NtfStream = ConcurrentQueue<NSENotification>
|
typealias NtfStream = ConcurrentQueue<NSENotification>
|
||||||
|
|
||||||
@ -177,6 +179,10 @@ class NSEThreads {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var noThreads: Bool {
|
||||||
|
allThreads.isEmpty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notification service extension creates a new instance of the class and calls didReceive for each notification.
|
// Notification service extension creates a new instance of the class and calls didReceive for each notification.
|
||||||
@ -261,7 +267,7 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
let dbStatus = startChat()
|
let dbStatus = startChat()
|
||||||
if case .ok = dbStatus,
|
if case .ok = dbStatus,
|
||||||
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
|
let ntfInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) {
|
||||||
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo), privacy: .public)")
|
logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfInfo.ntfMessages.count), privacy: .public)")
|
||||||
if let connEntity = ntfInfo.connEntity_ {
|
if let connEntity = ntfInfo.connEntity_ {
|
||||||
setBestAttemptNtf(
|
setBestAttemptNtf(
|
||||||
ntfInfo.ntfsEnabled
|
ntfInfo.ntfsEnabled
|
||||||
@ -326,7 +332,15 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
if let t = threadId {
|
if let t = threadId {
|
||||||
threadId = nil
|
threadId = nil
|
||||||
if NSEThreads.shared.endThread(t) {
|
if NSEThreads.shared.endThread(t) {
|
||||||
suspendChat(nseSuspendTimeout)
|
logger.debug("NotificationService.deliverBestAttemptNtf: will suspend")
|
||||||
|
// suspension is delayed to allow chat core finalise any processing
|
||||||
|
// (e.g., send delivery receipts)
|
||||||
|
DispatchQueue.global().asyncAfter(deadline: .now() + nseSuspendDelay) {
|
||||||
|
if NSEThreads.shared.noThreads {
|
||||||
|
logger.debug("NotificationService.deliverBestAttemptNtf: suspending...")
|
||||||
|
suspendChat(nseSuspendTimeout)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let handler = contentHandler, let ntf = bestAttemptNtf {
|
if let handler = contentHandler, let ntf = bestAttemptNtf {
|
||||||
@ -497,7 +511,7 @@ func suspendChat(_ timeout: Int) {
|
|||||||
|
|
||||||
NSEChatState.shared.set(.suspending)
|
NSEChatState.shared.set(.suspending)
|
||||||
if apiSuspendChat(timeoutMicroseconds: timeout * 1000000) {
|
if apiSuspendChat(timeoutMicroseconds: timeout * 1000000) {
|
||||||
logger.debug("NotificationService: activateChat: after apiActivateChat")
|
logger.debug("NotificationService: suspendChat: after apiSuspendChat")
|
||||||
DispatchQueue.global().asyncAfter(deadline: .now() + Double(timeout) + 1, execute: chatSuspended)
|
DispatchQueue.global().asyncAfter(deadline: .now() + Double(timeout) + 1, execute: chatSuspended)
|
||||||
} else {
|
} else {
|
||||||
NSEChatState.shared.set(state)
|
NSEChatState.shared.set(state)
|
||||||
@ -510,6 +524,7 @@ func chatSuspended() {
|
|||||||
if case .suspending = NSEChatState.shared.value {
|
if case .suspending = NSEChatState.shared.value {
|
||||||
NSEChatState.shared.set(.suspended)
|
NSEChatState.shared.set(.suspended)
|
||||||
chatCloseStore()
|
chatCloseStore()
|
||||||
|
logger.debug("NotificationService chatSuspended: suspended")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ let GROUP_DEFAULT_APP_STATE = "appState"
|
|||||||
let GROUP_DEFAULT_NSE_STATE = "nseState"
|
let GROUP_DEFAULT_NSE_STATE = "nseState"
|
||||||
let GROUP_DEFAULT_DB_CONTAINER = "dbContainer"
|
let GROUP_DEFAULT_DB_CONTAINER = "dbContainer"
|
||||||
public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart"
|
public let GROUP_DEFAULT_CHAT_LAST_START = "chatLastStart"
|
||||||
|
public let GROUP_DEFAULT_CHAT_LAST_BACKGROUND_RUN = "chatLastBackgroundRun"
|
||||||
let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode"
|
let GROUP_DEFAULT_NTF_PREVIEW_MODE = "ntfPreviewMode"
|
||||||
public let GROUP_DEFAULT_NTF_ENABLE_LOCAL = "ntfEnableLocal" // no longer used
|
public let GROUP_DEFAULT_NTF_ENABLE_LOCAL = "ntfEnableLocal" // no longer used
|
||||||
public let GROUP_DEFAULT_NTF_ENABLE_PERIODIC = "ntfEnablePeriodic" // no longer used
|
public let GROUP_DEFAULT_NTF_ENABLE_PERIODIC = "ntfEnablePeriodic" // no longer used
|
||||||
@ -156,6 +157,8 @@ public let dbContainerGroupDefault = EnumDefault<DBContainer>(
|
|||||||
|
|
||||||
public let chatLastStartGroupDefault = DateDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_CHAT_LAST_START)
|
public let chatLastStartGroupDefault = DateDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_CHAT_LAST_START)
|
||||||
|
|
||||||
|
public let chatLastBackgroundRunGroupDefault = DateDefault(defaults: groupDefaults, forKey: GROUP_DEFAULT_CHAT_LAST_BACKGROUND_RUN)
|
||||||
|
|
||||||
public let ntfPreviewModeGroupDefault = EnumDefault<NotificationPreviewMode>(
|
public let ntfPreviewModeGroupDefault = EnumDefault<NotificationPreviewMode>(
|
||||||
defaults: groupDefaults,
|
defaults: groupDefaults,
|
||||||
forKey: GROUP_DEFAULT_NTF_PREVIEW_MODE,
|
forKey: GROUP_DEFAULT_NTF_PREVIEW_MODE,
|
||||||
|
Loading…
Reference in New Issue
Block a user