// // PingServersOperation.swift // PrivadoVPN // // Created by Juraldinio on 3/21/21. // Copyright © 2021 Privado LLC. All rights reserved. // import Foundation protocol PingServersOperationOutput { var result: MainOperationsResult? { get } } final class PingServersOperation: AsyncOperation { private enum Constants { static let maxConcurentOperations = 42 } typealias PingOperationProgressClosure = (Double) -> Void private(set) var result: MainOperationsResult? // PingServersOperationOutput private let operationQueue = OperationQueue() private var observation: NSKeyValueObservation? private var serversCount: Int = 0 private let progressClosure: PingOperationProgressClosure? init(progressClosure: PingOperationProgressClosure?) { self.progressClosure = progressClosure super.init() self.operationQueue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount == -1 ? Constants.maxConcurentOperations : min(Constants.maxConcurentOperations, OperationQueue.defaultMaxConcurrentOperationCount) self.operationQueue.isSuspended = true self.observation = self.operationQueue.whenEmptyOperations { [weak self] _ in self?.observation = nil self?.state = .finished } } override func main() { guard !self.isCancelled else { self.observation = nil self.state = .finished return } guard let convertingOutput = self.dependencies.first as? ConvertingServersOperationOutput , let result = convertingOutput.result , let servers = result.serverRecords else { self.observation = nil self.state = .finished return } self.result = result servers .execute { self.serversCount = $0.count } .compactMap { $0.server } .forEach { let operation = PingOperation(record: ServerPingRecord(server: $0)) operation.completionBlock = { [weak self] in guard let self = self, let progress = self.progressClosure else { return } progress( 1.0 - Double(self.operationQueue.operations.count) / Double(self.serversCount)) } self.operationQueue.addOperation(operation) } self.operationQueue.isSuspended = false } override func cancel() { self.operationQueue.cancelAllOperations() self.operationQueue.isSuspended = true super.cancel() } } extension PingServersOperation: PingServersOperationOutput { }