Import: rework addMultiple logic

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2018-11-03 02:51:32 +01:00
parent dff928fafa
commit 95101dce5c
2 changed files with 46 additions and 39 deletions

View File

@ -145,40 +145,50 @@ class TunnelsListTableViewController: UITableViewController {
do { do {
unarchivedFiles = try ZipArchive.unarchive(url: url, requiredFileExtensions: ["conf"]) unarchivedFiles = try ZipArchive.unarchive(url: url, requiredFileExtensions: ["conf"])
} catch ZipArchiveError.cantOpenInputZipFile { } catch ZipArchiveError.cantOpenInputZipFile {
showErrorAlert(title: "Unable to read zip archive", message: "The zip archive could not be read") showErrorAlert(title: "Unable to read zip archive", message: "The zip archive could not be read.")
return
} catch ZipArchiveError.badArchive { } catch ZipArchiveError.badArchive {
showErrorAlert(title: "Unable to read zip archive", message: "Bad or corrupt zip archive") showErrorAlert(title: "Unable to read zip archive", message: "Bad or corrupt zip archive.")
return
} catch (let error) { } catch (let error) {
showErrorAlert(title: "Unable to read zip archive", message: "Unexpected error: \(String(describing: error))") showErrorAlert(title: "Unable to read zip archive", message: "Unexpected error: \(String(describing: error))")
}
var numberOfConfigFilesWithErrors = 0
var tunnelConfigurationsToAdd: [TunnelConfiguration] = []
for unarchivedFile in unarchivedFiles {
guard let tunnelsManager = tunnelsManager else { return }
if let fileBaseName = URL(string: unarchivedFile.fileName)?.deletingPathExtension().lastPathComponent,
(!tunnelsManager.containsTunnel(named: fileBaseName)),
let fileContents = String(data: unarchivedFile.contents, encoding: .utf8),
let tunnelConfiguration = try? WgQuickConfigFileParser.parse(fileContents, name: fileBaseName) {
tunnelConfigurationsToAdd.append(tunnelConfiguration)
} else {
numberOfConfigFilesWithErrors = numberOfConfigFilesWithErrors + 1
}
}
guard (tunnelConfigurationsToAdd.count > 0) else {
showErrorAlert(title: "No configurations found", message: "Zip archive does not contain any valid .conf files")
return return
} }
var numberOfTunnelsRemainingAfterError = 0
tunnelsManager?.addMultiple(tunnelConfigurations: tunnelConfigurationsToAdd) { (numberOfTunnelsRemaining, error) in for (i, unarchivedFile) in unarchivedFiles.enumerated().reversed() {
if (error != nil) { if let trimmedName = URL(string: unarchivedFile.fileName)?.deletingPathExtension().lastPathComponent, !trimmedName.isEmpty {
numberOfTunnelsRemainingAfterError = numberOfTunnelsRemaining unarchivedFiles[i].fileName = trimmedName
} else { } else {
assert(numberOfTunnelsRemaining == 0) unarchivedFiles.remove(at: i)
} }
} }
if (numberOfConfigFilesWithErrors > 0) { if (unarchivedFiles.isEmpty) {
showErrorAlert(title: "Created \(unarchivedFiles.count) tunnels", showErrorAlert(title: "No tunnels in zip archive", message: "No .conf tunnel files were found inside the zip archive.")
message: "Created \(numberOfTunnelsRemainingAfterError) of \(unarchivedFiles.count) tunnels from files in zip archive") return
}
guard let tunnelsManager = tunnelsManager else { return }
unarchivedFiles.sort { $0.fileName < $1.fileName }
var lastFileName : String?
var configs: [TunnelConfiguration] = []
for file in unarchivedFiles {
if file.fileName == lastFileName {
continue
}
lastFileName = file.fileName
guard let fileContents = String(data: file.contents, encoding: .utf8) else {
continue
}
guard let tunnelConfig = try? WgQuickConfigFileParser.parse(fileContents, name: file.fileName) else {
continue
}
configs.append(tunnelConfig)
}
tunnelsManager.addMultiple(tunnelConfigurations: configs) { [weak self] (numberSuccessful) in
if numberSuccessful == unarchivedFiles.count {
return
}
self?.showErrorAlert(title: "Created \(numberSuccessful) tunnels",
message: "Created \(numberSuccessful) of \(unarchivedFiles.count) tunnels from zip archive")
} }
} }
} }

View File

@ -119,23 +119,20 @@ class TunnelsManager {
} }
} }
func addMultiple(tunnelConfigurations: [TunnelConfiguration], completionHandler: @escaping (Int, TunnelManagementError?) -> Void) { func addMultiple(tunnelConfigurations: [TunnelConfiguration], completionHandler: @escaping (UInt) -> Void) {
addMultiple(tunnelConfigurations: tunnelConfigurations[0...], completionHandler: completionHandler) addMultiple(tunnelConfigurations: tunnelConfigurations[0...], numberSuccessful: 0, completionHandler: completionHandler)
} }
private func addMultiple(tunnelConfigurations: ArraySlice<TunnelConfiguration>, completionHandler: @escaping (Int, TunnelManagementError?) -> Void) { private func addMultiple(tunnelConfigurations: ArraySlice<TunnelConfiguration>, numberSuccessful: UInt, completionHandler: @escaping (UInt) -> Void) {
assert(!tunnelConfigurations.isEmpty) if tunnelConfigurations.isEmpty {
let head = tunnelConfigurations.first! completionHandler(numberSuccessful)
let tail = tunnelConfigurations[1 ..< tunnelConfigurations.count] return
self.add(tunnelConfiguration: head) { [weak self] (tunnel, error) in
if (error != nil) {
completionHandler(tail.count, error)
} else if (tail.isEmpty) {
completionHandler(0, nil)
} else {
DispatchQueue.main.async {
self?.addMultiple(tunnelConfigurations: tail, completionHandler: completionHandler)
} }
let head = tunnelConfigurations.first!
let tail = tunnelConfigurations[1...]
self.add(tunnelConfiguration: head) { [weak self] (tunnel, error) in
DispatchQueue.main.async {
self?.addMultiple(tunnelConfigurations: tail, numberSuccessful: numberSuccessful + (error == nil ? 1 : 0), completionHandler: completionHandler)
} }
} }
} }