add DownloadIFNeeded

This commit is contained in:
Francisco Gindre 2020-10-08 14:00:27 -03:00
parent af8ee1ef12
commit 37a15bb93f
6 changed files with 141 additions and 48 deletions

View File

@ -10,7 +10,7 @@ import Foundation
import ZcashLightClientKit
import MnemonicSwift
struct DemoAppConfig {
static var host = ZcashSDK.isMainnet ? "lightwalletd.electriccoin.co" : "localhost"
static var host = ZcashSDK.isMainnet ? "localhost" : "localhost"
static var port: Int = 9067
static var birthdayHeight: BlockHeight = ZcashSDK.isMainnet ? 663174 : 620_000
static var network = ZcashSDK.isMainnet ? ZcashNetwork.mainNet : ZcashNetwork.testNet

View File

@ -59,32 +59,18 @@ class SaplingParametersViewController: UIViewController {
@IBAction func download(_ sender: Any) {
let outputParameter = try! __outputParamsURL()
let spendParameter = try! __spendParamsURL()
if !FileManager.default.isReadableFile(atPath: outputParameter.absoluteString) {
SaplingParameterDownloader.downloadOutputParameter(outputParameter) { [weak self] result in
SaplingParameterDownloader.downloadParamsIfnotPresent(spendURL: spendParameter, outputURL: outputParameter) { (result) in
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
DispatchQueue.main.async {
switch result{
case .success:
self.updateButtons()
self.updateColor()
case .failure(let error):
self.showError(error)
}
}
}
}
if !FileManager.default.isReadableFile(atPath: spendParameter.absoluteString) {
SaplingParameterDownloader.downloadSpendParameter(try! __spendParamsURL()) { [weak self] result in
guard let self = self else { return }
DispatchQueue.main.async {
switch result{
case .success:
self.updateButtons()
self.updateColor()
case .failure(let error):
self.showError(error)
}
switch result {
case .success(let urls):
self.spendPath.text = urls.spend.path
self.outputPath.text = urls.output.path
self.updateColor()
self.updateButtons()
case .failure(let error):
self.showError(error)
}
}
}
@ -109,14 +95,4 @@ class SaplingParametersViewController: UIViewController {
self.updateColor()
self.updateButtons()
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}

View File

@ -227,11 +227,58 @@ public class Initializer {
}
func isSpendParameterPresent() -> Bool {
FileManager.default.isReadableFile(atPath: self.spendParamsURL.absoluteString)
FileManager.default.isReadableFile(atPath: self.spendParamsURL.path)
}
func isOutputParameterPresent() -> Bool {
FileManager.default.isExecutableFile(atPath: self.outputParamsURL.absoluteString)
FileManager.default.isReadableFile(atPath: self.outputParamsURL.path)
}
func downloadParametersIfNeeded(result: @escaping (Result<Bool,Error>) -> Void) {
let spendParameterPresent = isSpendParameterPresent()
let outputParameterPresent = isOutputParameterPresent()
if spendParameterPresent && outputParameterPresent {
result(.success(true))
return
}
let outputURL = self.outputParamsURL
let spendURL = self.spendParamsURL
if !outputParameterPresent {
SaplingParameterDownloader.downloadOutputParameter(outputURL) { outputResult in
switch outputResult {
case .failure(let e):
result(.failure(e))
case .success:
guard !spendParameterPresent else {
result(.success(false))
return
}
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
switch spendResult {
case .failure(let e):
result(.failure(e))
case .success:
result(.success(false))
}
}
}
}
} else if !spendParameterPresent {
SaplingParameterDownloader.downloadSpendParameter(spendURL) { (spendResult) in
switch spendResult {
case .failure(let e):
result(.failure(e))
case .success:
result(.success(false))
}
}
}
}
}

View File

@ -21,6 +21,7 @@ public enum SynchronizerError: Error {
case networkTimeout
case uncategorized(underlyingError: Error)
case criticalError
case parameterMissing(underlyingError: Error)
}
/**

View File

@ -392,12 +392,6 @@ public class SDKSynchronizer: Synchronizer {
@objc func applicationWillResignActive(_ notification: Notification) {
registerBackgroundActivity()
LoggerProxy.debug("applicationWillResignActive")
// do {
//
// try stop()
// } catch {
// LoggerProxy.debug("stop failed with error: \(error)")
// }
}
@objc func applicationWillTerminate(_ notification: Notification) {
@ -408,6 +402,20 @@ public class SDKSynchronizer: Synchronizer {
public func sendToAddress(spendingKey: String, zatoshi: Int64, toAddress: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
initializer.downloadParametersIfNeeded { (downloadResult) in
DispatchQueue.main.async { [weak self] in
switch downloadResult {
case .success:
self?.createToAddress(spendingKey: spendingKey, zatoshi: zatoshi, toAddress: toAddress, memo: memo, from: accountIndex, resultBlock: resultBlock)
case .failure(let error):
resultBlock(.failure(SynchronizerError.parameterMissing(underlyingError: error)))
}
}
}
}
func createToAddress(spendingKey: String, zatoshi: Int64, toAddress: String, memo: String?, from accountIndex: Int, resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void) {
do {
let spend = try transactionManager.initSpend(zatoshi: Int(zatoshi), toAddress: toAddress, memo: memo, from: accountIndex)
@ -435,7 +443,6 @@ public class SDKSynchronizer: Synchronizer {
resultBlock(.failure(error))
}
}
public func getAddress(accountIndex: Int) -> String {
initializer.getAddress(index: accountIndex) ?? ""
}
@ -464,7 +471,7 @@ public class SDKSynchronizer: Synchronizer {
PagedTransactionRepositoryBuilder.build(initializer: initializer, kind: .all)
}
public func latestDownloadedHeight() throws -> BlockHeight {
public func latestDownloadedHeight() throws -> BlockHeight {
try initializer.downloader.lastDownloadedBlockHeight()
}

View File

@ -6,13 +6,21 @@
//
import Foundation
/**
Helper class to handle the download of Sapling parameters
*/
public class SaplingParameterDownloader {
public enum Errors: Error {
case invalidURL(url: String)
case failed(error: Error)
}
/**
Download a Spend parameter from default host and stores it at given URL
- Parameters:
- at: The destination URL for the download
- result: block to handle the download success or error
*/
public static func downloadSpendParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
guard let url = URL(string: spendParamsURLString) else {
@ -21,7 +29,12 @@ public class SaplingParameterDownloader {
}
downloadFileWithRequest(URLRequest(url: url), at: at, result: result)
}
/**
Download an Output parameter from default host and stores it at given URL
- Parameters:
- at: The destination URL for the download
- result: block to handle the download success or error
*/
public static func downloadOutputParameter(_ at: URL, result: @escaping (Result<URL, Error>) -> Void) {
guard let url = URL(string: outputParamsURLString) else {
result(.failure(Errors.invalidURL(url: outputParamsURLString)))
@ -46,6 +59,55 @@ public class SaplingParameterDownloader {
}
task.resume()
}
/**
Downloads the parameters if not present and provides the resulting URLs for both parameters
- Parameters:
- spendURL: URL to check whether the parameter is already downloaded
- outputURL: URL to check whether the parameter is already downloaded
- result: block to handle success or error
*/
public static func downloadParamsIfnotPresent(spendURL: URL, outputURL: URL, result: @escaping (Result<(spend: URL, output: URL),Error>) -> Void) {
ensureSpendParameter(at: spendURL) { (spendResult) in
switch spendResult {
case .success(let spendResultURL):
ensureOutputParameter(at: outputURL) { (outputResult) in
switch outputResult {
case .success(let outputResultURL):
result(.success((spendResultURL,outputResultURL)))
case .failure(let outputResultError):
result(.failure(Errors.failed(error: outputResultError)))
}
}
case .failure(let spendResultError):
result(.failure(Errors.failed(error: spendResultError)))
}
}
}
static func ensureSpendParameter(at url: URL, result: @escaping (Result<URL,Error>) -> Void) {
if isFilePresent(url: url) {
DispatchQueue.global().async {
result(.success(url))
}
} else {
downloadSpendParameter(url, result: result)
}
}
static func ensureOutputParameter(at url: URL, result: @escaping (Result<URL,Error>) -> Void) {
if isFilePresent(url: url) {
DispatchQueue.global().async {
result(.success(url))
}
} else {
downloadOutputParameter(url, result: result)
}
}
static func isFilePresent(url: URL) -> Bool {
(try? FileManager.default.attributesOfItem(atPath: url.path)) != nil
}
static var spendParamsURLString: String {
return ZcashSDK.CLOUD_PARAM_DIR_URL + ZcashSDK.SPEND_PARAM_FILE_NAME