mirror of
https://github.com/X1a0He/Adobe-Downloader.git
synced 2025-11-25 11:18:53 +08:00
fix: Fix the issue with download tasks
1. Fixed the issue where after the task download is completed, the program will prompt that it has been paused when re-entering the program
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Release"
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
|
||||
@@ -4,22 +4,6 @@
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "18E41264-2FE9-43DB-B1ED-0F25585C8B89"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Adobe Downloader/Utils/DownloadUtils.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "442"
|
||||
endingLineNumber = "442"
|
||||
landmarkName = "startDownloadProcess(task:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
@@ -52,5 +36,19 @@
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "FF32C0C6-C193-4B43-831E-E6F00D1EE00D"
|
||||
shouldBeEnabled = "No"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "Adobe Downloader/Commons/Extensions.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "22"
|
||||
endingLineNumber = "22">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
||||
@@ -11,7 +11,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
if event.modifierFlags.contains(.command) && event.characters?.lowercased() == "q" {
|
||||
if let mainWindow = NSApp.mainWindow,
|
||||
mainWindow.sheets.isEmpty && !mainWindow.isSheet {
|
||||
self?.handleQuitCommand()
|
||||
_ = self?.applicationShouldTerminate(NSApp)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -19,16 +19,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor private func handleQuitCommand() {
|
||||
guard let manager = networkManager else {
|
||||
NSApplication.shared.terminate(nil)
|
||||
return
|
||||
}
|
||||
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||
guard let manager = networkManager else { return .terminateNow }
|
||||
|
||||
let hasActiveDownloads = manager.downloadTasks.contains { task in
|
||||
if case .downloading = task.totalStatus {
|
||||
return true
|
||||
}
|
||||
if case .downloading = task.totalStatus { return true }
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -40,6 +35,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
taskId: task.id,
|
||||
reason: .other(String(localized: "程序即将退出"))
|
||||
)
|
||||
await manager.saveTask(task)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +64,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
} else {
|
||||
NSApplication.shared.terminate(nil)
|
||||
}
|
||||
return .terminateCancel
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
@@ -19,38 +19,3 @@ extension NewDownloadTask {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NetworkManager {
|
||||
func configureNetworkMonitor() {
|
||||
monitor.pathUpdateHandler = { [weak self] path in
|
||||
Task { @MainActor [weak self] in
|
||||
guard let self else { return }
|
||||
let wasConnected = self.isConnected
|
||||
self.isConnected = path.status == .satisfied
|
||||
switch (wasConnected, self.isConnected) {
|
||||
case (false, true): await resumePausedTasks()
|
||||
case (true, false): await pauseActiveTasks()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
monitor.start(queue: .global(qos: .utility))
|
||||
}
|
||||
|
||||
private func resumePausedTasks() async {
|
||||
for task in downloadTasks {
|
||||
if case .paused(let info) = task.status,
|
||||
info.reason == .networkIssue {
|
||||
await downloadUtils.resumeDownloadTask(taskId: task.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func pauseActiveTasks() async {
|
||||
for task in downloadTasks {
|
||||
if case .downloading = task.status {
|
||||
await downloadUtils.pauseDownloadTask(taskId: task.id, reason: .networkIssue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,22 +99,21 @@ class NetworkManager: ObservableObject {
|
||||
|
||||
downloadTasks.append(task)
|
||||
updateDockBadge()
|
||||
saveTask(task)
|
||||
await saveTask(task)
|
||||
|
||||
do {
|
||||
try await downloadUtils.handleDownload(task: task, productInfo: productInfo, allowedPlatform: StorageData.shared.allowedPlatform, saps: saps)
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
||||
message: error.localizedDescription,
|
||||
error: error,
|
||||
timestamp: Date(),
|
||||
recoverable: true
|
||||
)))
|
||||
saveTask(task)
|
||||
await saveTask(task)
|
||||
await MainActor.run {
|
||||
objectWillChange.send()
|
||||
}
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,7 +135,7 @@ class NetworkManager: ObservableObject {
|
||||
timestamp: Date(),
|
||||
recoverable: false
|
||||
)))
|
||||
saveTask(task)
|
||||
await saveTask(task)
|
||||
}
|
||||
|
||||
if removeFiles {
|
||||
@@ -352,13 +351,10 @@ class NetworkManager: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
func saveTask(_ task: NewDownloadTask) {
|
||||
TaskPersistenceManager.shared.saveTask(task)
|
||||
objectWillChange.send()
|
||||
}
|
||||
|
||||
func loadSavedTasks() {
|
||||
Task {
|
||||
let savedTasks = TaskPersistenceManager.shared.loadTasks()
|
||||
await MainActor.run {
|
||||
for task in savedTasks {
|
||||
for product in task.productsToDownload {
|
||||
product.updateCompletedPackages()
|
||||
@@ -368,3 +364,46 @@ class NetworkManager: ObservableObject {
|
||||
updateDockBadge()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func saveTask(_ task: NewDownloadTask) async {
|
||||
await TaskPersistenceManager.shared.saveTask(task)
|
||||
objectWillChange.send()
|
||||
}
|
||||
|
||||
func configureNetworkMonitor() {
|
||||
monitor.pathUpdateHandler = { [weak self] path in
|
||||
let task = { @MainActor @Sendable [weak self] in
|
||||
guard let self else { return }
|
||||
let wasConnected = self.isConnected
|
||||
self.isConnected = path.status == .satisfied
|
||||
switch (wasConnected, self.isConnected) {
|
||||
case (false, true):
|
||||
await self.resumePausedTasks()
|
||||
case (true, false):
|
||||
await self.pauseActiveTasks()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
Task(operation: task)
|
||||
}
|
||||
monitor.start(queue: .global(qos: .utility))
|
||||
}
|
||||
|
||||
private func resumePausedTasks() async {
|
||||
for task in downloadTasks {
|
||||
if case .paused(let info) = task.status,
|
||||
info.reason == .networkIssue {
|
||||
await downloadUtils.resumeDownloadTask(taskId: task.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func pauseActiveTasks() async {
|
||||
for task in downloadTasks {
|
||||
if case .downloading = task.status {
|
||||
await downloadUtils.pauseDownloadTask(taskId: task.id, reason: .networkIssue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,9 @@ class DownloadUtils {
|
||||
|
||||
guard timeDiff >= NetworkConstants.progressUpdateInterval else { return }
|
||||
|
||||
Task {
|
||||
progressHandler?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
|
||||
}
|
||||
|
||||
lastUpdateTime = now
|
||||
lastBytes = totalBytesWritten
|
||||
@@ -133,21 +135,21 @@ class DownloadUtils {
|
||||
}
|
||||
}
|
||||
|
||||
await MainActor.run {
|
||||
if let task = networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||
task.setStatus(.paused(DownloadStatus.PauseInfo(
|
||||
reason: reason,
|
||||
timestamp: Date(),
|
||||
resumable: true
|
||||
)))
|
||||
networkManager?.saveTask(task)
|
||||
await networkManager?.saveTask(task)
|
||||
await MainActor.run {
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resumeDownloadTask(taskId: UUID) async {
|
||||
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||
await MainActor.run {
|
||||
task.setStatus(.downloading(DownloadStatus.DownloadInfo(
|
||||
fileName: task.currentPackage?.fullPackageName ?? "",
|
||||
currentPackageIndex: 0,
|
||||
@@ -155,7 +157,9 @@ class DownloadUtils {
|
||||
startTime: Date(),
|
||||
estimatedTimeRemaining: nil
|
||||
)))
|
||||
networkManager?.saveTask(task)
|
||||
await networkManager?.saveTask(task)
|
||||
await MainActor.run {
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
|
||||
if task.sapCode == "APRO" {
|
||||
@@ -178,8 +182,7 @@ class DownloadUtils {
|
||||
func cancelDownloadTask(taskId: UUID, removeFiles: Bool = false) async {
|
||||
await cancelTracker.cancel(taskId)
|
||||
|
||||
await MainActor.run {
|
||||
if let task = networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||
if removeFiles {
|
||||
try? FileManager.default.removeItem(at: task.directory)
|
||||
}
|
||||
@@ -191,6 +194,8 @@ class DownloadUtils {
|
||||
recoverable: false
|
||||
)))
|
||||
|
||||
await networkManager?.saveTask(task)
|
||||
await MainActor.run {
|
||||
networkManager?.updateDockBadge()
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
@@ -259,7 +264,8 @@ class DownloadUtils {
|
||||
return
|
||||
}
|
||||
|
||||
Task { @MainActor in
|
||||
Task {
|
||||
await MainActor.run {
|
||||
package.downloadedSize = package.downloadSize
|
||||
package.progress = 1.0
|
||||
package.status = .completed
|
||||
@@ -295,11 +301,13 @@ class DownloadUtils {
|
||||
}
|
||||
|
||||
product.updateCompletedPackages()
|
||||
networkManager?.saveTask(task)
|
||||
}
|
||||
await networkManager?.saveTask(task)
|
||||
await MainActor.run {
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
|
||||
continuation.resume()
|
||||
}
|
||||
},
|
||||
progressHandler: { [weak networkManager] bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
|
||||
Task { @MainActor in
|
||||
@@ -444,8 +452,8 @@ class DownloadUtils {
|
||||
startTime: Date(),
|
||||
estimatedTimeRemaining: nil
|
||||
)))
|
||||
networkManager?.saveTask(task)
|
||||
}
|
||||
await networkManager?.saveTask(task)
|
||||
|
||||
await progress.increment()
|
||||
|
||||
@@ -487,8 +495,8 @@ class DownloadUtils {
|
||||
totalTime: Date().timeIntervalSince(task.createAt),
|
||||
totalSize: task.totalSize
|
||||
)))
|
||||
networkManager?.saveTask(task)
|
||||
}
|
||||
await networkManager?.saveTask(task)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -925,6 +933,18 @@ class DownloadUtils {
|
||||
|
||||
let (errorMessage, isRecoverable) = classifyError(error)
|
||||
|
||||
if isRecoverable,
|
||||
let downloadTask = await cancelTracker.downloadTasks[taskId] {
|
||||
let resumeData = await withCheckedContinuation { continuation in
|
||||
downloadTask.cancel(byProducingResumeData: { data in
|
||||
continuation.resume(returning: data)
|
||||
})
|
||||
}
|
||||
if let resumeData = resumeData {
|
||||
await cancelTracker.storeResumeData(taskId, data: resumeData)
|
||||
}
|
||||
}
|
||||
|
||||
if isRecoverable && task.retryCount < NetworkConstants.maxRetryAttempts {
|
||||
task.retryCount += 1
|
||||
let nextRetryDate = Date().addingTimeInterval(TimeInterval(NetworkConstants.retryDelay / 1_000_000_000))
|
||||
@@ -946,7 +966,6 @@ class DownloadUtils {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
await MainActor.run {
|
||||
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
||||
message: errorMessage,
|
||||
error: error,
|
||||
@@ -961,7 +980,8 @@ class DownloadUtils {
|
||||
try? FileManager.default.removeItem(at: fileURL)
|
||||
}
|
||||
|
||||
networkManager?.saveTask(task)
|
||||
await networkManager?.saveTask(task)
|
||||
await MainActor.run {
|
||||
networkManager?.updateDockBadge()
|
||||
networkManager?.objectWillChange.send()
|
||||
}
|
||||
@@ -987,12 +1007,14 @@ class DownloadUtils {
|
||||
}
|
||||
case let urlError as URLError:
|
||||
switch urlError.code {
|
||||
case .notConnectedToInternet:
|
||||
case .notConnectedToInternet, .networkConnectionLost, .dataNotAllowed:
|
||||
return (String(localized: "网络连接已断开"), true)
|
||||
case .timedOut:
|
||||
return (String(localized: "连接超时"), true)
|
||||
case .cancelled:
|
||||
return (String(localized: "下载已取消"), false)
|
||||
case .cannotConnectToHost, .dnsLookupFailed:
|
||||
return (String(localized: "无法连接到服务器"), true)
|
||||
default:
|
||||
return (urlError.localizedDescription, true)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class TaskPersistenceManager {
|
||||
: "Adobe Downloader \(sapCode)_\(version)-\(language)-\(platform)-task.json"
|
||||
}
|
||||
|
||||
func saveTask(_ task: NewDownloadTask) {
|
||||
func saveTask(_ task: NewDownloadTask) async {
|
||||
let fileName = getTaskFileName(
|
||||
sapCode: task.sapCode,
|
||||
version: task.version,
|
||||
@@ -34,13 +34,11 @@ class TaskPersistenceManager {
|
||||
|
||||
var resumeDataDict: [String: Data]? = nil
|
||||
|
||||
Task {
|
||||
if let currentPackage = task.currentPackage,
|
||||
let cancelTracker = self.cancelTracker,
|
||||
let resumeData = await cancelTracker.getResumeData(task.id) {
|
||||
resumeDataDict = [currentPackage.id.uuidString: resumeData]
|
||||
}
|
||||
}
|
||||
|
||||
let taskData = TaskData(
|
||||
sapCode: task.sapCode,
|
||||
@@ -151,13 +149,13 @@ class TaskPersistenceManager {
|
||||
|
||||
let initialStatus: DownloadStatus
|
||||
switch taskData.totalStatus {
|
||||
case .completed:
|
||||
initialStatus = taskData.totalStatus
|
||||
case .failed:
|
||||
initialStatus = taskData.totalStatus
|
||||
case .completed(let info):
|
||||
initialStatus = .completed(info)
|
||||
case .failed(let info):
|
||||
initialStatus = .failed(info)
|
||||
case .downloading:
|
||||
initialStatus = .paused(DownloadStatus.PauseInfo(
|
||||
reason: .other(String(localized: "程序意外退出")),
|
||||
reason: .other(String(localized: "程序退出")),
|
||||
timestamp: Date(),
|
||||
resumable: true
|
||||
))
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
},
|
||||
"(可能导致处理 Setup 组件失败)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -21,6 +22,7 @@
|
||||
}
|
||||
},
|
||||
"(将导致无法使用安装功能)" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -286,7 +288,6 @@
|
||||
|
||||
},
|
||||
"Debug 模式" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1384,7 +1385,6 @@
|
||||
}
|
||||
},
|
||||
"将执行的命令:" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1425,7 +1425,6 @@
|
||||
}
|
||||
},
|
||||
"展开全部" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1446,6 +1445,7 @@
|
||||
}
|
||||
},
|
||||
"已处理" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1456,6 +1456,7 @@
|
||||
}
|
||||
},
|
||||
"已备份" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1661,7 +1662,6 @@
|
||||
}
|
||||
},
|
||||
"折叠全部" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -1889,6 +1889,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"无法连接到服务器" : {
|
||||
|
||||
},
|
||||
"无法连接到服务器: %@" : {
|
||||
"comment" : "Server unreachable",
|
||||
@@ -2583,6 +2586,7 @@
|
||||
}
|
||||
},
|
||||
"程序意外退出" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@@ -2601,6 +2605,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"程序退出" : {
|
||||
|
||||
},
|
||||
"程序重启后自动暂停" : {
|
||||
"localizations" : {
|
||||
|
||||
Reference in New Issue
Block a user