aboutsummaryrefslogtreecommitdiffstats
path: root/WireGuard/WireGuard/UI/macOS/TunnelsTracker.swift
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--WireGuard/WireGuard/UI/macOS/TunnelsTracker.swift126
1 files changed, 126 insertions, 0 deletions
diff --git a/WireGuard/WireGuard/UI/macOS/TunnelsTracker.swift b/WireGuard/WireGuard/UI/macOS/TunnelsTracker.swift
new file mode 100644
index 0000000..781fa2e
--- /dev/null
+++ b/WireGuard/WireGuard/UI/macOS/TunnelsTracker.swift
@@ -0,0 +1,126 @@
+// 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
+ }
+}