Skip to content

Commit d69d97c

Browse files
author
mojganii
committed
Fix getting stuck in blocked state after reconnecting
1 parent acd9d48 commit d69d97c

27 files changed

+267
-118
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// AccessMethodRepositoryStub.swift
2+
// AccessMethodRepository+Stub.swift
33
// MullvadRESTTests
44
//
55
// Created by Mojgan on 2024-01-02.
@@ -9,27 +9,27 @@
99
import Combine
1010
import MullvadSettings
1111

12-
struct AccessMethodRepositoryStub: AccessMethodRepositoryDataSource {
13-
var directAccess: PersistentAccessMethod
12+
public struct AccessMethodRepositoryStub: AccessMethodRepositoryDataSource {
13+
public var directAccess: PersistentAccessMethod
1414

15-
var accessMethodsPublisher: AnyPublisher<[PersistentAccessMethod], Never> {
15+
public var accessMethodsPublisher: AnyPublisher<[PersistentAccessMethod], Never> {
1616
passthroughSubject.eraseToAnyPublisher()
1717
}
1818

1919
let passthroughSubject: CurrentValueSubject<[PersistentAccessMethod], Never> = CurrentValueSubject([])
2020

21-
init(accessMethods: [PersistentAccessMethod]) {
21+
public init(accessMethods: [PersistentAccessMethod]) {
2222
directAccess = accessMethods.first(where: { $0.kind == .direct })!
2323
passthroughSubject.send(accessMethods)
2424
}
2525

26-
func fetchAll() -> [PersistentAccessMethod] {
26+
public func fetchAll() -> [PersistentAccessMethod] {
2727
passthroughSubject.value
2828
}
2929

30-
func saveLastReachable(_ method: PersistentAccessMethod) {}
30+
public func saveLastReachable(_ method: PersistentAccessMethod) {}
3131

32-
func fetchLastReachable() -> PersistentAccessMethod {
32+
public func fetchLastReachable() -> PersistentAccessMethod {
3333
directAccess
3434
}
3535
}

ios/MullvadMockData/MullvadREST/RelaySelectorStub.swift

+14-3
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,18 @@ import MullvadTypes
1111
import WireGuardKitTypes
1212

1313
/// Relay selector stub that accepts a block that can be used to provide custom implementation.
14-
public struct RelaySelectorStub: RelaySelectorProtocol {
15-
let block: (RelayConstraints, UInt) throws -> SelectedRelays
14+
public final class RelaySelectorStub: RelaySelectorProtocol {
15+
var selectedRelaysResult: (RelayConstraints, UInt) throws -> SelectedRelays
16+
17+
init(selectedRelaysResult: @escaping (RelayConstraints, UInt) throws -> SelectedRelays) {
18+
self.selectedRelaysResult = selectedRelaysResult
19+
}
1620

1721
public func selectRelays(
1822
with constraints: RelayConstraints,
1923
connectionAttemptCount: UInt
2024
) throws -> SelectedRelays {
21-
return try block(constraints, connectionAttemptCount)
25+
return try selectedRelaysResult(constraints, connectionAttemptCount)
2226
}
2327
}
2428

@@ -53,4 +57,11 @@ extension RelaySelectorStub {
5357
)
5458
}
5559
}
60+
61+
/// Returns a relay selector that cannot satisfy constraints .
62+
public static func unsatisfied() -> RelaySelectorStub {
63+
return RelaySelectorStub { _, _ in
64+
throw NoRelaysSatisfyingConstraintsError()
65+
}
66+
}
5667
}

ios/MullvadRESTTests/TransportStrategyTests.swift

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// Copyright © 2023 Mullvad VPN AB. All rights reserved.
77
//
88

9+
@testable import MullvadMockData
910
@testable import MullvadREST
1011
@testable import MullvadSettings
1112
@testable import MullvadTypes

ios/MullvadVPN.xcodeproj/project.pbxproj

+8-8
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,6 @@
836836
A9DF789D2B7D1E8B0094E4AD /* LoggedInWithTimeUITestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 859089692B61763B003AF5F5 /* LoggedInWithTimeUITestCase.swift */; };
837837
A9E031782ACB09930095D843 /* UIApplication+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */; };
838838
A9E0317A2ACB0AE70095D843 /* UIApplication+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */; };
839-
A9E0317C2ACBFC7E0095D843 /* TunnelStore+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E0317B2ACBFC7E0095D843 /* TunnelStore+Stubs.swift */; };
840839
A9E0317F2ACC331C0095D843 /* TunnelStatusBlockObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */; };
841840
A9E034642ABB302000E59A5A /* UIEdgeInsets+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */; };
842841
E1187ABC289BBB850024E748 /* OutOfTimeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1187ABA289BBB850024E748 /* OutOfTimeViewController.swift */; };
@@ -846,7 +845,6 @@
846845
F006CCFC2B99CC8400C6C2AC /* EditLocationsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F006CCFB2B99CC8400C6C2AC /* EditLocationsCoordinator.swift */; };
847846
F0077EEE2C52844800DAB2AA /* KeyExchangingResultStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0FBD98E2C4A60CC00EE5323 /* KeyExchangingResultStub.swift */; };
848847
F01528BB2BFF3FEE00B01D00 /* ShadowsocksRelaySelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = F01528BA2BFF3FEE00B01D00 /* ShadowsocksRelaySelector.swift */; };
849-
F0164EBA2B4456D30020268D /* AccessMethodRepositoryStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164EB92B4456D30020268D /* AccessMethodRepositoryStub.swift */; };
850848
F0164EBC2B482E430020268D /* AppStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164EBB2B482E430020268D /* AppStorage.swift */; };
851849
F0164EBE2B4BFF940020268D /* ShadowsocksLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164EBD2B4BFF940020268D /* ShadowsocksLoader.swift */; };
852850
F0164EC32B4C49D30020268D /* ShadowsocksLoaderStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164EC22B4C49D30020268D /* ShadowsocksLoaderStub.swift */; };
@@ -887,6 +885,7 @@
887885
F062B94D2C16E09700B6D47A /* TunnelSettingsManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F062B94C2C16E09700B6D47A /* TunnelSettingsManagerTests.swift */; };
888886
F072D3CF2C07122400906F64 /* MultihopUpdaterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3CE2C07122400906F64 /* MultihopUpdaterTests.swift */; };
889887
F072D3D22C071AD100906F64 /* ShadowsocksLoaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F072D3D12C071AD100906F64 /* ShadowsocksLoaderTests.swift */; };
888+
F073FCB32C6617D70062EA1D /* TunnelStore+Stubs.swift in Sources */ = {isa = PBXBuildFile; fileRef = F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */; };
890889
F07751552C50F149006E6A12 /* PostQuantumKeyExchangeActorStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BF2C495E7500A79006 /* PostQuantumKeyExchangeActorStub.swift */; };
891890
F07751572C50F149006E6A12 /* PostQuantumKeyExchangingPipelineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F053F4B92C4A94D300FBD937 /* PostQuantumKeyExchangingPipelineTests.swift */; };
892891
F07751582C50F149006E6A12 /* MultiHopPostQuantumKeyExchangingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0C4C9BD2C49477B00A79006 /* MultiHopPostQuantumKeyExchangingTests.swift */; };
@@ -895,6 +894,7 @@
895894
F07BF2622A26279100042943 /* RedeemVoucherOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F07BF2612A26279100042943 /* RedeemVoucherOperation.swift */; };
896895
F07C9D952B220C77006F1C5E /* libmullvad_ios.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 01F1FF1D29F0627D007083C3 /* libmullvad_ios.a */; };
897896
F07CFF2029F2720E008C0343 /* RegisteredDeviceInAppNotificationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F07CFF1F29F2720E008C0343 /* RegisteredDeviceInAppNotificationProvider.swift */; };
897+
F07F63CE2C63E5790027A351 /* AccessMethodRepository+Stub.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0164EB92B4456D30020268D /* AccessMethodRepository+Stub.swift */; };
898898
F08827872B318C840020A383 /* ShadowsocksCipherOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58DFF7D92B02862E00F864E0 /* ShadowsocksCipherOptions.swift */; };
899899
F08827882B318F960020A383 /* PersistentAccessMethod.swift in Sources */ = {isa = PBXBuildFile; fileRef = 586C0D962B04E0AC00E7CDD7 /* PersistentAccessMethod.swift */; };
900900
F08827892B3192110020A383 /* AccessMethodRepositoryProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58EF875A2B16385400C098B2 /* AccessMethodRepositoryProtocol.swift */; };
@@ -2041,7 +2041,6 @@
20412041
A9D9A4D32C36E1EA004088DD /* mullvad_rust_runtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mullvad_rust_runtime.h; path = include/mullvad_rust_runtime.h; sourceTree = "<group>"; };
20422042
A9E031762ACB08950095D843 /* UIApplication+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extensions.swift"; sourceTree = "<group>"; };
20432043
A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Stubs.swift"; sourceTree = "<group>"; };
2044-
A9E0317B2ACBFC7E0095D843 /* TunnelStore+Stubs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TunnelStore+Stubs.swift"; sourceTree = "<group>"; };
20452044
A9E0317D2ACC32920095D843 /* TunnelStatusBlockObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelStatusBlockObserver.swift; sourceTree = "<group>"; };
20462045
A9E034632ABB302000E59A5A /* UIEdgeInsets+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIEdgeInsets+Extensions.swift"; sourceTree = "<group>"; };
20472046
A9EB4F9C2B7FAB21002A2D7A /* PostQuantumKeyNegotiator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostQuantumKeyNegotiator.swift; sourceTree = "<group>"; };
@@ -2053,7 +2052,7 @@
20532052
E1FD0DF428AA7CE400299DB4 /* StatusActivityView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityView.swift; sourceTree = "<group>"; };
20542053
F006CCFB2B99CC8400C6C2AC /* EditLocationsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditLocationsCoordinator.swift; sourceTree = "<group>"; };
20552054
F01528BA2BFF3FEE00B01D00 /* ShadowsocksRelaySelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksRelaySelector.swift; sourceTree = "<group>"; };
2056-
F0164EB92B4456D30020268D /* AccessMethodRepositoryStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessMethodRepositoryStub.swift; sourceTree = "<group>"; };
2055+
F0164EB92B4456D30020268D /* AccessMethodRepository+Stub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AccessMethodRepository+Stub.swift"; sourceTree = "<group>"; };
20572056
F0164EBB2B482E430020268D /* AppStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppStorage.swift; sourceTree = "<group>"; };
20582057
F0164EBD2B4BFF940020268D /* ShadowsocksLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksLoader.swift; sourceTree = "<group>"; };
20592058
F0164EC22B4C49D30020268D /* ShadowsocksLoaderStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksLoaderStub.swift; sourceTree = "<group>"; };
@@ -2092,6 +2091,7 @@
20922091
F062B94C2C16E09700B6D47A /* TunnelSettingsManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelSettingsManagerTests.swift; sourceTree = "<group>"; };
20932092
F072D3CE2C07122400906F64 /* MultihopUpdaterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MultihopUpdaterTests.swift; sourceTree = "<group>"; };
20942093
F072D3D12C071AD100906F64 /* ShadowsocksLoaderTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowsocksLoaderTests.swift; sourceTree = "<group>"; };
2094+
F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TunnelStore+Stubs.swift"; sourceTree = "<group>"; };
20952095
F07B53562C53B5270024F547 /* LocalNetworkIPs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalNetworkIPs.swift; sourceTree = "<group>"; };
20962096
F07BF2572A26112D00042943 /* InputTextFormatterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputTextFormatterTests.swift; sourceTree = "<group>"; };
20972097
F07BF2612A26279100042943 /* RedeemVoucherOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedeemVoucherOperation.swift; sourceTree = "<group>"; };
@@ -2513,7 +2513,7 @@
25132513
A9A5F9A12ACB003D0083449F /* TunnelManagerTests.swift */,
25142514
F0A0868F2C22D6A700BF83E7 /* TunnelSettingsStrategyTests.swift */,
25152515
44BB5F992BE529FE002520EB /* TunnelStateTests.swift */,
2516-
A9E0317B2ACBFC7E0095D843 /* TunnelStore+Stubs.swift */,
2516+
F073FCB22C6617D70062EA1D /* TunnelStore+Stubs.swift */,
25172517
A9E031792ACB0AE70095D843 /* UIApplication+Stubs.swift */,
25182518
58165EBD2A262CBB00688EAD /* WgKeyRotationTests.swift */,
25192519
);
@@ -3710,7 +3710,6 @@
37103710
58FBFBE7291622580020E046 /* MullvadRESTTests */ = {
37113711
isa = PBXGroup;
37123712
children = (
3713-
F0164EB92B4456D30020268D /* AccessMethodRepositoryStub.swift */,
37143713
58FBFBE8291622580020E046 /* ExponentialBackoffTests.swift */,
37153714
A932D9F22B5EB61100999395 /* HeadRequestTests.swift */,
37163715
58BDEB9E2A98F6B400F578F2 /* Mocks */,
@@ -4091,6 +4090,7 @@
40914090
F0ACE3172BE4E487006D5333 /* MullvadREST */ = {
40924091
isa = PBXGroup;
40934092
children = (
4093+
F0164EB92B4456D30020268D /* AccessMethodRepository+Stub.swift */,
40944094
A900E9BF2ACC661900C95F67 /* AccessTokenManager+Stubs.swift */,
40954095
A900E9B72ACC5C2B00C95F67 /* AccountsProxy+Stubs.swift */,
40964096
A900E9BD2ACC654100C95F67 /* APIProxy+Stubs.swift */,
@@ -5271,7 +5271,6 @@
52715271
A9A5FA072ACB05160083449F /* SimulatorVPNConnection.swift in Sources */,
52725272
7A6F2FA52AFA3CB2006D0856 /* AccountExpiryTests.swift in Sources */,
52735273
A9A5FA082ACB05160083449F /* StorePaymentBlockObserver.swift in Sources */,
5274-
A9E0317C2ACBFC7E0095D843 /* TunnelStore+Stubs.swift in Sources */,
52755274
7A516C3C2B712F0B00BBD33D /* IPOverrideWrapperTests.swift in Sources */,
52765275
A9A5FA092ACB05160083449F /* SendStoreReceiptOperation.swift in Sources */,
52775276
A9A5FA0A2ACB05160083449F /* StorePaymentEvent.swift in Sources */,
@@ -5343,6 +5342,7 @@
53435342
A9A5FA312ACB05160083449F /* MockFileCache.swift in Sources */,
53445343
A9A5FA322ACB05160083449F /* RelayCacheTests.swift in Sources */,
53455344
A9A5FA332ACB05160083449F /* RelaySelectorTests.swift in Sources */,
5345+
F073FCB32C6617D70062EA1D /* TunnelStore+Stubs.swift in Sources */,
53465346
58DFF7D32B02570000F864E0 /* MarkdownStylingOptions.swift in Sources */,
53475347
A9A5FA342ACB05160083449F /* StringTests.swift in Sources */,
53485348
7A52F96C2C17450C00B133B9 /* RelaySelectorWrapperTests.swift in Sources */,
@@ -5972,7 +5972,6 @@
59725972
buildActionMask = 2147483647;
59735973
files = (
59745974
58B465702A98C53300467203 /* RequestExecutorTests.swift in Sources */,
5975-
F0164EBA2B4456D30020268D /* AccessMethodRepositoryStub.swift in Sources */,
59765975
A917352129FAAA5200D5DCFD /* TransportStrategyTests.swift in Sources */,
59775976
58FBFBE9291622580020E046 /* ExponentialBackoffTests.swift in Sources */,
59785977
F0164EC32B4C49D30020268D /* ShadowsocksLoaderStub.swift in Sources */,
@@ -6096,6 +6095,7 @@
60966095
buildActionMask = 2147483647;
60976096
files = (
60986097
F0ACE31D2BE4E4F2006D5333 /* DevicesProxy+Stubs.swift in Sources */,
6098+
F07F63CE2C63E5790027A351 /* AccessMethodRepository+Stub.swift in Sources */,
60996099
F0ACE31E2BE4E4F2006D5333 /* AccountsProxy+Stubs.swift in Sources */,
61006100
F0ACE3202BE4E4F2006D5333 /* AccessTokenManager+Stubs.swift in Sources */,
61016101
F0ACE32C2BE4E77E006D5333 /* DeviceMock.swift in Sources */,

ios/MullvadVPN/AddressCacheTracker/AddressCacheTracker.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ final class AddressCacheTracker {
103103

104104
operation.addObserver(
105105
BackgroundObserver(
106-
application: application,
106+
backgroundTaskProvider: application,
107107
name: "Update endpoints",
108108
cancelUponExpiration: true
109109
)

ios/MullvadVPN/RelayCacheTracker/RelayCacheTracker.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ final class RelayCacheTracker: RelayCacheTrackerProtocol {
120120

121121
operation.addObserver(
122122
BackgroundObserver(
123-
application: application,
123+
backgroundTaskProvider: application,
124124
name: "Update relays",
125125
cancelUponExpiration: true
126126
)

ios/MullvadVPN/SimulatorTunnelProvider/SimulatorTunnelProviderHost.swift

+3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ final class SimulatorTunnelProviderHost: SimulatorTunnelProviderDelegate {
6262
do {
6363
setInternalStateConnected(with: try selectedRelays ?? pickRelays())
6464
completionHandler(nil)
65+
} catch let error where error is NoRelaysSatisfyingConstraintsError {
66+
observedState = .error(ObservedBlockedState(reason: .noRelaysSatisfyingConstraints))
67+
completionHandler(error)
6568
} catch {
6669
providerLogger.error(
6770
error: error,

ios/MullvadVPN/SimulatorTunnelProvider/SimulatorVPNConnection.swift

+4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#if targetEnvironment(simulator)
1010

1111
import Foundation
12+
import MullvadREST
1213
import NetworkExtension
1314

1415
class SimulatorVPNConnection: NSObject, VPNConnectionProtocol {
@@ -94,6 +95,9 @@ class SimulatorVPNConnection: NSObject, VPNConnectionProtocol {
9495
if error == nil {
9596
self.status = .connected
9697
self.connectedDate = Date()
98+
} else if error is NoRelaysSatisfyingConstraintsError {
99+
self.reasserting = true
100+
self.connectedDate = nil
97101
} else {
98102
self.status = .disconnected
99103
self.connectedDate = nil

ios/MullvadVPN/StorePaymentManager/StorePaymentManager.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver {
232232
}
233233

234234
accountOperation.addObserver(BackgroundObserver(
235-
application: backgroundTaskProvider,
235+
backgroundTaskProvider: backgroundTaskProvider,
236236
name: "Validate account number",
237237
cancelUponExpiration: false
238238
))
@@ -267,7 +267,7 @@ final class StorePaymentManager: NSObject, SKPaymentTransactionObserver {
267267

268268
operation.addObserver(
269269
BackgroundObserver(
270-
application: backgroundTaskProvider,
270+
backgroundTaskProvider: backgroundTaskProvider,
271271
name: "Send AppStore receipt",
272272
cancelUponExpiration: true
273273
)

ios/MullvadVPN/TunnelManager/MapConnectionStatusOperation.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class MapConnectionStatusOperation: AsyncOperation {
2222

2323
private let logger = Logger(label: "TunnelManager.MapConnectionStatusOperation")
2424

25-
init(
25+
required init(
2626
queue: DispatchQueue,
2727
interactor: TunnelInteractor,
2828
connectionStatus: NEVPNStatus,

0 commit comments

Comments
 (0)