summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2022-05-31 19:06:29 +0200
committerAndrej Mihajlov <and@mullvad.net>2022-06-13 15:04:21 +0200
commitf0265be30037f02a8eae37623a9c44c6420a8b0e (patch)
tree36a53b3177153ebe663f3dcf9963a3d55136a982
parent25d17700f292fdb6a825404f817561347b80d30f (diff)
downloadmullvadvpn-f0265be30037f02a8eae37623a9c44c6420a8b0e.tar.xz
mullvadvpn-f0265be30037f02a8eae37623a9c44c6420a8b0e.zip
Add transform operation
-rw-r--r--ios/MullvadVPN.xcodeproj/project.pbxproj12
-rw-r--r--ios/MullvadVPN/Operations/OutputOperation.swift15
-rw-r--r--ios/MullvadVPN/Operations/ResultOperation+Output.swift15
-rw-r--r--ios/MullvadVPN/Operations/TransformOperation.swift127
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))
+ }
+ }
+ }
+
+}
+