Encapsulate behavior on app active (#812)

Implement inside AppContext.
This commit is contained in:
Davide 2024-11-05 10:41:02 +01:00 committed by GitHub
parent bba661f104
commit 1cb46e066c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 90 additions and 70 deletions

View File

@ -41,7 +41,7 @@
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source", "location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
"state" : { "state" : {
"revision" : "cd54765853982204f83d721a6c67a26742dc99e3" "revision" : "2b639620b371181fa56594296918b09acf528058"
} }
}, },
{ {

View File

@ -73,14 +73,7 @@ extension PassepartoutApp {
.onChange(of: scenePhase) { .onChange(of: scenePhase) {
switch $0 { switch $0 {
case .active: case .active:
Task { context.onApplicationActive()
do {
pp_log(.app, .notice, "Prepare tunnel and purge stale data")
try await context.tunnel.prepare(purge: true)
} catch {
pp_log(.app, .fault, "Unable to prepare tunnel: \(error)")
}
}
default: default:
break break

View File

@ -40,7 +40,7 @@ let package = Package(
], ],
dependencies: [ dependencies: [
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.9.0"), // .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", from: "0.9.0"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "cd54765853982204f83d721a6c67a26742dc99e3"), .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source", revision: "2b639620b371181fa56594296918b09acf528058"),
// .package(path: "../../../passepartoutkit-source"), // .package(path: "../../../passepartoutkit-source"),
.package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"), .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", from: "0.9.1"),
// .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"), // .package(url: "git@github.com:passepartoutvpn/passepartoutkit-source-openvpn-openssl", revision: "031863a1cd683962a7dfe68e20b91fa820a1ecce"),

View File

@ -38,9 +38,7 @@ public final class AppUIMain: UILibraryConfiguring {
// keep this for login item because scenePhase is not triggered // keep this for login item because scenePhase is not triggered
if isStartedFromLoginItem { if isStartedFromLoginItem {
Task { context.onApplicationActive()
try await context.tunnel.prepare(purge: true)
}
} }
} }
} }

View File

@ -63,17 +63,7 @@ extension VPNFiltersView {
presets = [] presets = []
subscriptions = [] subscriptions = []
$filters observeObjects()
.sink { [weak self] in
self?.filtersDidChange.send($0)
}
.store(in: &subscriptions)
$onlyShowsFavorites
.sink { [weak self] in
self?.onlyShowsFavoritesDidChange.send($0)
}
.store(in: &subscriptions)
} }
func load(options: VPNFilterOptions, initialFilters: VPNFilters?) { func load(options: VPNFilterOptions, initialFilters: VPNFilters?) {
@ -135,6 +125,26 @@ private extension VPNFiltersView.Model {
} }
} }
// MARK: - Observation
private extension VPNFiltersView.Model {
func observeObjects() {
$filters
.sink { [weak self] in
self?.filtersDidChange.send($0)
}
.store(in: &subscriptions)
$onlyShowsFavorites
.sink { [weak self] in
self?.onlyShowsFavoritesDidChange.send($0)
}
.store(in: &subscriptions)
}
}
// MARK: -
private extension String { private extension String {
var asCountryCodeWithDescription: VPNFiltersView.Model.CodeWithDescription { var asCountryCodeWithDescription: VPNFiltersView.Model.CodeWithDescription {
(self, localizedAsRegionCode ?? self) (self, localizedAsRegionCode ?? self)

View File

@ -64,53 +64,13 @@ public final class ExtendedTunnel: ObservableObject {
self.processor = processor self.processor = processor
self.interval = interval self.interval = interval
subscriptions = [] subscriptions = []
}
public func observeObjects() { observeObjects()
tunnel
.$status
.receive(on: DispatchQueue.main)
.sink { [weak self] in
guard let self else {
return
}
switch $0 {
case .activating:
lastErrorCode = nil
default:
lastErrorCode = value(forKey: TunnelEnvironmentKeys.lastErrorCode)
}
if $0 != .active {
dataCount = nil
}
}
.store(in: &subscriptions)
tunnel
.$currentProfile
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
self?.objectWillChange.send()
}
.store(in: &subscriptions)
Timer
.publish(every: interval, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
guard let self else {
return
}
guard tunnel.status == .active else {
return
}
dataCount = value(forKey: TunnelEnvironmentKeys.dataCount)
}
.store(in: &subscriptions)
} }
} }
// MARK: - Public interface
extension ExtendedTunnel { extension ExtendedTunnel {
public var status: TunnelStatus { public var status: TunnelStatus {
tunnel.status tunnel.status
@ -171,6 +131,56 @@ extension ExtendedTunnel {
} }
} }
// MARK: - Observation
private extension ExtendedTunnel {
func observeObjects() {
tunnel
.$status
.receive(on: DispatchQueue.main)
.sink { [weak self] in
guard let self else {
return
}
switch $0 {
case .activating:
lastErrorCode = nil
default:
lastErrorCode = value(forKey: TunnelEnvironmentKeys.lastErrorCode)
}
if $0 != .active {
dataCount = nil
}
}
.store(in: &subscriptions)
tunnel
.$currentProfile
.receive(on: DispatchQueue.main)
.sink { [weak self] _ in
self?.objectWillChange.send()
}
.store(in: &subscriptions)
Timer
.publish(every: interval, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
guard let self else {
return
}
guard tunnel.status == .active else {
return
}
dataCount = value(forKey: TunnelEnvironmentKeys.dataCount)
}
.store(in: &subscriptions)
}
}
// MARK: - Processing
private extension ExtendedTunnel { private extension ExtendedTunnel {
var processedTitle: (Profile) -> String { var processedTitle: (Profile) -> String {
if let processor { if let processor {

View File

@ -59,11 +59,21 @@ public final class AppContext: ObservableObject {
Task { Task {
await iapManager.reloadReceipt() await iapManager.reloadReceipt()
self.tunnel.observeObjects()
profileManager.observeObjects() profileManager.observeObjects()
observeObjects() observeObjects()
} }
} }
public func onApplicationActive() {
Task {
do {
pp_log(.app, .notice, "Prepare tunnel and purge stale data")
try await tunnel.prepare(purge: true)
} catch {
pp_log(.app, .fault, "Unable to prepare tunnel: \(error)")
}
}
}
} }
// MARK: - Observation // MARK: - Observation

View File

@ -28,6 +28,7 @@ import CommonLibrary
import Foundation import Foundation
import PassepartoutKit import PassepartoutKit
@MainActor
public protocol UILibraryConfiguring { public protocol UILibraryConfiguring {
func configure(with context: AppContext) func configure(with context: AppContext)
} }

View File

@ -37,7 +37,6 @@ extension ExtendedTunnelTests {
let env = InMemoryEnvironment() let env = InMemoryEnvironment()
let tunnel = Tunnel(strategy: FakeTunnelStrategy(environment: env)) let tunnel = Tunnel(strategy: FakeTunnelStrategy(environment: env))
let sut = ExtendedTunnel(tunnel: tunnel, environment: env, interval: 0.1) let sut = ExtendedTunnel(tunnel: tunnel, environment: env, interval: 0.1)
sut.observeObjects()
let module = try DNSModule.Builder().tryBuild() let module = try DNSModule.Builder().tryBuild()
let profile = try Profile.Builder(modules: [module], activatingModules: true).tryBuild() let profile = try Profile.Builder(modules: [module], activatingModules: true).tryBuild()
@ -53,7 +52,6 @@ extension ExtendedTunnelTests {
let env = InMemoryEnvironment() let env = InMemoryEnvironment()
let tunnel = Tunnel(strategy: FakeTunnelStrategy(environment: env)) let tunnel = Tunnel(strategy: FakeTunnelStrategy(environment: env))
let sut = ExtendedTunnel(tunnel: tunnel, environment: env, interval: 0.1) let sut = ExtendedTunnel(tunnel: tunnel, environment: env, interval: 0.1)
sut.observeObjects()
let module = try DNSModule.Builder().tryBuild() let module = try DNSModule.Builder().tryBuild()
let profile = try Profile.Builder(modules: [module], activatingModules: true).tryBuild() let profile = try Profile.Builder(modules: [module], activatingModules: true).tryBuild()