dc8f27c5c3
The TunnelTracker is now the central place to track what the current tunnel is, and for keeping track of the tunnel list. Signed-off-by: Roopesh Chander <roop@roopc.net>
127 lines
4.6 KiB
Swift
127 lines
4.6 KiB
Swift
// SPDX-License-Identifier: MIT
|
|
// Copyright © 2018-2019 WireGuard LLC. All Rights Reserved.
|
|
|
|
import Cocoa
|
|
|
|
// Keeps track of tunnels and informs the following objects of changes in tunnels:
|
|
// - Status menu
|
|
// - Status item controller
|
|
// - Tunnels list view controller in the Manage Tunnels window
|
|
|
|
class TunnelsTracker {
|
|
|
|
weak var statusMenu: StatusMenu?
|
|
weak var statusItemController: StatusItemController?
|
|
weak var manageTunnelsRootVC: ManageTunnelsRootViewController?
|
|
|
|
private var tunnelsManager: TunnelsManager
|
|
private var tunnelStatusObservers = [AnyObject]()
|
|
private var currentTunnel: TunnelContainer? {
|
|
didSet {
|
|
statusMenu?.currentTunnel = currentTunnel
|
|
statusItemController?.currentTunnel = currentTunnel
|
|
}
|
|
}
|
|
|
|
init(tunnelsManager: TunnelsManager) {
|
|
self.tunnelsManager = tunnelsManager
|
|
|
|
if let waitingTunnel = tunnelsManager.waitingTunnel() {
|
|
currentTunnel = waitingTunnel
|
|
} else {
|
|
for index in 0 ..< tunnelsManager.numberOfTunnels() {
|
|
let tunnel = tunnelsManager.tunnel(at: index)
|
|
if tunnel.status != .inactive {
|
|
currentTunnel = tunnel
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
for index in 0 ..< tunnelsManager.numberOfTunnels() {
|
|
let tunnel = tunnelsManager.tunnel(at: index)
|
|
let statusObservationToken = observeStatus(of: tunnel)
|
|
tunnelStatusObservers.insert(statusObservationToken, at: index)
|
|
}
|
|
|
|
tunnelsManager.tunnelsListDelegate = self
|
|
tunnelsManager.activationDelegate = self
|
|
}
|
|
|
|
func observeStatus(of tunnel: TunnelContainer) -> AnyObject {
|
|
return tunnel.observe(\.status) { [weak self] tunnel, _ in
|
|
guard let self = self else { return }
|
|
if tunnel.status == .deactivating || tunnel.status == .inactive {
|
|
if self.currentTunnel == tunnel {
|
|
if let waitingTunnel = self.tunnelsManager.waitingTunnel() {
|
|
self.currentTunnel = waitingTunnel
|
|
} else if tunnel.status == .inactive {
|
|
self.currentTunnel = nil
|
|
}
|
|
}
|
|
} else {
|
|
self.currentTunnel = tunnel
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extension TunnelsTracker: TunnelsManagerListDelegate {
|
|
func tunnelAdded(at index: Int) {
|
|
let tunnel = tunnelsManager.tunnel(at: index)
|
|
if tunnel.status != .deactivating && tunnel.status != .inactive {
|
|
self.currentTunnel = tunnel
|
|
}
|
|
let statusObservationToken = observeStatus(of: tunnel)
|
|
tunnelStatusObservers.insert(statusObservationToken, at: index)
|
|
|
|
statusMenu?.insertTunnelMenuItem(for: tunnel, at: index)
|
|
manageTunnelsRootVC?.tunnelsListVC?.tunnelAdded(at: index)
|
|
}
|
|
|
|
func tunnelModified(at index: Int) {
|
|
manageTunnelsRootVC?.tunnelsListVC?.tunnelModified(at: index)
|
|
}
|
|
|
|
func tunnelMoved(from oldIndex: Int, to newIndex: Int) {
|
|
let statusObserver = tunnelStatusObservers.remove(at: oldIndex)
|
|
tunnelStatusObservers.insert(statusObserver, at: newIndex)
|
|
|
|
statusMenu?.moveTunnelMenuItem(from: oldIndex, to: newIndex)
|
|
manageTunnelsRootVC?.tunnelsListVC?.tunnelMoved(from: oldIndex, to: newIndex)
|
|
}
|
|
|
|
func tunnelRemoved(at index: Int) {
|
|
tunnelStatusObservers.remove(at: index)
|
|
|
|
statusMenu?.removeTunnelMenuItem(at: index)
|
|
manageTunnelsRootVC?.tunnelsListVC?.tunnelRemoved(at: index)
|
|
}
|
|
}
|
|
|
|
extension TunnelsTracker: TunnelsManagerActivationDelegate {
|
|
func tunnelActivationAttemptFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationAttemptError) {
|
|
if let manageTunnelsRootVC = manageTunnelsRootVC, manageTunnelsRootVC.view.window?.isVisible ?? false {
|
|
ErrorPresenter.showErrorAlert(error: error, from: manageTunnelsRootVC)
|
|
} else {
|
|
ErrorPresenter.showErrorAlert(error: error, from: nil)
|
|
}
|
|
}
|
|
|
|
func tunnelActivationAttemptSucceeded(tunnel: TunnelContainer) {
|
|
// Nothing to do
|
|
}
|
|
|
|
func tunnelActivationFailed(tunnel: TunnelContainer, error: TunnelsManagerActivationError) {
|
|
if let manageTunnelsRootVC = manageTunnelsRootVC, manageTunnelsRootVC.view.window?.isVisible ?? false {
|
|
ErrorPresenter.showErrorAlert(error: error, from: manageTunnelsRootVC)
|
|
} else {
|
|
ErrorPresenter.showErrorAlert(error: error, from: nil)
|
|
}
|
|
}
|
|
|
|
func tunnelActivationSucceeded(tunnel: TunnelContainer) {
|
|
// Nothing to do
|
|
}
|
|
}
|