2019-01-17 19:57:17 +00:00
|
|
|
// 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 {
|
|
|
|
|
2019-01-24 11:21:01 +00:00
|
|
|
weak var statusMenu: StatusMenu? {
|
|
|
|
didSet {
|
|
|
|
statusMenu?.currentTunnel = currentTunnel
|
|
|
|
}
|
|
|
|
}
|
|
|
|
weak var statusItemController: StatusItemController? {
|
|
|
|
didSet {
|
|
|
|
statusItemController?.currentTunnel = currentTunnel
|
|
|
|
}
|
|
|
|
}
|
2019-01-17 19:57:17 +00:00
|
|
|
weak var manageTunnelsRootVC: ManageTunnelsRootViewController?
|
|
|
|
|
|
|
|
private var tunnelsManager: TunnelsManager
|
|
|
|
private var tunnelStatusObservers = [AnyObject]()
|
2019-01-23 11:01:26 +00:00
|
|
|
private(set) var currentTunnel: TunnelContainer? {
|
2019-01-17 19:57:17 +00:00
|
|
|
didSet {
|
|
|
|
statusMenu?.currentTunnel = currentTunnel
|
|
|
|
statusItemController?.currentTunnel = currentTunnel
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
init(tunnelsManager: TunnelsManager) {
|
|
|
|
self.tunnelsManager = tunnelsManager
|
2019-01-24 12:41:55 +00:00
|
|
|
currentTunnel = tunnelsManager.tunnelInOperation()
|
2019-01-17 19:57:17 +00:00
|
|
|
|
|
|
|
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 {
|
2019-01-24 12:41:55 +00:00
|
|
|
self.currentTunnel = self.tunnelsManager.tunnelInOperation()
|
2019-01-17 19:57:17 +00:00
|
|
|
}
|
|
|
|
} 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)
|
|
|
|
}
|
|
|
|
|
2019-01-23 10:51:20 +00:00
|
|
|
func tunnelRemoved(at index: Int, tunnel: TunnelContainer) {
|
2019-01-17 19:57:17 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|