/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-iphone
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
import Foundation
import NetworkExtension
import linphonesw
import Combine
let localPushProviderBundleIdentifier = "org.linphone.phone.localpushprovider"
@available(iOS 15.0, *)
@objc class LocalPushManager : NSObject, NEAppPushDelegate {
@objc static let shared = LocalPushManager()
private var appPushManager: NEAppPushManager?
private let isInitialized = MutableLiveData(false)
let isActive = MutableLiveData(false)
private let dispatchQueue = DispatchQueue(label: "DirectoryViewModel.dispatchQueue")
private let pushManagerIsActiveSubject = CurrentValueSubject(false)
private var pushManagerIsActiveCancellable: AnyCancellable?
private var cancellables = Set()
private(set) lazy var pushManagerIsActivePublisher = {
pushManagerIsActiveSubject
.debounce(for: .milliseconds(500), scheduler: dispatchQueue)
.eraseToAnyPublisher()
}()
override init() {
super.init()
NEAppPushManager.loadAllFromPreferences { managers, error in
if let error = error {
Log.e("[LocalPushManager] Failed to load all NEAppPushManager's from preferences: \(error)")
self.isInitialized.value = true
return
}
self.appPushManager = managers?.first ?? NEAppPushManager()
let appPushManager = self.appPushManager!
self.pushManagerIsActiveCancellable = NSObject.KeyValueObservingPublisher(object: appPushManager, keyPath: \.isActive, options: [.initial, .new])
.subscribe(self.pushManagerIsActiveSubject)
self.pushManagerIsActivePublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] isAppPushManagerActive in
self?.isActive.value = isAppPushManagerActive
}
.store(in: &self.cancellables)
appPushManager.delegate = self
self.isInitialized.value = true
Log.i("[LocalPushManager] NEAppPushManager initialisation : enabled=\(String(describing: appPushManager.isEnabled)) ssids=\(String(describing: appPushManager.matchSSIDs))")
}
}
@objc func extensionIsActive() -> Bool {
return appPushManager?.isActive == true
}
private func applyConfig(coreConfig:Config) {
let appPushManager = self.appPushManager!
let ssids = coreConfig.getStringList(section: "local_push", key: "ssids", defaultList: []) // csv
let enabled = !ssids.isEmpty
appPushManager.isEnabled = enabled
appPushManager.matchSSIDs = ssids
appPushManager.providerConfiguration = [
"coreconfig": coreConfig.dump()
]
appPushManager.localizedDescription = NSLocalizedString("Local Push Manager", comment: "")
appPushManager.providerBundleIdentifier = localPushProviderBundleIdentifier
if (appPushManager.isEnabled) {
self.pushManagerIsActiveCancellable = NSObject.KeyValueObservingPublisher(object: appPushManager, keyPath: \.isActive, options: [.initial, .new])
.subscribe(self.pushManagerIsActiveSubject)
appPushManager.saveToPreferences { error in
if (error != nil) {
Log.e("[LocalPushManager] error saving Local Push preferences \(String(describing: error))")
} else {
Log.i("[LocalPushManager] NEAppPushManager saved : enabled=\(String(describing: appPushManager.isEnabled)) ssids=\(String(describing: appPushManager.matchSSIDs))")
}
}
} else {
pushManagerIsActiveSubject.send(false)
Log.i("[LocalPushManager] NEAppPushManager disabled.")
}
}
@objc func configureLocalPush(cCoreConfig:OpaquePointer) {
if (self.isInitialized.value != true ) {
self.isInitialized.observeOnce { _ in
self.applyConfig(coreConfig: Config.getSwiftObject(cObject: cCoreConfig))
}
} else {
applyConfig(coreConfig: Config.getSwiftObject(cObject: cCoreConfig))
}
}
func appPushManager(_ manager: NEAppPushManager, didReceiveIncomingCallWithUserInfo userInfo: [AnyHashable : Any] = [:]) {
// Call handling
}
@objc func addActiveCallBackObserver (action:@escaping(Bool) -> Void) {
isActive.readCurrentAndObserve { active in
action(active!)
}
}
}