diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2022-05-31 19:06:29 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2022-06-13 15:04:21 +0200 |
| commit | f0265be30037f02a8eae37623a9c44c6420a8b0e (patch) | |
| tree | 36a53b3177153ebe663f3dcf9963a3d55136a982 | |
| parent | 25d17700f292fdb6a825404f817561347b80d30f (diff) | |
| download | mullvadvpn-f0265be30037f02a8eae37623a9c44c6420a8b0e.tar.xz mullvadvpn-f0265be30037f02a8eae37623a9c44c6420a8b0e.zip | |
Add transform operation
| -rw-r--r-- | ios/MullvadVPN.xcodeproj/project.pbxproj | 12 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/OutputOperation.swift | 15 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/ResultOperation+Output.swift | 15 | ||||
| -rw-r--r-- | ios/MullvadVPN/Operations/TransformOperation.swift | 127 |
4 files changed, 169 insertions, 0 deletions
diff --git a/ios/MullvadVPN.xcodeproj/project.pbxproj b/ios/MullvadVPN.xcodeproj/project.pbxproj index be16e9c4c6..6933de9e76 100644 --- a/ios/MullvadVPN.xcodeproj/project.pbxproj +++ b/ios/MullvadVPN.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 5801C9A527A14B2A0031566A /* TunnelManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5801C9A427A14B2A0031566A /* TunnelManagerState.swift */; }; + 58059DDC28465E8F002B1049 /* TransformOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58059DDB28465E8F002B1049 /* TransformOperation.swift */; }; + 58059DDE28468158002B1049 /* OutputOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58059DDD28468158002B1049 /* OutputOperation.swift */; }; + 58059DE02846823E002B1049 /* ResultOperation+Output.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58059DDF2846823E002B1049 /* ResultOperation+Output.swift */; }; 58059DE228468255002B1049 /* ResultOperation+Fallible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58059DE128468255002B1049 /* ResultOperation+Fallible.swift */; }; 5806767C27048E9B00C858CB /* PacketTunnelProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58CE5E7B224146470008646E /* PacketTunnelProvider.swift */; }; 5807483B27DB8A980020ECBF /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 5807483A27DB8A980020ECBF /* WireGuardKitTypes */; }; @@ -343,6 +346,9 @@ /* Begin PBXFileReference section */ 5801C9A427A14B2A0031566A /* TunnelManagerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelManagerState.swift; sourceTree = "<group>"; }; + 58059DDB28465E8F002B1049 /* TransformOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformOperation.swift; sourceTree = "<group>"; }; + 58059DDD28468158002B1049 /* OutputOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputOperation.swift; sourceTree = "<group>"; }; + 58059DDF2846823E002B1049 /* ResultOperation+Output.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultOperation+Output.swift"; sourceTree = "<group>"; }; 58059DE128468255002B1049 /* ResultOperation+Fallible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ResultOperation+Fallible.swift"; sourceTree = "<group>"; }; 5807E2BF2432038B00F5FF30 /* String+Split.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Split.swift"; sourceTree = "<group>"; }; 5807E2C1243203D000F5FF30 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = "<group>"; }; @@ -637,11 +643,14 @@ 5840BE34279EDB16002836BA /* OperationCompletion.swift */, 589D28772846250500F9A7B3 /* OperationCondition.swift */, 589D28792846250500F9A7B3 /* OperationObserver.swift */, + 58059DDD28468158002B1049 /* OutputOperation.swift */, 5820675D26E6839900655B05 /* PresentAlertOperation.swift */, 5846226426E0D9630035F7C2 /* ProductsRequestOperation.swift */, 58F7D26427EB50A300E4D821 /* ResultOperation.swift */, 5842102D282D3FC200F24E46 /* ResultBlockOperation.swift */, 58059DE128468255002B1049 /* ResultOperation+Fallible.swift */, + 58059DDF2846823E002B1049 /* ResultOperation+Output.swift */, + 58059DDB28465E8F002B1049 /* TransformOperation.swift */, ); path = Operations; sourceTree = "<group>"; @@ -1298,6 +1307,7 @@ 5875960726F36B3A00BF6711 /* TunnelIPCError.swift in Sources */, 58F8AC0E25D3F8CE002BE0ED /* ProblemReportReviewViewController.swift in Sources */, 58CCA010224249A1004F3011 /* ConnectViewController.swift in Sources */, + 58059DE02846823E002B1049 /* ResultOperation+Output.swift in Sources */, 588BCF282816D664009ADCEC /* RESTResponseHandler.swift in Sources */, 58554F77280AFD5C00013055 /* RESTTaskIdentifier.swift in Sources */, 58BFA5C622A7C97F00A6173D /* RelayCacheTracker.swift in Sources */, @@ -1423,6 +1433,7 @@ 584592612639B4A200EF967F /* ConsentContentView.swift in Sources */, 58B5A895280AACC4009FDE99 /* RESTRequestFactory.swift in Sources */, 584EBDBD2747C98F00A0C9FD /* NSAttributedString+Markdown.swift in Sources */, + 58059DDC28465E8F002B1049 /* TransformOperation.swift in Sources */, 5875960A26F371FC00BF6711 /* TunnelIPCSession.swift in Sources */, 58FB865E26EA284E00F188BC /* LogFormatting.swift in Sources */, 585DA88726B0277200B8C587 /* RESTError.swift in Sources */, @@ -1444,6 +1455,7 @@ 58FD5BF22424F7D700112C88 /* UserInterfaceInteractionRestriction.swift in Sources */, 5811DE50239014550011EB53 /* NEVPNStatus+Debug.swift in Sources */, 58C3A4B222456F1B00340BDB /* AccountInputGroupView.swift in Sources */, + 58059DDE28468158002B1049 /* OutputOperation.swift in Sources */, 589D287B2846250500F9A7B3 /* AsyncOperationQueue.swift in Sources */, 58F840B22464491D0044E708 /* ChainedError.swift in Sources */, 588BCF24280FE43D009ADCEC /* RESTDevicesProxy.swift in Sources */, diff --git a/ios/MullvadVPN/Operations/OutputOperation.swift b/ios/MullvadVPN/Operations/OutputOperation.swift new file mode 100644 index 0000000000..0a7f50df5b --- /dev/null +++ b/ios/MullvadVPN/Operations/OutputOperation.swift @@ -0,0 +1,15 @@ +// +// OutputOperation.swift +// MullvadVPN +// +// Created by pronebird on 31/05/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +protocol OutputOperation: Operation { + associatedtype Output + + var output: Output? { get } +} diff --git a/ios/MullvadVPN/Operations/ResultOperation+Output.swift b/ios/MullvadVPN/Operations/ResultOperation+Output.swift new file mode 100644 index 0000000000..db5cd2a6e7 --- /dev/null +++ b/ios/MullvadVPN/Operations/ResultOperation+Output.swift @@ -0,0 +1,15 @@ +// +// ResultOperation+Output.swift +// MullvadVPN +// +// Created by pronebird on 31/05/2022. +// Copyright © 2022 Mullvad VPN AB. All rights reserved. +// + +import Foundation + +extension ResultOperation: OutputOperation { + var output: Success? { + return completion?.value + } +} diff --git a/ios/MullvadVPN/Operations/TransformOperation.swift b/ios/MullvadVPN/Operations/TransformOperation.swift new file mode 100644 index 0000000000..b09b5780c1 --- /dev/null +++ b/ios/MullvadVPN/Operations/TransformOperation.swift @@ -0,0 +1,127 @@ +// +// TransformOperation.swift +// AsyncOperationQueueTest +// +// Created by pronebird on 31/05/2022. +// + +import Foundation + +final class TransformOperation<Input, Output, Failure: Error>: ResultOperation<Output, Failure> { + typealias ExecutionBlock = ((Input, TransformOperation<Input, Output, Failure>) -> Void) + typealias ThrowingExecutionBlock = ((Input) throws -> Output) + + private var input: Input? + private var executionBlock: ExecutionBlock? + private var configurationBlocks: [() -> Void] = [] + private var cancellationBlocks: [() -> Void] = [] + + init( + dispatchQueue: DispatchQueue? = nil, + input: Input? = nil, + block: ExecutionBlock? = nil + ) + { + self.input = input + self.executionBlock = block + + super.init(dispatchQueue: dispatchQueue) + } + + convenience init( + dispatchQueue: DispatchQueue?, + input: Input? = nil, + block: @escaping ThrowingExecutionBlock + ) + { + self.init( + dispatchQueue: dispatchQueue, + input: input, + block: Self.wrapThrowingBlock(block) + ) + } + + override func main() { + for configurationBlock in configurationBlocks { + configurationBlock() + } + + configurationBlocks.removeAll() + + guard let input = input, let executionBlock = executionBlock else { + finish(completion: .cancelled) + return + } + + executionBlock(input, self) + } + + override func operationDidCancel() { + let blocks = cancellationBlocks + cancellationBlocks.removeAll() + + for block in blocks { + block() + } + } + + override func operationDidFinish() { + cancellationBlocks.removeAll() + executionBlock = nil + } + + func setExecutionBlock(_ block: @escaping ExecutionBlock) { + dispatchQueue.async { + assert(!self.isExecuting && !self.isFinished) + self.executionBlock = block + } + } + + func setExecutionBlock(_ block: @escaping ThrowingExecutionBlock) { + setExecutionBlock(Self.wrapThrowingBlock(block)) + } + + func addCancellationBlock(_ block: @escaping () -> Void) { + dispatchQueue.async { + if self.isCancelled { + block() + } else { + self.cancellationBlocks.append(block) + } + } + } + + func inject<T>(from dependency: T) where T: OutputOperation, T.Output == Input { + inject(from: dependency, via: { $0 }) + } + + func inject<T>(from dependency: T, via block: @escaping (T.Output) -> Input) where T: OutputOperation { + dispatchQueue.async { + self.configurationBlocks.append { [weak self] in + guard let self = self else { return } + + if let output = dependency.output { + self.input = block(output) + } + } + + } + addDependency(dependency) + } + + private class func wrapThrowingBlock(_ executionBlock: @escaping ThrowingExecutionBlock) -> ExecutionBlock { + return { input, operation in + do { + let value = try executionBlock(input) + + operation.finish(completion: .success(value)) + } catch { + let castedError = error as! Failure + + operation.finish(completion: .failure(castedError)) + } + } + } + +} + |
