From 4e29c7a38ccbd23c17f3a9382e36441eebea9d10 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Mon, 30 Mar 2020 15:23:20 -0700 Subject: [PATCH] Fixes RefreshAltStoreViewController never finishing --- .../RefreshAltStoreViewController.swift | 4 +-- AltStore/Managing Apps/AppManager.swift | 26 +++++++++-------- .../Operations/AuthenticationOperation.swift | 5 +++- AltStore/Operations/OperationContexts.swift | 29 +++++++++++++++++++ 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/AltStore/Authentication/RefreshAltStoreViewController.swift b/AltStore/Authentication/RefreshAltStoreViewController.swift index 6c17f427..a14124b0 100644 --- a/AltStore/Authentication/RefreshAltStoreViewController.swift +++ b/AltStore/Authentication/RefreshAltStoreViewController.swift @@ -52,12 +52,12 @@ private extension RefreshAltStoreViewController switch result { case .success: self.completionHandler?(.success(())) - case .failure(let error): + case .failure(let error as NSError): DispatchQueue.main.async { sender.progress = nil sender.isIndicatingActivity = false - let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh AltStore", comment: ""), message: error.localizedDescription, preferredStyle: .alert) + let alertController = UIAlertController(title: NSLocalizedString("Failed to Refresh AltStore", comment: ""), message: error.localizedFailureReason ?? error.localizedDescription, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("Try Again", comment: ""), style: .default, handler: { (action) in refresh() })) diff --git a/AltStore/Managing Apps/AppManager.swift b/AltStore/Managing Apps/AppManager.swift index 8b215f96..202e6da1 100644 --- a/AltStore/Managing Apps/AppManager.swift +++ b/AltStore/Managing Apps/AppManager.swift @@ -135,7 +135,7 @@ extension AppManager } } - self.run([findServerOperation]) + self.run([findServerOperation], context: context) return findServerOperation } @@ -162,7 +162,7 @@ extension AppManager } authenticationOperation.addDependency(findServerOperation) - self.run([authenticationOperation]) + self.run([authenticationOperation], context: context) return authenticationOperation } @@ -184,7 +184,7 @@ extension AppManager } } - self.run([fetchSourceOperation]) + self.run([fetchSourceOperation], context: nil) } func fetchSources(completionHandler: @escaping (Result, Error>) -> Void) @@ -231,7 +231,7 @@ extension AppManager NotificationCenter.default.post(name: AppManager.didFetchSourceNotification, object: self) } - self.run(operations) + self.run(operations, context: nil) } } @@ -244,7 +244,7 @@ extension AppManager let fetchAppIDsOperation = FetchAppIDsOperation(context: authenticationOperation.context) fetchAppIDsOperation.resultHandler = completionHandler fetchAppIDsOperation.addDependency(authenticationOperation) - self.run([fetchAppIDsOperation]) + self.run([fetchAppIDsOperation], context: authenticationOperation.context) } @discardableResult @@ -311,7 +311,7 @@ extension AppManager } deactivateAppOperation.addDependency(findServerOperation) - self.run([deactivateAppOperation], requiresSerialQueue: true) + self.run([deactivateAppOperation], context: context, requiresSerialQueue: true) } func installationProgress(for app: AppProtocol) -> Progress? @@ -434,7 +434,7 @@ private extension AppManager } } awaitAuthenticationOperation.addDependency(authenticationOperation) - self.run([awaitAuthenticationOperation], requiresSerialQueue: true) + self.run([awaitAuthenticationOperation], context: group.context, requiresSerialQueue: true) } else { @@ -541,7 +541,7 @@ private extension AppManager let operations = [downloadOperation, refreshAnisetteDataOperation, fetchProvisioningProfilesOperation, resignAppOperation, sendAppOperation, installOperation] group.add(operations) - self.run(operations) + self.run(operations, context: group.context) return progress } @@ -590,7 +590,7 @@ private extension AppManager let operations = [fetchProvisioningProfilesOperation, refreshAppOperation] group.add(operations) - self.run(operations) + self.run(operations, context: group.context) return progress } @@ -665,7 +665,7 @@ private extension AppManager UNUserNotificationCenter.current().add(request) } - func run(_ operations: [Foundation.Operation], requiresSerialQueue: Bool = false) + func run(_ operations: [Foundation.Operation], context: OperationContext?, requiresSerialQueue: Bool = false) { for operation in operations { @@ -673,9 +673,9 @@ private extension AppManager { case _ where requiresSerialQueue: fallthrough case is InstallAppOperation, is RefreshAppOperation: - if let previousOperation = self.serialOperationQueue.operations.last + if let context = context, let previousOperation = self.serialOperationQueue.operations.last(where: { context.operations.contains($0) }) { - // Ensure operations execute in the order they're added, since they may become ready at different points. + // Ensure operations execute in the order they're added (in same context), since they may become ready at different points. operation.addDependency(previousOperation) } @@ -684,6 +684,8 @@ private extension AppManager default: self.operationQueue.addOperation(operation) } + + context?.operations.add(operation) } } diff --git a/AltStore/Operations/AuthenticationOperation.swift b/AltStore/Operations/AuthenticationOperation.swift index 1add4234..054ba403 100644 --- a/AltStore/Operations/AuthenticationOperation.swift +++ b/AltStore/Operations/AuthenticationOperation.swift @@ -655,8 +655,11 @@ private extension AuthenticationOperation completionHandler(false) #else DispatchQueue.main.async { + let context = AuthenticatedOperationContext(context: self.context) + context.operations.removeAllObjects() // Prevent deadlock due to endless waiting on previous operations to finish. + let refreshViewController = self.storyboard.instantiateViewController(withIdentifier: "refreshAltStoreViewController") as! RefreshAltStoreViewController - refreshViewController.context = self.context + refreshViewController.context = context refreshViewController.completionHandler = { _ in completionHandler(true) } diff --git a/AltStore/Operations/OperationContexts.swift b/AltStore/Operations/OperationContexts.swift index ef138bf1..406ddee7 100644 --- a/AltStore/Operations/OperationContexts.swift +++ b/AltStore/Operations/OperationContexts.swift @@ -16,6 +16,25 @@ class OperationContext { var server: Server? var error: Error? + + let operations: NSHashTable + + init(server: Server? = nil, error: Error? = nil, operations: [Foundation.Operation] = []) + { + self.server = server + self.error = error + + self.operations = NSHashTable.weakObjects() + for operation in operations + { + self.operations.add(operation) + } + } + + convenience init(context: OperationContext) + { + self.init(server: context.server, error: context.error, operations: context.operations.allObjects) + } } class AuthenticatedOperationContext: OperationContext @@ -26,6 +45,16 @@ class AuthenticatedOperationContext: OperationContext var certificate: ALTCertificate? weak var authenticationOperation: AuthenticationOperation? + + convenience init(context: AuthenticatedOperationContext) + { + self.init(server: context.server, error: context.error, operations: context.operations.allObjects) + + self.session = context.session + self.team = context.team + self.certificate = context.certificate + self.authenticationOperation = context.authenticationOperation + } } @dynamicMemberLookup