Merge branch 'optimize-pool-caching'
This commit is contained in:
commit
257f62e136
|
@ -26,36 +26,6 @@
|
|||
import UIKit
|
||||
import Passepartout_Core
|
||||
|
||||
private class PoolModel {
|
||||
let title: String
|
||||
|
||||
var poolsByGroup: [PoolGroup: [Pool]] = [:]
|
||||
|
||||
private(set) var sortedGroups: [PoolGroup] = []
|
||||
|
||||
var isEmpty: Bool {
|
||||
return sortedGroups.isEmpty
|
||||
}
|
||||
|
||||
init(title: String) {
|
||||
self.title = title
|
||||
}
|
||||
|
||||
func addPool(_ p: Pool) {
|
||||
let group = p.group()
|
||||
if var existingPools = poolsByGroup[group] {
|
||||
existingPools.append(p)
|
||||
poolsByGroup[group] = existingPools
|
||||
} else {
|
||||
poolsByGroup[group] = [p]
|
||||
}
|
||||
}
|
||||
|
||||
func sort() {
|
||||
sortedGroups = poolsByGroup.keys.sorted()
|
||||
}
|
||||
}
|
||||
|
||||
protocol ProviderPoolViewControllerDelegate: class {
|
||||
func providerPoolController(_: ProviderPoolViewController, didSelectPool pool: Pool)
|
||||
}
|
||||
|
@ -69,28 +39,19 @@ class ProviderPoolViewController: UIViewController {
|
|||
|
||||
weak var delegate: ProviderPoolViewControllerDelegate?
|
||||
|
||||
func setPools(_ pools: [Pool], currentPoolId: String?) {
|
||||
let freeModel = PoolModel(title: L10n.Provider.Pool.Sections.Free.header)
|
||||
let paidModel = PoolModel(title: L10n.Provider.Pool.Sections.Paid.header)
|
||||
for p in pools {
|
||||
if p.isFree ?? false {
|
||||
freeModel.addPool(p)
|
||||
} else {
|
||||
paidModel.addPool(p)
|
||||
func setModels(_ models: [PoolModel], currentPoolId: String?) {
|
||||
self.models = models
|
||||
|
||||
// XXX: uglyyy
|
||||
for m in models {
|
||||
for pools in m.poolsByGroup.values {
|
||||
for p in pools {
|
||||
if p.id == currentPoolId {
|
||||
currentPool = p
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.id == currentPoolId {
|
||||
currentPool = p
|
||||
}
|
||||
}
|
||||
freeModel.sort()
|
||||
paidModel.sort()
|
||||
|
||||
models = []
|
||||
if !freeModel.isEmpty {
|
||||
models.append(freeModel)
|
||||
}
|
||||
if !paidModel.isEmpty {
|
||||
models.append(paidModel)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,7 +101,7 @@ extension ProviderPoolViewController: UITableViewDataSource, UITableViewDelegate
|
|||
return nil
|
||||
}
|
||||
let model = models[section]
|
||||
return model.title
|
||||
return model.isFree ? L10n.Provider.Pool.Sections.Free.header : L10n.Provider.Pool.Sections.Paid.header
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
@ -173,7 +134,7 @@ extension ProviderPoolViewController: UITableViewDataSource, UITableViewDelegate
|
|||
let model = models[indexPath.section]
|
||||
let group = model.sortedGroups[indexPath.row]
|
||||
let groupPools = model.poolsByGroup[group]!
|
||||
guard let pool = groupPools.first else {
|
||||
guard let pool = groupPools.randomElement() else {
|
||||
fatalError("Empty pools in group \(group)")
|
||||
}
|
||||
currentPool = pool
|
||||
|
|
|
@ -152,7 +152,7 @@ class ServiceViewController: UIViewController, TableModelHost {
|
|||
|
||||
case .providerPoolSegueIdentifier:
|
||||
let vc = destination as? ProviderPoolViewController
|
||||
vc?.setPools(uncheckedProviderProfile.pools(), currentPoolId: uncheckedProviderProfile.poolId)
|
||||
vc?.setModels(InfrastructureCache.shared.poolModels(for: uncheckedProviderProfile), currentPoolId: uncheckedProviderProfile.poolId)
|
||||
vc?.delegate = self
|
||||
|
||||
case .endpointSegueIdentifier:
|
||||
|
@ -289,14 +289,19 @@ class ServiceViewController: UIViewController, TableModelHost {
|
|||
}
|
||||
|
||||
private func refreshProviderInfrastructure() {
|
||||
let name = uncheckedProviderProfile.name
|
||||
|
||||
let hud = HUD()
|
||||
let isUpdating = InfrastructureFactory.shared.update(uncheckedProviderProfile.name, notBeforeInterval: AppConstants.Web.minimumUpdateInterval) { (response, error) in
|
||||
let isUpdating = InfrastructureFactory.shared.update(name, notBeforeInterval: AppConstants.Web.minimumUpdateInterval) { (response, error) in
|
||||
hud.hide()
|
||||
guard let response = response else {
|
||||
return
|
||||
}
|
||||
self.lastInfrastructureUpdate = response.1
|
||||
self.tableView.reloadData()
|
||||
|
||||
// invalidate current pool cache
|
||||
InfrastructureCache.shared.removePoolModels(for: name)
|
||||
}
|
||||
if !isUpdating {
|
||||
hud.hide()
|
||||
|
|
|
@ -89,7 +89,7 @@ class ShortcutsConnectToViewController: UITableViewController, ProviderPoolViewC
|
|||
guard let provider = selectedProfile as? ProviderConnectionProfile else {
|
||||
return
|
||||
}
|
||||
vc.setPools(provider.pools(), currentPoolId: nil)
|
||||
vc.setModels(InfrastructureCache.shared.poolModels(for: provider), currentPoolId: nil)
|
||||
vc.delegate = self
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,8 @@
|
|||
0E58BD9322404EF1006FB157 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 0E58BD9122404EF1006FB157 /* Intents.intentdefinition */; };
|
||||
0E58BF65224152F9006FB157 /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 0E58BD9122404EF1006FB157 /* Intents.intentdefinition */; settings = {ATTRIBUTES = (no_codegen, ); }; };
|
||||
0E58BF68224305A8006FB157 /* Countries.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0E58BF6A224305A8006FB157 /* Countries.strings */; };
|
||||
0E66A270225FE25800F9C779 /* PoolModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E66A26F225FE25800F9C779 /* PoolModel.swift */; };
|
||||
0E66A272225FE5FB00F9C779 /* InfrastructureCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E66A271225FE5FB00F9C779 /* InfrastructureCache.swift */; };
|
||||
0E6BE13F20CFBAB300A6DD36 /* DebugLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6BE13E20CFBAB300A6DD36 /* DebugLogViewController.swift */; };
|
||||
0E773BF8224BF37600CDDC8E /* ShortcutsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E773BF7224BF37600CDDC8E /* ShortcutsViewController.swift */; };
|
||||
0E89DFCE213EEDFA00741BA1 /* WizardProviderViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E89DFCD213EEDFA00741BA1 /* WizardProviderViewController.swift */; };
|
||||
|
@ -217,6 +219,8 @@
|
|||
0E5E5DDE215119AF00E318A3 /* VPNStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNStatus.swift; sourceTree = "<group>"; };
|
||||
0E5E5DE1215119DD00E318A3 /* VPNConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNConfiguration.swift; sourceTree = "<group>"; };
|
||||
0E5E5DE421511C5F00E318A3 /* GracefulVPN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GracefulVPN.swift; sourceTree = "<group>"; };
|
||||
0E66A26F225FE25800F9C779 /* PoolModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoolModel.swift; sourceTree = "<group>"; };
|
||||
0E66A271225FE5FB00F9C779 /* InfrastructureCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfrastructureCache.swift; sourceTree = "<group>"; };
|
||||
0E6BE13920CFB76800A6DD36 /* ApplicationError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationError.swift; sourceTree = "<group>"; };
|
||||
0E6BE13E20CFBAB300A6DD36 /* DebugLogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DebugLogViewController.swift; sourceTree = "<group>"; };
|
||||
0E773BF7224BF37600CDDC8E /* ShortcutsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShortcutsViewController.swift; sourceTree = "<group>"; };
|
||||
|
@ -476,7 +480,9 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
0EBE3AA3213DC1B000BFA2F5 /* HostConnectionProfile.swift */,
|
||||
0E66A271225FE5FB00F9C779 /* InfrastructureCache.swift */,
|
||||
0E79D13E21919EC900BB5FB2 /* PlaceholderConnectionProfile.swift */,
|
||||
0E66A26F225FE25800F9C779 /* PoolModel.swift */,
|
||||
0E79D14021919F5600BB5FB2 /* ProfileKey.swift */,
|
||||
0EBE3AA4213DC1B000BFA2F5 /* ProviderConnectionProfile.swift */,
|
||||
);
|
||||
|
@ -1005,6 +1011,7 @@
|
|||
files = (
|
||||
0E3152BD223FA03D00F61841 /* GroupConstants.swift in Sources */,
|
||||
0ECEB10A224FECEA00E9E551 /* DataUnit.swift in Sources */,
|
||||
0E66A270225FE25800F9C779 /* PoolModel.swift in Sources */,
|
||||
0E3152C2223FA04800F61841 /* MockVPNProvider.swift in Sources */,
|
||||
0E533B162258E03B00EF94FC /* PoolGroup.swift in Sources */,
|
||||
0E3152D2223FA05400F61841 /* DebugLog.swift in Sources */,
|
||||
|
@ -1035,6 +1042,7 @@
|
|||
0E3152CD223FA05400F61841 /* ConnectionProfile.swift in Sources */,
|
||||
0E3152BC223FA03D00F61841 /* ApplicationError.swift in Sources */,
|
||||
0E3152C9223FA04D00F61841 /* InfrastructureFactory.swift in Sources */,
|
||||
0E66A272225FE5FB00F9C779 /* InfrastructureCache.swift in Sources */,
|
||||
0E58BD9322404EF1006FB157 /* Intents.intentdefinition in Sources */,
|
||||
0E3152D3223FA05400F61841 /* EndpointDataSource.swift in Sources */,
|
||||
0E3152D4223FA05400F61841 /* Preferences.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// InfrastructureCache.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/11/19.
|
||||
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// TODO: retain max N pool models at a time (LRU)
|
||||
|
||||
public class InfrastructureCache {
|
||||
public static let shared = InfrastructureCache()
|
||||
|
||||
private var poolModelsByName: [Infrastructure.Name: [PoolModel]]
|
||||
|
||||
private init() {
|
||||
poolModelsByName = [:]
|
||||
}
|
||||
|
||||
public func poolModels(for provider: ProviderConnectionProfile) -> [PoolModel] {
|
||||
if let models = poolModelsByName[provider.name] {
|
||||
return models
|
||||
}
|
||||
let freeModel = PoolModel(isFree: true)
|
||||
let paidModel = PoolModel(isFree: false)
|
||||
for p in provider.infrastructure.pools {
|
||||
if p.isFree ?? false {
|
||||
freeModel.addPool(p)
|
||||
} else {
|
||||
paidModel.addPool(p)
|
||||
}
|
||||
// if p.id == currentPoolId {
|
||||
// currentPool = p
|
||||
// }
|
||||
}
|
||||
freeModel.sort()
|
||||
paidModel.sort()
|
||||
|
||||
var models: [PoolModel] = []
|
||||
if !freeModel.isEmpty {
|
||||
models.append(freeModel)
|
||||
}
|
||||
if !paidModel.isEmpty {
|
||||
models.append(paidModel)
|
||||
}
|
||||
poolModelsByName[provider.name] = models
|
||||
return models
|
||||
}
|
||||
|
||||
public func removePoolModels(for name: Infrastructure.Name? = nil) {
|
||||
if let name = name {
|
||||
poolModelsByName.removeValue(forKey: name)
|
||||
return
|
||||
}
|
||||
poolModelsByName.removeAll()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
//
|
||||
// PoolModel.swift
|
||||
// Passepartout
|
||||
//
|
||||
// Created by Davide De Rosa on 4/11/19.
|
||||
// Copyright (c) 2019 Davide De Rosa. All rights reserved.
|
||||
//
|
||||
// https://github.com/passepartoutvpn
|
||||
//
|
||||
// This file is part of Passepartout.
|
||||
//
|
||||
// Passepartout is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Passepartout is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public class PoolModel {
|
||||
public let isFree: Bool
|
||||
|
||||
public var poolsByGroup: [PoolGroup: [Pool]]
|
||||
|
||||
public private(set) var sortedGroups: [PoolGroup]
|
||||
|
||||
public init(isFree: Bool) {
|
||||
self.isFree = isFree
|
||||
poolsByGroup = [:]
|
||||
sortedGroups = []
|
||||
}
|
||||
|
||||
public var isEmpty: Bool {
|
||||
return sortedGroups.isEmpty
|
||||
}
|
||||
|
||||
public func addPool(_ p: Pool) {
|
||||
let group = p.group()
|
||||
if var existingPools = poolsByGroup[group] {
|
||||
existingPools.append(p)
|
||||
poolsByGroup[group] = existingPools
|
||||
} else {
|
||||
poolsByGroup[group] = [p]
|
||||
}
|
||||
}
|
||||
|
||||
public func sort() {
|
||||
sortedGroups = poolsByGroup.keys.sorted()
|
||||
}
|
||||
}
|
|
@ -72,10 +72,6 @@ public class ProviderConnectionProfile: ConnectionProfile, Codable, Equatable {
|
|||
presetId = infrastructure.defaults.preset
|
||||
}
|
||||
|
||||
public func pools() -> [Pool] {
|
||||
return infrastructure.pools
|
||||
}
|
||||
|
||||
private func validateEndpoint() {
|
||||
guard let pool = pool, let preset = preset else {
|
||||
manualAddress = nil
|
||||
|
|
|
@ -28,6 +28,8 @@ import SwiftyBeaver
|
|||
|
||||
private let log = SwiftyBeaver.self
|
||||
|
||||
// TODO: retain max N infrastructures at a time (LRU)
|
||||
|
||||
public class InfrastructureFactory {
|
||||
private static func embedded(withName name: Infrastructure.Name) -> Infrastructure {
|
||||
guard let url = name.bundleURL else {
|
||||
|
|
Loading…
Reference in New Issue