mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-18 03:03:31 +01:00
[AltStore] Improves app installation cancellation/progress tracking
This commit is contained in:
@@ -26,6 +26,8 @@ class AppManager
|
|||||||
private let operationQueue = OperationQueue()
|
private let operationQueue = OperationQueue()
|
||||||
private let processingQueue = DispatchQueue(label: "com.altstore.AppManager.processingQueue")
|
private let processingQueue = DispatchQueue(label: "com.altstore.AppManager.processingQueue")
|
||||||
|
|
||||||
|
private var installationProgress = [App: Progress]()
|
||||||
|
|
||||||
private init()
|
private init()
|
||||||
{
|
{
|
||||||
self.operationQueue.name = "com.altstore.AppManager.operationQueue"
|
self.operationQueue.name = "com.altstore.AppManager.operationQueue"
|
||||||
@@ -105,10 +107,17 @@ extension AppManager
|
|||||||
{
|
{
|
||||||
func install(_ app: App, presentingViewController: UIViewController, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> Progress
|
func install(_ app: App, presentingViewController: UIViewController, completionHandler: @escaping (Result<InstalledApp, Error>) -> Void) -> Progress
|
||||||
{
|
{
|
||||||
|
if let progress = self.installationProgress(for: app)
|
||||||
|
{
|
||||||
|
return progress
|
||||||
|
}
|
||||||
|
|
||||||
let group = self.install([app], forceDownload: true, presentingViewController: presentingViewController)
|
let group = self.install([app], forceDownload: true, presentingViewController: presentingViewController)
|
||||||
group.completionHandler = { (result) in
|
group.completionHandler = { (result) in
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
self.installationProgress[app] = nil
|
||||||
|
|
||||||
guard let (_, result) = try result.get().first else { throw OperationError.unknown }
|
guard let (_, result) = try result.get().first else { throw OperationError.unknown }
|
||||||
completionHandler(result)
|
completionHandler(result)
|
||||||
}
|
}
|
||||||
@@ -118,6 +127,8 @@ extension AppManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.installationProgress[app] = group.progress
|
||||||
|
|
||||||
return group.progress
|
return group.progress
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +139,12 @@ extension AppManager
|
|||||||
let group = self.install(apps, forceDownload: false, presentingViewController: presentingViewController, group: group)
|
let group = self.install(apps, forceDownload: false, presentingViewController: presentingViewController, group: group)
|
||||||
return group
|
return group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func installationProgress(for app: App) -> Progress?
|
||||||
|
{
|
||||||
|
let progress = self.installationProgress[app]
|
||||||
|
return progress
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private extension AppManager
|
private extension AppManager
|
||||||
@@ -171,11 +188,8 @@ private extension AppManager
|
|||||||
/* Resign */
|
/* Resign */
|
||||||
let resignAppOperation = ResignAppOperation(context: context)
|
let resignAppOperation = ResignAppOperation(context: context)
|
||||||
resignAppOperation.resultHandler = { (result) in
|
resignAppOperation.resultHandler = { (result) in
|
||||||
switch result
|
guard let fileURL = self.process(result, context: context) else { return }
|
||||||
{
|
context.resignedFileURL = fileURL
|
||||||
case .failure(let error): context.error = error
|
|
||||||
case .success(let fileURL): context.resignedFileURL = fileURL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
resignAppOperation.addDependency(authenticationOperation)
|
resignAppOperation.addDependency(authenticationOperation)
|
||||||
progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20)
|
progress.addChild(resignAppOperation.progress, withPendingUnitCount: 20)
|
||||||
@@ -203,11 +217,8 @@ private extension AppManager
|
|||||||
|
|
||||||
let downloadOperation = DownloadAppOperation(app: app)
|
let downloadOperation = DownloadAppOperation(app: app)
|
||||||
downloadOperation.resultHandler = { (result) in
|
downloadOperation.resultHandler = { (result) in
|
||||||
switch result
|
guard let installedApp = self.process(result, context: context) else { return }
|
||||||
{
|
context.installedApp = installedApp
|
||||||
case .failure(let error): context.error = error
|
|
||||||
case .success(let installedApp): context.installedApp = installedApp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
progress.addChild(downloadOperation.progress, withPendingUnitCount: 40)
|
progress.addChild(downloadOperation.progress, withPendingUnitCount: 40)
|
||||||
resignAppOperation.addDependency(downloadOperation)
|
resignAppOperation.addDependency(downloadOperation)
|
||||||
@@ -218,11 +229,8 @@ private extension AppManager
|
|||||||
/* Send */
|
/* Send */
|
||||||
let sendAppOperation = SendAppOperation(context: context)
|
let sendAppOperation = SendAppOperation(context: context)
|
||||||
sendAppOperation.resultHandler = { (result) in
|
sendAppOperation.resultHandler = { (result) in
|
||||||
switch result
|
guard let connection = self.process(result, context: context) else { return }
|
||||||
{
|
context.connection = connection
|
||||||
case .failure(let error): context.error = error
|
|
||||||
case .success(let connection): context.connection = connection
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
progress.addChild(sendAppOperation.progress, withPendingUnitCount: 10)
|
progress.addChild(sendAppOperation.progress, withPendingUnitCount: 10)
|
||||||
sendAppOperation.addDependency(resignAppOperation)
|
sendAppOperation.addDependency(resignAppOperation)
|
||||||
@@ -232,12 +240,7 @@ private extension AppManager
|
|||||||
/* Install */
|
/* Install */
|
||||||
let installOperation = InstallAppOperation(context: context)
|
let installOperation = InstallAppOperation(context: context)
|
||||||
installOperation.resultHandler = { (result) in
|
installOperation.resultHandler = { (result) in
|
||||||
switch result
|
guard let _ = self.process(result, context: context) else { return }
|
||||||
{
|
|
||||||
case .failure(let error): context.error = error
|
|
||||||
case .success: break
|
|
||||||
}
|
|
||||||
|
|
||||||
self.finishAppOperation(context)
|
self.finishAppOperation(context)
|
||||||
}
|
}
|
||||||
progress.addChild(installOperation.progress, withPendingUnitCount: 30)
|
progress.addChild(installOperation.progress, withPendingUnitCount: 30)
|
||||||
@@ -260,6 +263,13 @@ private extension AppManager
|
|||||||
let value = try result.get()
|
let value = try result.get()
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
catch OperationError.cancelled
|
||||||
|
{
|
||||||
|
context.error = OperationError.cancelled
|
||||||
|
self.finishAppOperation(context)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
context.error = error
|
context.error = error
|
||||||
@@ -270,6 +280,9 @@ private extension AppManager
|
|||||||
func finishAppOperation(_ context: AppOperationContext)
|
func finishAppOperation(_ context: AppOperationContext)
|
||||||
{
|
{
|
||||||
self.processingQueue.sync {
|
self.processingQueue.sync {
|
||||||
|
guard !context.isFinished else { return }
|
||||||
|
context.isFinished = true
|
||||||
|
|
||||||
if let error = context.error
|
if let error = context.error
|
||||||
{
|
{
|
||||||
context.group.results[context.appIdentifier] = .failure(error)
|
context.group.results[context.appIdentifier] = .failure(error)
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ class AppOperationContext
|
|||||||
var resignedFileURL: URL?
|
var resignedFileURL: URL?
|
||||||
var connection: NWConnection?
|
var connection: NWConnection?
|
||||||
|
|
||||||
|
var isFinished = false
|
||||||
|
|
||||||
var error: Error? {
|
var error: Error? {
|
||||||
get {
|
get {
|
||||||
return _error ?? self.group.error
|
return _error ?? self.group.error
|
||||||
|
|||||||
@@ -23,7 +23,14 @@ class ResultOperation<ResultType>: Operation
|
|||||||
{
|
{
|
||||||
guard !self.isFinished else { return }
|
guard !self.isFinished else { return }
|
||||||
|
|
||||||
self.resultHandler?(result)
|
if self.isCancelled
|
||||||
|
{
|
||||||
|
self.resultHandler?(.failure(OperationError.cancelled))
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
self.resultHandler?(result)
|
||||||
|
}
|
||||||
|
|
||||||
super.finish()
|
super.finish()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user