forked from mirrors/linphone-iphone
Refactoring of LocalPushProvider + Aggregation mecanism (3 seconds by default)
This commit is contained in:
parent
b966c34868
commit
35f4dec79f
1 changed files with 104 additions and 39 deletions
|
|
@ -23,42 +23,62 @@ import NetworkExtension
|
|||
import UserNotifications
|
||||
import linphonesw
|
||||
import os
|
||||
import linphone
|
||||
|
||||
let APP_GROUP_ID = "group.org.linphone.phone.msgNotification"
|
||||
|
||||
class LocalPushProvider: NEAppPushProvider, CoreDelegate {
|
||||
extension String: Error {}
|
||||
|
||||
class LocalPushProvider: NEAppPushProvider {
|
||||
var core: Core? = nil
|
||||
let log = LoggingService.Instance
|
||||
var logDelegate: LinphoneLoggingServiceManager!
|
||||
var coreDelegateStub : CoreDelegateStub? = nil
|
||||
let defaults = UserDefaults.init(suiteName: APP_GROUP_ID)
|
||||
var coreIteratorTimer:Timer? = nil
|
||||
var aggretatorTimer:Timer? = nil
|
||||
var aggregagor:[ChatMessage] = []
|
||||
|
||||
func createAndStartCore() {
|
||||
func createCore() throws {
|
||||
coreDelegateStub = CoreDelegateStub(
|
||||
onMessageReceived: { (core:Core, chatRoom:ChatRoom, message:ChatMessage) -> Void in
|
||||
if (self.ignoredContentTypes.contains(message.contentType)) {
|
||||
self.log.error(message: "Received unexpected content type.\(message.contentType)")
|
||||
} else {
|
||||
self.aggregagor.append(message)
|
||||
}
|
||||
}
|
||||
)
|
||||
guard let configString = providerConfiguration?["coreconfig"] as? String, let config = Config.newFromBuffer(buffer: configString) else {
|
||||
self.log.error(message: "Unable to get core config through provider configuration")
|
||||
return
|
||||
log.error(message: "Unable to get core config through provider configuration")
|
||||
throw "Unable to get core config through provider configuration"
|
||||
}
|
||||
logDelegate = try LinphoneLoggingServiceManager(config: config, log: log, domain: "LocalPushProvider")
|
||||
|
||||
// Ensure a separate UUID from app is used, use previously generated one or a new one if n/a.
|
||||
|
||||
if let uuid = defaults?.string(forKey: "misc_uuid") {
|
||||
config.setString(section: "misc", key: "uuid", value: uuid)
|
||||
} else {
|
||||
config.cleanEntry(section: "misc", key: "uuid")
|
||||
}
|
||||
logDelegate = try! LinphoneLoggingServiceManager(config: config, log: log, domain: "LocalPushProvider")
|
||||
core = try! Factory.Instance.createCoreWithConfig(config: config, systemContext: nil)
|
||||
core?.autoIterateEnabled = false // 20ms auto-iterations are too frequent for NE, it gets killed by the OS. (limit of 150 wakeups per second over 300 seconds)
|
||||
core!.addDelegate(delegate: self)
|
||||
let timer = Timer(timeInterval: 0.5, target: self, selector: #selector(iterate), userInfo: nil, repeats: true) // 0.5 second
|
||||
RunLoop.main.add(timer, forMode: .default)
|
||||
try?core?.start()
|
||||
core?.addDelegate(delegate: coreDelegateStub!)
|
||||
log.message(message: "core started")
|
||||
|
||||
// Keep generated UUID to avoid re-creating one every time the NE is starting.
|
||||
if (core!.config!.hasEntry(section: "misc", key: "uuid") != 0) {
|
||||
defaults?.set(core!.config!.getString(section: "misc", key: "uuid", defaultString: ""), forKey: "misc_uuid")
|
||||
self.log.message(message: "storing generated UUID \(String(describing: defaults?.string(forKey: "misc_uuid")))")
|
||||
log.message(message: "Creating LocalPushProvider core with configuration : \(config.dump())")
|
||||
core = try Factory.Instance.createCoreWithConfig(config: config, systemContext: nil)
|
||||
core?.autoIterateEnabled = false // 20ms auto-iterations are too frequent for NE, sometimes it gets killed by the OS. (triggers limit exceed of 150 wakeups per second over 300 seconds)
|
||||
core?.addDelegate(delegate: coreDelegateStub!)
|
||||
coreIteratorTimer = Timer(timeInterval: 0.1, target: self, selector: #selector(iterate), userInfo: nil, repeats: true) // 0.1 second
|
||||
RunLoop.main.add(coreIteratorTimer!, forMode: .default)
|
||||
|
||||
let aggregateTime = config.getInt(section: "local_push", key: "notif_aggregation_period", defaultValue: 3)
|
||||
aggretatorTimer = Timer(timeInterval: TimeInterval(aggregateTime), target: self, selector: #selector(flushAggregator), userInfo: nil, repeats: true) // 0.1 second
|
||||
RunLoop.main.add(aggretatorTimer!, forMode: .default)
|
||||
|
||||
|
||||
core?.accountList.forEach { account in
|
||||
let params = account.params?.clone()
|
||||
params?.expires = 60 // handleTimerEvent(), called by the OS, refreshes registers every 60 seconds, we don't need to expiration longer as if it's not refreshed it means the extension is not reachable.
|
||||
account.params = params
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,28 +86,59 @@ class LocalPushProvider: NEAppPushProvider, CoreDelegate {
|
|||
core?.iterate()
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
coreDelegateStub = CoreDelegateStub(
|
||||
onMessageReceived: { (core:Core, chatRoom:ChatRoom, message:ChatMessage) -> Void in
|
||||
self.showLocalNotification(message: message)
|
||||
@objc func flushAggregator() {
|
||||
if (aggregagor.count == 1) {
|
||||
showLocalNotification(message: aggregagor[0])
|
||||
} else if (aggregagor.count > 1) {
|
||||
var displayNames : [String] = []
|
||||
aggregagor.forEach { message in
|
||||
let displayName = getDisplayName(message: message)
|
||||
if (!displayNames.contains(displayName)) {
|
||||
displayNames.append(displayName)
|
||||
}
|
||||
}
|
||||
)
|
||||
displayNames.sort()
|
||||
showMultipleMessagesNotifications(count: aggregagor.count,displayNames: displayNames.joined(separator: ","))
|
||||
}
|
||||
aggregagor.removeAll()
|
||||
}
|
||||
|
||||
// MARK: - NEAppPushProvider Life Cycle
|
||||
|
||||
|
||||
override func start() {
|
||||
createAndStartCore()
|
||||
// MARK: - NEAppPushProvider Life Cycle
|
||||
|
||||
override func start(completionHandler: @escaping (Error?) -> Void) {
|
||||
do {
|
||||
if (core == nil) {
|
||||
try createCore()
|
||||
log.message(message: "Creating core")
|
||||
}
|
||||
try core?.start()
|
||||
coreIteratorTimer?.fire()
|
||||
aggretatorTimer?.fire()
|
||||
log.message(message: "Core started")
|
||||
// Keep freshly generated UUID after start to avoid re-creating one every time the NE is starting.
|
||||
if (core?.config?.hasEntry(section: "misc", key: "uuid") != 0) {
|
||||
defaults?.set(core?.config?.getString(section: "misc", key: "uuid", defaultString: ""), forKey: "misc_uuid")
|
||||
log.message(message: "storing generated UUID \(String(describing: defaults?.string(forKey: "misc_uuid")))")
|
||||
}
|
||||
completionHandler(nil)
|
||||
} catch {
|
||||
completionHandler(error)
|
||||
}
|
||||
}
|
||||
|
||||
override func stop(with reason: NEProviderStopReason, completionHandler: @escaping () -> Void) {
|
||||
log.message(message: "Received stop for reason \(reason)")
|
||||
core?.stopAsync()
|
||||
coreIteratorTimer?.invalidate()
|
||||
aggretatorTimer?.invalidate()
|
||||
flushAggregator()
|
||||
completionHandler()
|
||||
}
|
||||
|
||||
override func handleTimerEvent() {
|
||||
self.log.message(message: "Refreshing registers (handleTimerEvent)")
|
||||
log.message(message: "Refreshing registers (handleTimerEvent)")
|
||||
core?.refreshRegisters()
|
||||
}
|
||||
|
||||
|
|
@ -95,12 +146,31 @@ class LocalPushProvider: NEAppPushProvider, CoreDelegate {
|
|||
|
||||
let ignoredContentTypes = ["message/imdn+xml","application/im-iscomposing+xml"]
|
||||
|
||||
func showLocalNotification(message: ChatMessage) {
|
||||
|
||||
if (ignoredContentTypes.contains(message.contentType)) {
|
||||
self.log.error(message: "Received unexpected content type.\(message.contentType)")
|
||||
return
|
||||
func showMultipleMessagesNotifications(count:Int, displayNames: String) {
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = NSLocalizedString("%s messages received", comment: "").replacingOccurrences(of: "%s", with: String(count))
|
||||
content.body = NSLocalizedString("from: %s", comment: "").replacingOccurrences(of: "%s", with: displayNames)
|
||||
content.sound = UNNotificationSound(named: UNNotificationSoundName("msg.caf"))
|
||||
content.categoryIdentifier = "app_active"
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(request) { error in
|
||||
if let error = error {
|
||||
self.log.error(message: "Error submitting local notification: \(error)")
|
||||
return
|
||||
}
|
||||
self.log.message(message: "Local notification posted successfully")
|
||||
}
|
||||
}
|
||||
|
||||
func getDisplayName(message:ChatMessage) -> String {
|
||||
let fromAddr = message.chatRoom?.peerAddress?.asStringUriOnly()
|
||||
var displayName = fromAddr?.getDisplayNameFromSipAddress(lc: core!, logger: log, groupId: APP_GROUP_ID)
|
||||
displayName = displayName != nil ? displayName : message.chatRoom?.peerAddress?.displayName
|
||||
displayName = displayName != nil && displayName?.isEmpty != true ? displayName :message.chatRoom?.peerAddress?.username
|
||||
return displayName!
|
||||
}
|
||||
|
||||
func showLocalNotification(message: ChatMessage) {
|
||||
|
||||
var messageContent = ""
|
||||
if (message.hasConferenceInvitationContent()) {
|
||||
|
|
@ -109,15 +179,10 @@ class LocalPushProvider: NEAppPushProvider, CoreDelegate {
|
|||
messageContent = message.hasTextContent() ? message.utf8Text : "🗻"
|
||||
}
|
||||
|
||||
let fromAddr = message.chatRoom?.peerAddress?.asStringUriOnly()
|
||||
var displayName = fromAddr?.getDisplayNameFromSipAddress(lc: core!, logger: log, groupId: APP_GROUP_ID)
|
||||
displayName = displayName != nil ? displayName : message.chatRoom?.peerAddress?.displayName
|
||||
displayName = displayName != nil && displayName?.isEmpty != true ? displayName :message.chatRoom?.peerAddress?.username
|
||||
|
||||
let content = UNMutableNotificationContent()
|
||||
content.title = displayName!
|
||||
content.title = getDisplayName(message:message)
|
||||
content.body = messageContent
|
||||
content.sound = .default
|
||||
content.sound = UNNotificationSound(named: UNNotificationSoundName("msg.caf"))
|
||||
content.categoryIdentifier = "app_active"
|
||||
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil)
|
||||
UNUserNotificationCenter.current().add(request) { error in
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue