diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-09-25 16:34:23 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-09-26 16:35:38 +0200 |
| commit | f389956c2cd884df142adbf00ff2ac7e2f69c2b2 (patch) | |
| tree | 5f7d4869324760eb4ba0107c0356edc89efd1457 /ios/Operations/AsyncOperationQueue.swift | |
| parent | 2e83b1ca27ff243a615ff10c94c20840b38dfd45 (diff) | |
| download | mullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.tar.xz mullvadvpn-f389956c2cd884df142adbf00ff2ac7e2f69c2b2.zip | |
Move AsyncOperation into Operations static library and add separate tests
Diffstat (limited to 'ios/Operations/AsyncOperationQueue.swift')
| -rw-r--r-- | ios/Operations/AsyncOperationQueue.swift | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/ios/Operations/AsyncOperationQueue.swift b/ios/Operations/AsyncOperationQueue.swift new file mode 100644 index 0000000000..1c62038671 --- /dev/null +++ b/ios/Operations/AsyncOperationQueue.swift @@ -0,0 +1,98 @@ +// +// AsyncOperationQueue.swift +// MullvadVPN +// +// Created by pronebird on 30/05/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +public class AsyncOperationQueue: OperationQueue { + override public func addOperation(_ operation: Operation) { + if let operation = operation as? AsyncOperation { + let categories = operation.conditions + .filter { condition in + return condition.isMutuallyExclusive + } + .map { condition in + return condition.name + } + + if !categories.isEmpty { + ExclusivityManager.shared.addOperation(operation, categories: Set(categories)) + } + + super.addOperation(operation) + + operation.didEnqueue() + } else { + super.addOperation(operation) + } + } + + override public func addOperations(_ operations: [Operation], waitUntilFinished wait: Bool) { + for operation in operations { + addOperation(operation) + } + + if wait { + for operation in operations { + operation.waitUntilFinished() + } + } + } +} + +private final class ExclusivityManager { + static let shared = ExclusivityManager() + + private var operationsByCategory = [String: [Operation]]() + private let nslock = NSLock() + + private init() {} + + func addOperation(_ operation: AsyncOperation, categories: Set<String>) { + nslock.lock() + defer { nslock.unlock() } + + for category in categories { + var operations = operationsByCategory[category] ?? [] + + if let lastOperation = operations.last { + operation.addDependency(lastOperation) + } + + operations.append(operation) + + operationsByCategory[category] = operations + + let blockObserver = OperationBlockObserver(didFinish: { [weak self] op, error in + self?.removeOperation(op, categories: categories) + }) + + operation.addObserver(blockObserver) + } + } + + private func removeOperation(_ operation: Operation, categories: Set<String>) { + nslock.lock() + defer { nslock.unlock() } + + for category in categories { + guard var operations = operationsByCategory[category] else { + continue + } + + if let index = operations.firstIndex(of: operation) { + operations.remove(at: index) + } + + if operations.isEmpty { + operationsByCategory.removeValue(forKey: category) + } else { + operationsByCategory[category] = operations + } + } + } +} |
