Use MockVPN from TunnelKit

Rather than ad hoc strategy.
This commit is contained in:
Davide De Rosa 2022-10-11 18:16:11 +02:00
parent fb4d563804
commit 54dc8a2556
5 changed files with 21 additions and 140 deletions

View File

@ -51,8 +51,8 @@
"repositoryURL": "https://github.com/passepartoutvpn/tunnelkit",
"state": {
"branch": null,
"revision": "ca378c4999f2040565b9ec944746b684ab19c347",
"version": "5.0.0"
"revision": "3a54295ed9d2b71057fdeef752144beea66e31f2",
"version": null
}
},
{

View File

@ -90,13 +90,15 @@ class CoreContext {
)
#if targetEnvironment(simulator)
let strategy = MockVPNManagerStrategy()
let vpn = MockVPN()
#else
let vpn = NetworkExtensionVPN()
#endif
let strategy = TunnelKitVPNManagerStrategy(
appGroup: Constants.App.appGroupId,
tunnelBundleIdentifier: Constants.App.tunnelBundleId
tunnelBundleIdentifier: Constants.App.tunnelBundleId,
vpn: vpn
)
#endif
vpnManager = VPNManager(
appGroup: Constants.App.appGroupId,
store: store,

View File

@ -23,8 +23,8 @@ let package = Package(
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
.package(name: "TunnelKit", url: "https://github.com/passepartoutvpn/tunnelkit", from: "5.0.0"),
// .package(name: "TunnelKit", url: "https://github.com/passepartoutvpn/tunnelkit", .revision("000fde0aa2f028575e811a984ef1972cb9afeb36")),
// .package(name: "TunnelKit", url: "https://github.com/passepartoutvpn/tunnelkit", from: "5.0.0"),
.package(name: "TunnelKit", url: "https://github.com/passepartoutvpn/tunnelkit", .revision("3a54295ed9d2b71057fdeef752144beea66e31f2")),
// .package(name: "TunnelKit", path: "../../tunnelkit"),
.package(url: "https://github.com/zoul/generic-json-swift", from: "2.0.0"),
.package(url: "https://github.com/SwiftyBeaver/SwiftyBeaver", from: "1.9.0")

View File

@ -1,126 +0,0 @@
//
// MockVPNManagerStrategy.swift
// Passepartout
//
// Created by Davide De Rosa on 2/9/22.
// Copyright (c) 2022 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Foundation
import Combine
import TunnelKitCore
import PassepartoutCore
// XXX: mock connect/disconnect tasks overlap, should cancel other pending task
public class MockVPNManagerStrategy: VPNManagerStrategy {
private var currentState: ObservableVPNState?
private var dataCountTimer: AnyCancellable?
public init() {
}
public func observe(into state: ObservableVPNState) {
currentState = state
}
public func reinstate(configuration: VPNConfiguration) {
}
@MainActor
public func connect(configuration: VPNConfiguration) {
guard currentState?.vpnStatus != .connected else {
return
}
Task {
currentState?.isEnabled = true
currentState?.vpnStatus = .connecting
await Task.maybeWait(forMilliseconds: 1000)
currentState?.vpnStatus = .connected
startCountingData()
}
}
@MainActor
public func reconnect() async {
guard currentState?.vpnStatus == .connected else {
return
}
Task {
currentState?.vpnStatus = .disconnecting
await Task.maybeWait(forMilliseconds: 1000)
currentState?.vpnStatus = .disconnected
await Task.maybeWait(forMilliseconds: 1000)
currentState?.vpnStatus = .connecting
await Task.maybeWait(forMilliseconds: 1000)
currentState?.vpnStatus = .connected
currentState?.dataCount = nil
}
}
@MainActor
public func disconnect() {
stopCountingData()
guard currentState?.vpnStatus != .disconnected else {
return
}
Task {
currentState?.isEnabled = false
currentState?.vpnStatus = .disconnecting
await Task.maybeWait(forMilliseconds: 1000)
currentState?.vpnStatus = .disconnected
currentState?.dataCount = nil
}
}
private func startCountingData() {
guard currentState?.vpnStatus == .connected else {
return
}
guard dataCountTimer == nil else {
return
}
dataCountTimer = Timer.TimerPublisher(interval: 2.0, runLoop: .main, mode: .common)
.autoconnect()
.sink(receiveValue: { _ in
let previous = self.currentState?.dataCount ?? DataCount(0, 0)
self.currentState?.dataCount = DataCount(previous.received + 4000, previous.sent + 2000)
})
}
private func stopCountingData() {
dataCountTimer?.cancel()
dataCountTimer = nil
}
@MainActor
public func removeConfigurations() {
disconnect()
}
public func serverConfiguration(forProtocol vpnProtocol: VPNProtocolType) -> Any? {
nil
}
public func debugLogURL(forProtocol vpnProtocol: VPNProtocolType) -> URL? {
nil
}
}

View File

@ -32,7 +32,7 @@ import TunnelKitOpenVPNCore
import PassepartoutCore
import PassepartoutUtils
public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
public class TunnelKitVPNManagerStrategy<VPNType: VPN>: VPNManagerStrategy where VPNType.Configuration == NetworkExtensionConfiguration, VPNType.Extra == NetworkExtensionExtra {
private struct AtomicState: Equatable {
let isEnabled: Bool
@ -44,7 +44,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
}
}
private static let reconnectionSeconds = 2
private let reconnectionSeconds = 2
private let appGroup: String
@ -52,7 +52,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
private let defaults: UserDefaults
private let vpn: NetworkExtensionVPN
private let vpn: VPNType
private let dataCountInterval: TimeInterval
@ -71,14 +71,19 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
private var currentBundleIdentifier: String?
@MainActor
public init(appGroup: String, tunnelBundleIdentifier: @escaping (VPNProtocolType) -> String, dataCountInterval: TimeInterval = 3.0) {
public init(
appGroup: String,
tunnelBundleIdentifier: @escaping (VPNProtocolType) -> String,
vpn: VPNType,
dataCountInterval: TimeInterval = 3.0
) {
self.appGroup = appGroup
self.tunnelBundleIdentifier = tunnelBundleIdentifier
guard let defaults = UserDefaults(suiteName: appGroup) else {
fatalError("No entitlements for group '\(appGroup)'")
}
self.defaults = defaults
vpn = NetworkExtensionVPN()
self.vpn = vpn
self.dataCountInterval = dataCountInterval
registerNotification(withName: VPNNotification.didReinstall) {
@ -151,7 +156,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
bundleIdentifier,
configuration: configuration.neConfiguration,
extra: configuration.neExtra,
after: .seconds(Self.reconnectionSeconds)
after: .seconds(reconnectionSeconds)
)
} catch {
pp_log.error("Unable to connect: \(error)")
@ -160,7 +165,7 @@ public class TunnelKitVPNManagerStrategy: VPNManagerStrategy {
public func reconnect() async {
try? await vpn.reconnect(
after: .seconds(Self.reconnectionSeconds)
after: .seconds(reconnectionSeconds)
)
}