diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-03-23 14:42:08 +0100 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-03-31 14:39:43 +0200 |
| commit | d71995c950f87e0866862bc2c6191d2e2e59deb8 (patch) | |
| tree | 4c741062a0cacf05a62ce36c77bc66d81ed55f52 | |
| parent | a0735ca20791a33b4f0ac613f3488959cf07c93a (diff) | |
| download | mullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.tar.xz mullvadvpn-d71995c950f87e0866862bc2c6191d2e2e59deb8.zip | |
Add ResultOperation
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 6 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/ResultOperation.swift | 77 |
2 files changed, 82 insertions, 1 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index 266f67eafe..65cf355107 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -273,6 +273,7 @@ 58F559102697002100F630D0 /* HeaderBar.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F559092697002100F630D0 /* HeaderBar.strings */; }; 58F61F4F2692F21C00DCFC2B /* WireguardKeys.strings in Resources */ = {isa = PBXBuildFile; fileRef = 58F61F4D2692F21C00DCFC2B /* WireguardKeys.strings */; }; 58F7CA882692E34000FC59FD /* WireguardKeysContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */; }; + 58F7D26527EB50A300E4D821 /* ResultOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F7D26427EB50A300E4D821 /* ResultOperation.swift */; }; 58F840B22464491D0044E708 /* ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F840B12464491D0044E708 /* ChainedError.swift */; }; 58F840B32464491D0044E708 /* ChainedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F840B12464491D0044E708 /* ChainedError.swift */; }; 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */; }; @@ -548,6 +549,7 @@ 58F5590A2697002100F630D0 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/HeaderBar.strings; sourceTree = "<group>"; }; 58F61F4E2692F21C00DCFC2B /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/WireguardKeys.strings; sourceTree = "<group>"; }; 58F7CA872692E34000FC59FD /* WireguardKeysContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WireguardKeysContentView.swift; sourceTree = "<group>"; }; + 58F7D26427EB50A300E4D821 /* ResultOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResultOperation.swift; sourceTree = "<group>"; }; 58F840B12464491D0044E708 /* ChainedError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainedError.swift; sourceTree = "<group>"; }; 58F8AC0D25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProblemReportReviewViewController.swift; sourceTree = "<group>"; }; 58FAEDEB245059F000CB0F5B /* KeychainAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainAttributes.swift; sourceTree = "<group>"; }; @@ -632,9 +634,10 @@ 580EE22324B3243100F9D8A1 /* AsyncBlockOperation.swift */, 58E973DD24850EB600096F90 /* AsyncOperation.swift */, 580EE20524B3222200F9D8A1 /* ExclusivityController.swift */, + 5840BE34279EDB16002836BA /* OperationCompletion.swift */, 5820675D26E6839900655B05 /* PresentAlertOperation.swift */, 5846226426E0D9630035F7C2 /* ProductsRequestOperation.swift */, - 5840BE34279EDB16002836BA /* OperationCompletion.swift */, + 58F7D26427EB50A300E4D821 /* ResultOperation.swift */, ); path = Operations; sourceTree = "<group>"; @@ -1290,6 +1293,7 @@ 585DA87D26B0254000B8C587 /* RelayCacheIO.swift in Sources */, 582AD44027BE616E002A6BFC /* CodingErrors+ChainedError.swift in Sources */, 58F2E148276A307400A79513 /* MapConnectionStatusOperation.swift in Sources */, + 58F7D26527EB50A300E4D821 /* ResultOperation.swift in Sources */, 58BA693123EADA6A009DC256 /* SimulatorTunnelProvider.swift in Sources */, 58F1311327E09B00007AC5BC /* Cancellable.swift in Sources */, 587C575326D2615F005EF767 /* PacketTunnelOptions.swift in Sources */, diff --git a/ios/MullvadVPN/Operations/ResultOperation.swift b/ios/MullvadVPN/Operations/ResultOperation.swift new file mode 100644 index 0000000000..ba2cd59c4e --- /dev/null +++ b/ios/MullvadVPN/Operations/ResultOperation.swift @@ -0,0 +1,77 @@ +// +// ResultOperation.swift +// MullvadVPN +// +// Created by pronebird on 23/03/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +/// Base class for operations producing result. +class ResultOperation<Success, Failure: Error>: AsyncOperation { + typealias Completion = OperationCompletion<Success, Failure> + typealias CompletionHandler = (Completion) -> Void + + private let stateLock = NSLock() + private var completionValue: Completion? + private let completionQueue: DispatchQueue? + private var completionHandler: CompletionHandler? + + var completion: Completion? { + stateLock.lock() + defer { stateLock.unlock() } + return completionValue + } + + init(completionQueue: DispatchQueue?, completionHandler: CompletionHandler?) { + self.completionQueue = completionQueue + self.completionHandler = completionHandler + + super.init() + } + + override func finish() { + // Propagate cancellation if finish() is called directly from start(). + if isCancelled { + finish(completion: .cancelled) + } else { + preconditionFailure("Use finish(completion:) to finish operation.") + } + } + + func finish(completion: Completion) { + stateLock.lock() + + // Bail if operation is already finishing. + guard completionValue == nil else { + stateLock.unlock() + return + } + + // Store completion value. + completionValue = completion + + // Copy completion handler. + let completionHandler: CompletionHandler? = self.completionHandler + + // Unset completion handler. + self.completionHandler = nil + + stateLock.unlock() + + let block = { + // Call completion handler. + completionHandler?(completion) + + // Finish operation. + super.finish() + } + + if let completionQueue = completionQueue { + completionQueue.async(execute: block) + } else { + block() + } + } +} |
