TunnelsManager: Handle waiting on a stale tunnel
If we have a stale tunnel on which we don't get status updates we rely
on a timer to update the status (see commit 34a7e5b
). Previously, if
the user tries to activate another tunnel, that resulted in both tunnels
waiting indefinitely. This commit fixes that.
Signed-off-by: Roopesh Chander <roop@roopc.net>
This commit is contained in:
parent
fab7af6f38
commit
4e516d6769
|
@ -24,6 +24,7 @@ class TunnelsManager {
|
|||
weak var tunnelsListDelegate: TunnelsManagerListDelegate?
|
||||
weak var activationDelegate: TunnelsManagerActivationDelegate?
|
||||
private var statusObservationToken: AnyObject?
|
||||
private var waiteeObservationToken: AnyObject?
|
||||
|
||||
init(tunnelProviders: [NETunnelProviderManager]) {
|
||||
tunnels = tunnelProviders.map { TunnelContainer(tunnel: $0) }.sorted { $0.name < $1.name }
|
||||
|
@ -205,6 +206,7 @@ class TunnelsManager {
|
|||
if let tunnelInOperation = tunnels.first(where: { $0.status != .inactive }) {
|
||||
wg_log(.info, message: "Tunnel '\(tunnel.name)' waiting for deactivation of '\(tunnelInOperation.name)'")
|
||||
tunnel.status = .waiting
|
||||
activateWaitingTunnelOnDeactivation(of: tunnelInOperation)
|
||||
if tunnelInOperation.status != .deactivating {
|
||||
startDeactivation(of: tunnelInOperation)
|
||||
}
|
||||
|
@ -232,6 +234,18 @@ class TunnelsManager {
|
|||
tunnels.forEach { $0.refreshStatus() }
|
||||
}
|
||||
|
||||
private func activateWaitingTunnelOnDeactivation(of tunnel: TunnelContainer) {
|
||||
waiteeObservationToken = tunnel.observe(\.status) { [weak self] tunnel, _ in
|
||||
guard let self = self else { return }
|
||||
if tunnel.status == .inactive {
|
||||
if let waitingTunnel = self.tunnels.first(where: { $0.status == .waiting }) {
|
||||
waitingTunnel.startActivation(activationDelegate: self.activationDelegate)
|
||||
}
|
||||
self.waiteeObservationToken = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func startObservingTunnelStatuses() {
|
||||
guard statusObservationToken == nil else { return }
|
||||
|
||||
|
@ -268,13 +282,6 @@ class TunnelsManager {
|
|||
}
|
||||
|
||||
tunnel.refreshStatus()
|
||||
|
||||
// In case some other tunnel is waiting for this tunnel to get deactivated
|
||||
if session.status == .disconnected || session.status == .invalid {
|
||||
if let waitingTunnel = self.tunnels.first(where: { $0.status == .waiting }) {
|
||||
waitingTunnel.startActivation(activationDelegate: self.activationDelegate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,18 +315,21 @@ class TunnelContainer: NSObject {
|
|||
var isAttemptingActivation = false {
|
||||
didSet {
|
||||
if isAttemptingActivation {
|
||||
self.activationTimer?.invalidate()
|
||||
let activationTimer = Timer(timeInterval: 5 /* seconds */, repeats: true) { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.refreshStatus()
|
||||
if self.status == .inactive || self.status == .active {
|
||||
self.isAttemptingActivation = false // This also invalidates the timer
|
||||
wg_log(.debug, message: "Status update notification timeout for tunnel '\(self.name)'. Tunnel status is now '\(self.tunnelProvider.connection.status)'.")
|
||||
switch self.tunnelProvider.connection.status {
|
||||
case .connected, .disconnected, .invalid:
|
||||
self.activationTimer?.invalidate()
|
||||
self.activationTimer = nil
|
||||
default:
|
||||
break
|
||||
}
|
||||
self.refreshStatus()
|
||||
}
|
||||
self.activationTimer = activationTimer
|
||||
RunLoop.main.add(activationTimer, forMode: .default)
|
||||
} else {
|
||||
activationTimer?.invalidate()
|
||||
activationTimer = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue