* ios: fix callkit calls via NSE * comments * more reliable NSE start * remove public logs, different RTS parameters for NSE * only suspend NSE if we have chat controller, to avoid crashes if suspension attempted without controller created * comments * fix * simplify
84 lines
2.6 KiB
Swift
84 lines
2.6 KiB
Swift
//
|
|
// NSESubscriber.swift
|
|
// SimpleXChat
|
|
//
|
|
// Created by Evgeny on 09/12/2023.
|
|
// Copyright © 2023 SimpleX Chat. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import SimpleXChat
|
|
|
|
private var nseSubscribers: [UUID:NSESubscriber] = [:]
|
|
|
|
// timeout for active notification service extension going into "suspending" state.
|
|
// If in two seconds the state does not change, we assume that it was not running and proceed with app activation/answering call.
|
|
private let SUSPENDING_TIMEOUT: TimeInterval = 2
|
|
|
|
// timeout should be larger than SUSPENDING_TIMEOUT
|
|
func waitNSESuspended(timeout: TimeInterval, suspended: @escaping (Bool) -> Void) {
|
|
if timeout <= SUSPENDING_TIMEOUT {
|
|
logger.warning("waitNSESuspended: small timeout \(timeout), using \(SUSPENDING_TIMEOUT + 1)")
|
|
}
|
|
var state = nseStateGroupDefault.get()
|
|
if case .suspended = state {
|
|
DispatchQueue.main.async { suspended(true) }
|
|
return
|
|
}
|
|
let id = UUID()
|
|
var suspendedCalled = false
|
|
checkTimeout()
|
|
nseSubscribers[id] = nseMessageSubscriber { msg in
|
|
if case let .state(newState) = msg {
|
|
state = newState
|
|
logger.debug("waitNSESuspended state: \(state.rawValue)")
|
|
if case .suspended = newState {
|
|
notifySuspended(true)
|
|
}
|
|
}
|
|
}
|
|
return
|
|
|
|
func notifySuspended(_ ok: Bool) {
|
|
logger.debug("waitNSESuspended notifySuspended: \(ok)")
|
|
if !suspendedCalled {
|
|
logger.debug("waitNSESuspended notifySuspended: calling suspended(\(ok))")
|
|
suspendedCalled = true
|
|
nseSubscribers.removeValue(forKey: id)
|
|
DispatchQueue.main.async { suspended(ok) }
|
|
}
|
|
}
|
|
|
|
func checkTimeout() {
|
|
if !suspending() {
|
|
checkSuspendingTimeout()
|
|
} else if state == .suspending {
|
|
checkSuspendedTimeout()
|
|
}
|
|
}
|
|
|
|
func suspending() -> Bool {
|
|
suspendedCalled || state == .suspended || state == .suspending
|
|
}
|
|
|
|
func checkSuspendingTimeout() {
|
|
DispatchQueue.global().asyncAfter(deadline: .now() + SUSPENDING_TIMEOUT) {
|
|
logger.debug("waitNSESuspended check suspending timeout")
|
|
if !suspending() {
|
|
notifySuspended(false)
|
|
} else if state != .suspended {
|
|
checkSuspendedTimeout()
|
|
}
|
|
}
|
|
}
|
|
|
|
func checkSuspendedTimeout() {
|
|
DispatchQueue.global().asyncAfter(deadline: .now() + min(timeout - SUSPENDING_TIMEOUT, 1)) {
|
|
logger.debug("waitNSESuspended check suspended timeout")
|
|
if state != .suspended {
|
|
notifySuspended(false)
|
|
}
|
|
}
|
|
}
|
|
}
|