mas/mas-cli/AppStore/PurchaseDownloadObserver.swift
2016-10-21 22:59:33 +01:00

114 lines
3 KiB
Swift

//
// PurchaseDownloadObserver.swift
// mas-cli
//
// Created by Andrew Naylor on 21/08/2015.
// Copyright (c) 2015 Andrew Naylor. All rights reserved.
//
@objc class PurchaseDownloadObserver: NSObject, CKDownloadQueueObserver {
let purchase: SSPurchase
var completionHandler: (() -> ())?
var errorHandler: ((MASError) -> ())?
init(purchase: SSPurchase) {
self.purchase = purchase
}
func downloadQueue(_ queue: CKDownloadQueue, statusChangedFor download: SSDownload) {
guard download.metadata.itemIdentifier == purchase.itemIdentifier,
let status = download.status else {
return
}
if status.isFailed || status.isCancelled {
queue.removeDownload(withItemIdentifier: download.metadata.itemIdentifier)
}
else if let state = status.progressState {
progress(state)
}
}
func downloadQueue(_ queue: CKDownloadQueue, changedWithAddition download: SSDownload) {
guard download.metadata.itemIdentifier == purchase.itemIdentifier else {
return
}
clearLine()
printInfo("Downloading \(download.metadata.title)")
}
func downloadQueue(_ queue: CKDownloadQueue, changedWithRemoval download: SSDownload) {
guard download.metadata.itemIdentifier == purchase.itemIdentifier,
let status = download.status else {
return
}
clearLine()
if status.isFailed {
errorHandler?(.downloadFailed(error: status.error as NSError?))
}
else if status.isCancelled {
errorHandler?(.cancelled)
}
else {
printInfo("Installed \(download.metadata.title)")
completionHandler?()
}
}
}
struct ProgressState {
let percentComplete: Float
let phase: String
var percentage: String {
return String(format: "%.1f%%", arguments: [floor(percentComplete * 100)])
}
}
func progress(_ state: ProgressState) {
// Don't display the progress bar if we're not on a terminal
guard isatty(fileno(stdout)) != 0 else {
return
}
let barLength = 60
let completeLength = Int(state.percentComplete * Float(barLength))
var bar = ""
for i in 0..<barLength {
if i < completeLength {
bar += "#"
}
else {
bar += "-"
}
}
clearLine()
print("\(bar) \(state.percentage) \(state.phase)", terminator: "")
fflush(stdout)
}
extension SSDownloadStatus {
var progressState: ProgressState? {
if let phase = activePhase {
return ProgressState(percentComplete: percentComplete, phase: phase.phaseDescription)
}
else {
return nil
}
}
}
extension SSDownloadPhase {
var phaseDescription: String {
switch phaseType {
case 0:
return "Downloading"
case 1:
return "Installing"
default:
return "Waiting"
}
}
}