aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoopesh Chander <roop@roopc.net>2019-02-04 18:25:32 +0530
committerRoopesh Chander <roop@roopc.net>2019-02-05 12:36:35 +0530
commit80de2ac6ac6ccd6db5c0aa4596263d36757ddb29 (patch)
tree853933576e4dc017cb802454984c2f25e6f02228
parentTunnelViewModel: Don't call peer change handler if there are no changes (diff)
downloadwireguard-apple-80de2ac6ac6ccd6db5c0aa4596263d36757ddb29.tar.xz
wireguard-apple-80de2ac6ac6ccd6db5c0aa4596263d36757ddb29.zip
macOS: Apply runtime configuration by diff-ing
And apply the diff on the tableView as insertRows/removeRows. Signed-off-by: Roopesh Chander <roop@roopc.net>
Diffstat (limited to '')
-rw-r--r--WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift103
1 files changed, 88 insertions, 15 deletions
diff --git a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
index e481a11..d6be908 100644
--- a/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
+++ b/WireGuard/WireGuard/UI/macOS/ViewController/TunnelDetailTableViewController.swift
@@ -30,12 +30,12 @@ class TunnelDetailTableViewController: NSViewController {
}
}
- let interfaceFields: [TunnelViewModel.InterfaceField] = [
+ static let interfaceFields: [TunnelViewModel.InterfaceField] = [
.name, .publicKey, .addresses,
.listenPort, .mtu, .dns
]
- let peerFields: [TunnelViewModel.PeerField] = [
+ static let peerFields: [TunnelViewModel.PeerField] = [
.publicKey, .preSharedKey, .endpoint,
.allowedIPs, .persistentKeepAlive,
.rxBytes, .txBytes, .lastHandshakeTime
@@ -80,11 +80,12 @@ class TunnelDetailTableViewController: NSViewController {
let tunnel: TunnelContainer
var tunnelViewModel: TunnelViewModel {
- didSet { updateTableViewModelRowsBySection() }
- }
- private var tableViewModelRowsBySection = [[(isVisible: Bool, modelRow: TableViewModelRow)]]() {
- didSet { updateTableViewModelRows() }
+ didSet {
+ updateTableViewModelRowsBySection()
+ updateTableViewModelRows()
+ }
}
+ private var tableViewModelRowsBySection = [[(isVisible: Bool, modelRow: TableViewModelRow)]]()
private var tableViewModelRows = [TableViewModelRow]()
private var statusObservationToken: AnyObject?
@@ -96,6 +97,7 @@ class TunnelDetailTableViewController: NSViewController {
self.tunnel = tunnel
tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnel.tunnelConfiguration)
super.init(nibName: nil, bundle: nil)
+ updateTableViewModelRowsBySection()
updateTableViewModelRows()
updateStatus()
statusObservationToken = tunnel.observe(\TunnelContainer.status) { [weak self] _, _ in
@@ -167,7 +169,7 @@ class TunnelDetailTableViewController: NSViewController {
var modelRowsBySection = [[(isVisible: Bool, modelRow: TableViewModelRow)]]()
var interfaceSection = [(isVisible: Bool, modelRow: TableViewModelRow)]()
- for field in interfaceFields {
+ for field in TunnelDetailTableViewController.interfaceFields {
interfaceSection.append((isVisible: !tunnelViewModel.interfaceData[field].isEmpty, modelRow: .interfaceFieldRow(field)))
}
interfaceSection.append((isVisible: true, modelRow: .spacerRow))
@@ -175,7 +177,7 @@ class TunnelDetailTableViewController: NSViewController {
for peerData in tunnelViewModel.peersData {
var peerSection = [(isVisible: Bool, modelRow: TableViewModelRow)]()
- for field in peerFields {
+ for field in TunnelDetailTableViewController.peerFields {
peerSection.append((isVisible: !peerData[field].isEmpty, modelRow: .peerFieldRow(peer: peerData, field: field)))
}
peerSection.append((isVisible: true, modelRow: .spacerRow))
@@ -219,6 +221,7 @@ class TunnelDetailTableViewController: NSViewController {
if tunnel.status == .active {
startUpdatingRuntimeConfiguration()
} else if tunnel.status == .inactive {
+ reloadRuntimeConfiguration()
stopUpdatingRuntimeConfiguration()
}
}
@@ -255,14 +258,84 @@ class TunnelDetailTableViewController: NSViewController {
stopUpdatingRuntimeConfiguration()
}
+ func applyTunnelConfiguration(tunnelConfiguration: TunnelConfiguration) {
+ // Incorporates changes from tunnelConfiguation. Ignores any changes in peer ordering.
+ func sectionChanged<T>(fields: [T], modelRowsInSection: inout [(isVisible: Bool, modelRow: TableViewModelRow)], tableView: NSTableView, rowOffset: Int, changes: [T: TunnelViewModel.ChangeHandlers.FieldChange]) {
+ for (index, field) in fields.enumerated() {
+ guard let change = changes[field] else { continue }
+ let row = modelRowsInSection[0 ..< index].filter { $0.isVisible }.count
+ switch change {
+ case .added:
+ tableView.insertRows(at: IndexSet(integer: rowOffset + row), withAnimation: .effectFade)
+ modelRowsInSection[index].isVisible = true
+ case .removed:
+ tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: .effectFade)
+ modelRowsInSection[index].isVisible = false
+ case .modified:
+ tableView.removeRows(at: IndexSet(integer: rowOffset + row), withAnimation: [])
+ tableView.insertRows(at: IndexSet(integer: rowOffset + row), withAnimation: [])
+ }
+ }
+ }
+
+ var isChanged = false
+ let changeHandlers = TunnelViewModel.ChangeHandlers(
+ interfaceChanged: { [weak self] changes in
+ guard let self = self else { return }
+ sectionChanged(fields: TunnelDetailTableViewController.interfaceFields, modelRowsInSection: &self.tableViewModelRowsBySection[0],
+ tableView: self.tableView, rowOffset: 0, changes: changes)
+ isChanged = true
+ },
+ peerChangedAt: { [weak self] peerIndex, changes in
+ guard let self = self else { return }
+ let sectionIndex = 1 + peerIndex
+ let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
+ sectionChanged(fields: TunnelDetailTableViewController.peerFields, modelRowsInSection: &self.tableViewModelRowsBySection[sectionIndex],
+ tableView: self.tableView, rowOffset: rowOffset, changes: changes)
+ isChanged = true
+ },
+ peersRemovedAt: { [weak self] peerIndices in
+ guard let self = self else { return }
+ for peerIndex in peerIndices {
+ let sectionIndex = 1 + peerIndex
+ let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
+ let count = self.tableViewModelRowsBySection[sectionIndex].filter { $0.isVisible }.count
+ self.tableView.removeRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
+ self.tableViewModelRowsBySection.remove(at: sectionIndex)
+ }
+ isChanged = true
+ },
+ peersInsertedAt: { [weak self] peerIndices in
+ guard let self = self else { return }
+ for peerIndex in peerIndices {
+ let peerData = self.tunnelViewModel.peersData[peerIndex]
+ let sectionIndex = 1 + peerIndex
+ let rowOffset = self.tableViewModelRowsBySection[0 ..< sectionIndex].flatMap { $0.filter { $0.isVisible } }.count
+ var modelRowsInSection: [(isVisible: Bool, modelRow: TableViewModelRow)] = TunnelDetailTableViewController.peerFields.map {
+ (isVisible: !peerData[$0].isEmpty, modelRow: .peerFieldRow(peer: peerData, field: $0))
+ }
+ modelRowsInSection.append((isVisible: true, modelRow: .spacerRow))
+ let count = modelRowsInSection.filter { $0.isVisible }.count
+ self.tableView.insertRows(at: IndexSet(integersIn: rowOffset ..< rowOffset + count), withAnimation: .effectFade)
+ self.tableViewModelRowsBySection.insert(modelRowsInSection, at: sectionIndex)
+ }
+ isChanged = true
+ }
+ )
+
+ tableView.beginUpdates()
+ self.tunnelViewModel.applyConfiguration(other: tunnelConfiguration, changeHandlers: changeHandlers)
+ if isChanged {
+ updateTableViewModelRows()
+ }
+ tableView.endUpdates()
+ }
+
private func reloadRuntimeConfiguration() {
- tunnel.getRuntimeTunnelConfiguration(completionHandler: {
- guard let tunnelConfiguration = $0 else { return }
- self.tunnelViewModel = TunnelViewModel(tunnelConfiguration: tunnelConfiguration)
- // TODO(roopc): make this not loose scroll position
- self.tableView.reloadData()
- self.tunnelEditVC = nil
- })
+ tunnel.getRuntimeTunnelConfiguration { [weak self] tunnelConfiguration in
+ guard let tunnelConfiguration = tunnelConfiguration else { return }
+ self?.applyTunnelConfiguration(tunnelConfiguration: tunnelConfiguration)
+ }
}
func startUpdatingRuntimeConfiguration() {