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",
"location" : "git@github.com:passepartoutvpn/passepartoutkit-source",
"state" : {
"revision" : "cd54765853982204f83d721a6c67a26742dc99e3"
"revision" : "2b639620b371181fa56594296918b09acf528058"
}
},
{

View File

@ -73,14 +73,7 @@ extension PassepartoutApp {
.onChange(of: scenePhase) {
switch $0 {
case .active:
Task {
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)")
}
}
context.onApplicationActive()
default:
break

View File

@ -40,7 +40,7 @@ let package = Package(
],
dependencies: [
// .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(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"),

View File

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

View File

@ -63,17 +63,7 @@ extension VPNFiltersView {
presets = []
subscriptions = []
$filters
.sink { [weak self] in
self?.filtersDidChange.send($0)
}
.store(in: &subscriptions)
$onlyShowsFavorites
.sink { [weak self] in
self?.onlyShowsFavoritesDidChange.send($0)
}
.store(in: &subscriptions)
observeObjects()
}
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 {
var asCountryCodeWithDescription: VPNFiltersView.Model.CodeWithDescription {
(self, localizedAsRegionCode ?? self)

View File

@ -64,53 +64,13 @@ public final class ExtendedTunnel: ObservableObject {
self.processor = processor
self.interval = interval
subscriptions = []
}
public 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)
observeObjects()
}
}
// MARK: - Public interface
extension ExtendedTunnel {
public var status: TunnelStatus {
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 {
var processedTitle: (Profile) -> String {
if let processor {

View File

@ -59,11 +59,21 @@ public final class AppContext: ObservableObject {
Task {
await iapManager.reloadReceipt()
self.tunnel.observeObjects()
profileManager.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

View File

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

View File

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