// // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // import PromiseKit @objc(OWSSyncPushTokensJob) class SyncPushTokensJob: NSObject { let TAG = "[SyncPushTokensJob]" // MARK: Dependencies let accountManager: AccountManager let preferences: OWSPreferences var pushRegistrationManager: PushRegistrationManager { return PushRegistrationManager.shared } var uploadOnlyIfStale = true required init(accountManager: AccountManager, preferences: OWSPreferences) { self.accountManager = accountManager self.preferences = preferences } class func run(accountManager: AccountManager, preferences: OWSPreferences) -> Promise { let job = self.init(accountManager: accountManager, preferences: preferences) return job.run() } func run() -> Promise { Logger.info("\(TAG) Starting.") let runPromise: Promise = DispatchQueue.main.promise { // HACK: no-op dispatch to work around a bug in PromiseKit/Swift which won't compile // when dispatching complex Promise types. We should eventually be able to delete the // following two lines, skipping this no-op dispatch. return }.then { return self.pushRegistrationManager.requestPushTokens() }.then { (pushToken: String, voipToken: String) in Logger.info("\(self.TAG) finished: requesting push tokens") var shouldUploadTokens = false if self.preferences.getPushToken() != pushToken || self.preferences.getVoipToken() != voipToken { Logger.debug("\(self.TAG) Push tokens changed.") shouldUploadTokens = true } else if !self.uploadOnlyIfStale { Logger.debug("\(self.TAG) Forced uploading, even though tokens didn't change.") shouldUploadTokens = true } if AppVersion.instance().lastAppVersion != AppVersion.instance().currentAppVersion { Logger.info("\(self.TAG) Uploading due to fresh install or app upgrade.") shouldUploadTokens = true } guard shouldUploadTokens else { Logger.info("\(self.TAG) No reason to upload pushToken: \(pushToken), voipToken: \(voipToken)") return Promise(value: ()) } Logger.warn("\(self.TAG) uploading tokens to account servers. pushToken: \(pushToken), voipToken: \(voipToken)") return self.accountManager.updatePushTokens(pushToken:pushToken, voipToken:voipToken).then { Logger.info("\(self.TAG) successfully updated push tokens on server") return self.recordPushTokensLocally(pushToken:pushToken, voipToken:voipToken) } }.then { Logger.info("\(self.TAG) in \(#function): succeeded") }.catch { error in Logger.error("\(self.TAG) in \(#function): Failed with error: \(error).") } runPromise.retainUntilComplete() return runPromise } // MARK - objc wrappers, since objc can't use swift parameterized types @objc class func run(accountManager: AccountManager, preferences: OWSPreferences) -> AnyPromise { let promise: Promise = self.run(accountManager: accountManager, preferences: preferences) return AnyPromise(promise) } @objc func run() -> AnyPromise { let promise: Promise = self.run() return AnyPromise(promise) } private func recordPushTokensLocally(pushToken: String, voipToken: String) -> Promise { Logger.warn("\(TAG) Recording push tokens locally. pushToken: \(pushToken), voipToken: \(voipToken)") if (pushToken != self.preferences.getPushToken()) { Logger.info("\(TAG) Recording new plain push token") self.preferences.setPushToken(pushToken) } if (voipToken != self.preferences.getVoipToken()) { Logger.info("\(TAG) Recording new voip token") self.preferences.setVoipToken(voipToken) } return Promise(value: ()) } }