|
|
|
|
@ -7,7 +7,6 @@ import Foundation
|
|
|
|
|
@objc(OWSContactDiscoveryOperation)
|
|
|
|
|
class ContactDiscoveryOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
// TODO verify proper batch size
|
|
|
|
|
let batchSize = 2048
|
|
|
|
|
let recipientIdsToLookup: [String]
|
|
|
|
|
|
|
|
|
|
@ -49,9 +48,15 @@ class ContactDiscoveryOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
class LegacyContactDiscoveryBatchOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
private let recipientIdsToLookup: [String]
|
|
|
|
|
var registeredRecipientIds: Set<String>
|
|
|
|
|
|
|
|
|
|
private let recipientIdsToLookup: [String]
|
|
|
|
|
private var networkManager: TSNetworkManager {
|
|
|
|
|
return TSNetworkManager.shared()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Initializers
|
|
|
|
|
|
|
|
|
|
required init(recipientIdsToLookup: [String]) {
|
|
|
|
|
self.recipientIdsToLookup = recipientIdsToLookup
|
|
|
|
|
self.registeredRecipientIds = Set()
|
|
|
|
|
@ -61,10 +66,61 @@ class LegacyContactDiscoveryBatchOperation: OWSOperation {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function) with recipientIdsToLookup: \(recipientIdsToLookup.count)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private var networkManager: TSNetworkManager {
|
|
|
|
|
return TSNetworkManager.shared()
|
|
|
|
|
// MARK: OWSOperation Overrides
|
|
|
|
|
|
|
|
|
|
// Called every retry, this is where the bulk of the operation's work should go.
|
|
|
|
|
override func run() {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function)")
|
|
|
|
|
|
|
|
|
|
var phoneNumbersByHashes: [String: String] = [:]
|
|
|
|
|
|
|
|
|
|
for recipientId in recipientIdsToLookup {
|
|
|
|
|
let hash = Cryptography.truncatedSHA1Base64EncodedWithoutPadding(recipientId)
|
|
|
|
|
phoneNumbersByHashes[hash] = recipientId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let hashes: [String] = Array(phoneNumbersByHashes.keys)
|
|
|
|
|
|
|
|
|
|
let request = OWSRequestFactory.contactsIntersectionRequest(withHashesArray: hashes)
|
|
|
|
|
|
|
|
|
|
self.networkManager.makeRequest(request,
|
|
|
|
|
success: { (task, responseDict) in
|
|
|
|
|
do {
|
|
|
|
|
self.registeredRecipientIds = try self.parse(response: responseDict, phoneNumbersByHashes: phoneNumbersByHashes)
|
|
|
|
|
self.reportSuccess()
|
|
|
|
|
} catch {
|
|
|
|
|
self.reportError(error)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
failure: { (task, error) in
|
|
|
|
|
guard let response = task.response as? HTTPURLResponse else {
|
|
|
|
|
let responseError: NSError = OWSErrorMakeUnableToProcessServerResponseError() as NSError
|
|
|
|
|
responseError.isRetryable = true
|
|
|
|
|
self.reportError(responseError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (response.statusCode == 413) {
|
|
|
|
|
let rateLimitError = OWSErrorWithCodeDescription(OWSErrorCode.contactsUpdaterRateLimit, "Contacts Intersection Rate Limit")
|
|
|
|
|
self.reportError(rateLimitError)
|
|
|
|
|
}
|
|
|
|
|
self.reportError(error)
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Called at most one time.
|
|
|
|
|
override func didSucceed() {
|
|
|
|
|
// Compare against new CDS service
|
|
|
|
|
let newCDSBatchOperation = CDSBatchOperation(recipientIdsToLookup: self.recipientIdsToLookup)
|
|
|
|
|
let cdsFeedbackOperation = CDSFeedbackOperation(legacyRegisteredRecipientIds: self.registeredRecipientIds)
|
|
|
|
|
cdsFeedbackOperation.addDependency(newCDSBatchOperation)
|
|
|
|
|
|
|
|
|
|
CDSFeedbackOperation.operationQueue.addOperations([newCDSBatchOperation, cdsFeedbackOperation], waitUntilFinished: false)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Private Helpers
|
|
|
|
|
|
|
|
|
|
private func parse(response: Any?, phoneNumbersByHashes: [String: String]) throws -> Set<String> {
|
|
|
|
|
|
|
|
|
|
guard let responseDict = response as? [String: AnyObject] else {
|
|
|
|
|
@ -105,68 +161,43 @@ class LegacyContactDiscoveryBatchOperation: OWSOperation {
|
|
|
|
|
return registeredRecipientIds
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Mandatory overrides
|
|
|
|
|
|
|
|
|
|
// Called every retry, this is where the bulk of the operation's work should go.
|
|
|
|
|
override func run() {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function)")
|
|
|
|
|
|
|
|
|
|
var phoneNumbersByHashes: [String: String] = [:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for recipientId in recipientIdsToLookup {
|
|
|
|
|
let hash = Cryptography.truncatedSHA1Base64EncodedWithoutPadding(recipientId)
|
|
|
|
|
phoneNumbersByHashes[hash] = recipientId
|
|
|
|
|
}
|
|
|
|
|
class CDSBatchOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
let hashes: [String] = Array(phoneNumbersByHashes.keys)
|
|
|
|
|
private let recipientIdsToLookup: [String]
|
|
|
|
|
var registeredRecipientIds: Set<String>
|
|
|
|
|
|
|
|
|
|
let request = OWSRequestFactory.contactsIntersectionRequest(withHashesArray: hashes)
|
|
|
|
|
// MARK: Initializers
|
|
|
|
|
|
|
|
|
|
self.networkManager.makeRequest(request,
|
|
|
|
|
success: { (task, responseDict) in
|
|
|
|
|
do {
|
|
|
|
|
self.registeredRecipientIds = try self.parse(response: responseDict, phoneNumbersByHashes: phoneNumbersByHashes)
|
|
|
|
|
self.reportSuccess()
|
|
|
|
|
} catch {
|
|
|
|
|
self.reportError(error)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
failure: { (task, error) in
|
|
|
|
|
guard let response = task.response as? HTTPURLResponse else {
|
|
|
|
|
let responseError: NSError = OWSErrorMakeUnableToProcessServerResponseError() as NSError
|
|
|
|
|
responseError.isRetryable = true
|
|
|
|
|
self.reportError(responseError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
required init(recipientIdsToLookup: [String]) {
|
|
|
|
|
self.recipientIdsToLookup = recipientIdsToLookup
|
|
|
|
|
self.registeredRecipientIds = Set()
|
|
|
|
|
|
|
|
|
|
if (response.statusCode == 413) {
|
|
|
|
|
let rateLimitError = OWSErrorWithCodeDescription(OWSErrorCode.contactsUpdaterRateLimit, "Contacts Intersection Rate Limit")
|
|
|
|
|
self.reportError(rateLimitError)
|
|
|
|
|
}
|
|
|
|
|
self.reportError(error)
|
|
|
|
|
super.init()
|
|
|
|
|
|
|
|
|
|
})
|
|
|
|
|
Logger.debug("\(logTag) in \(#function) with recipientIdsToLookup: \(recipientIdsToLookup.count)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Optional Overrides
|
|
|
|
|
// MARK: OWSOperationOverrides
|
|
|
|
|
|
|
|
|
|
// Called at most one time.
|
|
|
|
|
override func didSucceed() {
|
|
|
|
|
// Compare against new CDS service
|
|
|
|
|
let newCDSBatchOperation = CDSBatchOperation(recipientIdsToLookup: self.recipientIdsToLookup)
|
|
|
|
|
let cdsFeedbackOperation = CDSFeedbackOperation(legacyRegisteredRecipientIds: self.registeredRecipientIds)
|
|
|
|
|
cdsFeedbackOperation.addDependency(newCDSBatchOperation)
|
|
|
|
|
// Called every retry, this is where the bulk of the operation's work should go.
|
|
|
|
|
override func run() {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function)")
|
|
|
|
|
|
|
|
|
|
CDSFeedbackOperation.operationQueue.addOperations([newCDSBatchOperation, cdsFeedbackOperation], waitUntilFinished: false)
|
|
|
|
|
Logger.debug("\(logTag) in \(#function) FAKING intersection (TODO)")
|
|
|
|
|
self.registeredRecipientIds = Set(self.recipientIdsToLookup)
|
|
|
|
|
self.reportSuccess()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CDSFeedbackOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
static let operationQueue = OperationQueue()
|
|
|
|
|
|
|
|
|
|
let legacyRegisteredRecipientIds: Set<String>
|
|
|
|
|
private let legacyRegisteredRecipientIds: Set<String>
|
|
|
|
|
|
|
|
|
|
// MARK: Initializers
|
|
|
|
|
|
|
|
|
|
required init(legacyRegisteredRecipientIds: Set<String>) {
|
|
|
|
|
self.legacyRegisteredRecipientIds = legacyRegisteredRecipientIds
|
|
|
|
|
@ -176,7 +207,7 @@ class CDSFeedbackOperation: OWSOperation {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Mandatory overrides
|
|
|
|
|
// MARK: OWSOperation Overrides
|
|
|
|
|
|
|
|
|
|
// Called every retry, this is where the bulk of the operation's work should go.
|
|
|
|
|
override func run() {
|
|
|
|
|
@ -208,32 +239,6 @@ class CDSFeedbackOperation: OWSOperation {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CDSBatchOperation: OWSOperation {
|
|
|
|
|
|
|
|
|
|
private let recipientIdsToLookup: [String]
|
|
|
|
|
var registeredRecipientIds: Set<String>
|
|
|
|
|
|
|
|
|
|
required init(recipientIdsToLookup: [String]) {
|
|
|
|
|
self.recipientIdsToLookup = recipientIdsToLookup
|
|
|
|
|
self.registeredRecipientIds = Set()
|
|
|
|
|
|
|
|
|
|
super.init()
|
|
|
|
|
|
|
|
|
|
Logger.debug("\(logTag) in \(#function) with recipientIdsToLookup: \(recipientIdsToLookup.count)")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// MARK: Mandatory overrides
|
|
|
|
|
|
|
|
|
|
// Called every retry, this is where the bulk of the operation's work should go.
|
|
|
|
|
override func run() {
|
|
|
|
|
Logger.debug("\(logTag) in \(#function)")
|
|
|
|
|
|
|
|
|
|
Logger.debug("\(logTag) in \(#function) FAKING intersection (TODO)")
|
|
|
|
|
self.registeredRecipientIds = Set(self.recipientIdsToLookup)
|
|
|
|
|
self.reportSuccess()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extension Array {
|
|
|
|
|
func chunked(by chunkSize: Int) -> [[Element]] {
|
|
|
|
|
return stride(from: 0, to: self.count, by: chunkSize).map {
|
|
|
|
|
|