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">
|
shouldAutocreateTestPlan = "YES">
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
|
|||||||
@@ -4,22 +4,6 @@
|
|||||||
type = "1"
|
type = "1"
|
||||||
version = "2.0">
|
version = "2.0">
|
||||||
<Breakpoints>
|
<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
|
<BreakpointProxy
|
||||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||||
<BreakpointContent
|
<BreakpointContent
|
||||||
@@ -52,5 +36,19 @@
|
|||||||
landmarkType = "7">
|
landmarkType = "7">
|
||||||
</BreakpointContent>
|
</BreakpointContent>
|
||||||
</BreakpointProxy>
|
</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>
|
</Breakpoints>
|
||||||
</Bucket>
|
</Bucket>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
if event.modifierFlags.contains(.command) && event.characters?.lowercased() == "q" {
|
if event.modifierFlags.contains(.command) && event.characters?.lowercased() == "q" {
|
||||||
if let mainWindow = NSApp.mainWindow,
|
if let mainWindow = NSApp.mainWindow,
|
||||||
mainWindow.sheets.isEmpty && !mainWindow.isSheet {
|
mainWindow.sheets.isEmpty && !mainWindow.isSheet {
|
||||||
self?.handleQuitCommand()
|
_ = self?.applicationShouldTerminate(NSApp)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,19 +19,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@MainActor private func handleQuitCommand() {
|
func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply {
|
||||||
guard let manager = networkManager else {
|
guard let manager = networkManager else { return .terminateNow }
|
||||||
NSApplication.shared.terminate(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let hasActiveDownloads = manager.downloadTasks.contains { task in
|
let hasActiveDownloads = manager.downloadTasks.contains { task in
|
||||||
if case .downloading = task.totalStatus {
|
if case .downloading = task.totalStatus { return true }
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasActiveDownloads {
|
if hasActiveDownloads {
|
||||||
Task {
|
Task {
|
||||||
for task in manager.downloadTasks {
|
for task in manager.downloadTasks {
|
||||||
@@ -40,6 +35,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
taskId: task.id,
|
taskId: task.id,
|
||||||
reason: .other(String(localized: "程序即将退出"))
|
reason: .other(String(localized: "程序即将退出"))
|
||||||
)
|
)
|
||||||
|
await manager.saveTask(task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +64,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
} else {
|
} else {
|
||||||
NSApplication.shared.terminate(nil)
|
NSApplication.shared.terminate(nil)
|
||||||
}
|
}
|
||||||
|
return .terminateCancel
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
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)
|
downloadTasks.append(task)
|
||||||
updateDockBadge()
|
updateDockBadge()
|
||||||
saveTask(task)
|
await saveTask(task)
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try await downloadUtils.handleDownload(task: task, productInfo: productInfo, allowedPlatform: StorageData.shared.allowedPlatform, saps: saps)
|
try await downloadUtils.handleDownload(task: task, productInfo: productInfo, allowedPlatform: StorageData.shared.allowedPlatform, saps: saps)
|
||||||
} catch {
|
} catch {
|
||||||
|
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
||||||
|
message: error.localizedDescription,
|
||||||
|
error: error,
|
||||||
|
timestamp: Date(),
|
||||||
|
recoverable: true
|
||||||
|
)))
|
||||||
|
await saveTask(task)
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
|
||||||
message: error.localizedDescription,
|
|
||||||
error: error,
|
|
||||||
timestamp: Date(),
|
|
||||||
recoverable: true
|
|
||||||
)))
|
|
||||||
saveTask(task)
|
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
throw error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +135,7 @@ class NetworkManager: ObservableObject {
|
|||||||
timestamp: Date(),
|
timestamp: Date(),
|
||||||
recoverable: false
|
recoverable: false
|
||||||
)))
|
)))
|
||||||
saveTask(task)
|
await saveTask(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
if removeFiles {
|
if removeFiles {
|
||||||
@@ -352,19 +351,59 @@ class NetworkManager: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveTask(_ task: NewDownloadTask) {
|
func loadSavedTasks() {
|
||||||
TaskPersistenceManager.shared.saveTask(task)
|
Task {
|
||||||
|
let savedTasks = TaskPersistenceManager.shared.loadTasks()
|
||||||
|
await MainActor.run {
|
||||||
|
for task in savedTasks {
|
||||||
|
for product in task.productsToDownload {
|
||||||
|
product.updateCompletedPackages()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
downloadTasks.append(contentsOf: savedTasks)
|
||||||
|
updateDockBadge()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveTask(_ task: NewDownloadTask) async {
|
||||||
|
await TaskPersistenceManager.shared.saveTask(task)
|
||||||
objectWillChange.send()
|
objectWillChange.send()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadSavedTasks() {
|
func configureNetworkMonitor() {
|
||||||
let savedTasks = TaskPersistenceManager.shared.loadTasks()
|
monitor.pathUpdateHandler = { [weak self] path in
|
||||||
for task in savedTasks {
|
let task = { @MainActor @Sendable [weak self] in
|
||||||
for product in task.productsToDownload {
|
guard let self else { return }
|
||||||
product.updateCompletedPackages()
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
downloadTasks.append(contentsOf: savedTasks)
|
|
||||||
updateDockBadge()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ class DownloadUtils {
|
|||||||
|
|
||||||
guard timeDiff >= NetworkConstants.progressUpdateInterval else { return }
|
guard timeDiff >= NetworkConstants.progressUpdateInterval else { return }
|
||||||
|
|
||||||
progressHandler?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
|
Task {
|
||||||
|
progressHandler?(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)
|
||||||
|
}
|
||||||
|
|
||||||
lastUpdateTime = now
|
lastUpdateTime = now
|
||||||
lastBytes = totalBytesWritten
|
lastBytes = totalBytesWritten
|
||||||
@@ -133,29 +135,31 @@ class DownloadUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await MainActor.run {
|
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||||
if let task = networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
task.setStatus(.paused(DownloadStatus.PauseInfo(
|
||||||
task.setStatus(.paused(DownloadStatus.PauseInfo(
|
reason: reason,
|
||||||
reason: reason,
|
timestamp: Date(),
|
||||||
timestamp: Date(),
|
resumable: true
|
||||||
resumable: true
|
)))
|
||||||
)))
|
await networkManager?.saveTask(task)
|
||||||
networkManager?.saveTask(task)
|
await MainActor.run {
|
||||||
|
networkManager?.objectWillChange.send()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func resumeDownloadTask(taskId: UUID) async {
|
func resumeDownloadTask(taskId: UUID) async {
|
||||||
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||||
|
task.setStatus(.downloading(DownloadStatus.DownloadInfo(
|
||||||
|
fileName: task.currentPackage?.fullPackageName ?? "",
|
||||||
|
currentPackageIndex: 0,
|
||||||
|
totalPackages: task.productsToDownload.reduce(0) { $0 + $1.packages.count },
|
||||||
|
startTime: Date(),
|
||||||
|
estimatedTimeRemaining: nil
|
||||||
|
)))
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
task.setStatus(.downloading(DownloadStatus.DownloadInfo(
|
networkManager?.objectWillChange.send()
|
||||||
fileName: task.currentPackage?.fullPackageName ?? "",
|
|
||||||
currentPackageIndex: 0,
|
|
||||||
totalPackages: task.productsToDownload.reduce(0) { $0 + $1.packages.count },
|
|
||||||
startTime: Date(),
|
|
||||||
estimatedTimeRemaining: nil
|
|
||||||
)))
|
|
||||||
networkManager?.saveTask(task)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if task.sapCode == "APRO" {
|
if task.sapCode == "APRO" {
|
||||||
@@ -178,19 +182,20 @@ class DownloadUtils {
|
|||||||
func cancelDownloadTask(taskId: UUID, removeFiles: Bool = false) async {
|
func cancelDownloadTask(taskId: UUID, removeFiles: Bool = false) async {
|
||||||
await cancelTracker.cancel(taskId)
|
await cancelTracker.cancel(taskId)
|
||||||
|
|
||||||
await MainActor.run {
|
if let task = await networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
||||||
if let task = networkManager?.downloadTasks.first(where: { $0.id == taskId }) {
|
if removeFiles {
|
||||||
if removeFiles {
|
try? FileManager.default.removeItem(at: task.directory)
|
||||||
try? FileManager.default.removeItem(at: task.directory)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
|
||||||
message: String(localized: "下载已取消"),
|
|
||||||
error: NetworkError.downloadCancelled,
|
|
||||||
timestamp: Date(),
|
|
||||||
recoverable: false
|
|
||||||
)))
|
|
||||||
|
|
||||||
|
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
||||||
|
message: String(localized: "下载已取消"),
|
||||||
|
error: NetworkError.downloadCancelled,
|
||||||
|
timestamp: Date(),
|
||||||
|
recoverable: false
|
||||||
|
)))
|
||||||
|
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
|
await MainActor.run {
|
||||||
networkManager?.updateDockBadge()
|
networkManager?.updateDockBadge()
|
||||||
networkManager?.objectWillChange.send()
|
networkManager?.objectWillChange.send()
|
||||||
}
|
}
|
||||||
@@ -259,47 +264,50 @@ class DownloadUtils {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Task { @MainActor in
|
Task {
|
||||||
package.downloadedSize = package.downloadSize
|
await MainActor.run {
|
||||||
package.progress = 1.0
|
package.downloadedSize = package.downloadSize
|
||||||
package.status = .completed
|
package.progress = 1.0
|
||||||
package.downloaded = true
|
package.status = .completed
|
||||||
|
package.downloaded = true
|
||||||
|
|
||||||
var totalDownloaded: Int64 = 0
|
var totalDownloaded: Int64 = 0
|
||||||
var totalSize: Int64 = 0
|
var totalSize: Int64 = 0
|
||||||
|
|
||||||
for prod in task.productsToDownload {
|
for prod in task.productsToDownload {
|
||||||
for pkg in prod.packages {
|
for pkg in prod.packages {
|
||||||
totalSize += pkg.downloadSize
|
totalSize += pkg.downloadSize
|
||||||
if pkg.downloaded {
|
if pkg.downloaded {
|
||||||
totalDownloaded += pkg.downloadSize
|
totalDownloaded += pkg.downloadSize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
task.totalSize = totalSize
|
||||||
|
task.totalDownloadedSize = totalDownloaded
|
||||||
|
task.totalProgress = Double(totalDownloaded) / Double(totalSize)
|
||||||
|
task.totalSpeed = 0
|
||||||
|
|
||||||
|
let allCompleted = task.productsToDownload.allSatisfy {
|
||||||
|
product in product.packages.allSatisfy { $0.downloaded }
|
||||||
|
}
|
||||||
|
|
||||||
|
if allCompleted {
|
||||||
|
task.setStatus(.completed(DownloadStatus.CompletionInfo(
|
||||||
|
timestamp: Date(),
|
||||||
|
totalTime: Date().timeIntervalSince(task.createAt),
|
||||||
|
totalSize: totalSize
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
product.updateCompletedPackages()
|
||||||
}
|
}
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
task.totalSize = totalSize
|
await MainActor.run {
|
||||||
task.totalDownloadedSize = totalDownloaded
|
networkManager?.objectWillChange.send()
|
||||||
task.totalProgress = Double(totalDownloaded) / Double(totalSize)
|
|
||||||
task.totalSpeed = 0
|
|
||||||
|
|
||||||
let allCompleted = task.productsToDownload.allSatisfy {
|
|
||||||
product in product.packages.allSatisfy { $0.downloaded }
|
|
||||||
}
|
}
|
||||||
|
continuation.resume()
|
||||||
if allCompleted {
|
|
||||||
task.setStatus(.completed(DownloadStatus.CompletionInfo(
|
|
||||||
timestamp: Date(),
|
|
||||||
totalTime: Date().timeIntervalSince(task.createAt),
|
|
||||||
totalSize: totalSize
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
product.updateCompletedPackages()
|
|
||||||
networkManager?.saveTask(task)
|
|
||||||
networkManager?.objectWillChange.send()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continuation.resume()
|
|
||||||
},
|
},
|
||||||
progressHandler: { [weak networkManager] bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
|
progressHandler: { [weak networkManager] bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
@@ -444,8 +452,8 @@ class DownloadUtils {
|
|||||||
startTime: Date(),
|
startTime: Date(),
|
||||||
estimatedTimeRemaining: nil
|
estimatedTimeRemaining: nil
|
||||||
)))
|
)))
|
||||||
networkManager?.saveTask(task)
|
|
||||||
}
|
}
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
|
|
||||||
await progress.increment()
|
await progress.increment()
|
||||||
|
|
||||||
@@ -487,8 +495,8 @@ class DownloadUtils {
|
|||||||
totalTime: Date().timeIntervalSince(task.createAt),
|
totalTime: Date().timeIntervalSince(task.createAt),
|
||||||
totalSize: task.totalSize
|
totalSize: task.totalSize
|
||||||
)))
|
)))
|
||||||
networkManager?.saveTask(task)
|
|
||||||
}
|
}
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,6 +933,18 @@ class DownloadUtils {
|
|||||||
|
|
||||||
let (errorMessage, isRecoverable) = classifyError(error)
|
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 {
|
if isRecoverable && task.retryCount < NetworkConstants.maxRetryAttempts {
|
||||||
task.retryCount += 1
|
task.retryCount += 1
|
||||||
let nextRetryDate = Date().addingTimeInterval(TimeInterval(NetworkConstants.retryDelay / 1_000_000_000))
|
let nextRetryDate = Date().addingTimeInterval(TimeInterval(NetworkConstants.retryDelay / 1_000_000_000))
|
||||||
@@ -946,22 +966,22 @@ class DownloadUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
||||||
|
message: errorMessage,
|
||||||
|
error: error,
|
||||||
|
timestamp: Date(),
|
||||||
|
recoverable: isRecoverable
|
||||||
|
)))
|
||||||
|
|
||||||
|
if let currentPackage = task.currentPackage {
|
||||||
|
let destinationDir = task.directory
|
||||||
|
.appendingPathComponent("\(task.sapCode)")
|
||||||
|
let fileURL = destinationDir.appendingPathComponent(currentPackage.fullPackageName)
|
||||||
|
try? FileManager.default.removeItem(at: fileURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
await networkManager?.saveTask(task)
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
task.setStatus(.failed(DownloadStatus.FailureInfo(
|
|
||||||
message: errorMessage,
|
|
||||||
error: error,
|
|
||||||
timestamp: Date(),
|
|
||||||
recoverable: isRecoverable
|
|
||||||
)))
|
|
||||||
|
|
||||||
if let currentPackage = task.currentPackage {
|
|
||||||
let destinationDir = task.directory
|
|
||||||
.appendingPathComponent("\(task.sapCode)")
|
|
||||||
let fileURL = destinationDir.appendingPathComponent(currentPackage.fullPackageName)
|
|
||||||
try? FileManager.default.removeItem(at: fileURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
networkManager?.saveTask(task)
|
|
||||||
networkManager?.updateDockBadge()
|
networkManager?.updateDockBadge()
|
||||||
networkManager?.objectWillChange.send()
|
networkManager?.objectWillChange.send()
|
||||||
}
|
}
|
||||||
@@ -973,7 +993,7 @@ class DownloadUtils {
|
|||||||
case let networkError as NetworkError:
|
case let networkError as NetworkError:
|
||||||
switch networkError {
|
switch networkError {
|
||||||
case .noConnection:
|
case .noConnection:
|
||||||
return (String(localized: "网络连接已断开"), true)
|
return (String(localized: "网络连接已断开"), true)
|
||||||
case .timeout:
|
case .timeout:
|
||||||
return (String(localized: "下载超时"), true)
|
return (String(localized: "下载超时"), true)
|
||||||
case .serverUnreachable:
|
case .serverUnreachable:
|
||||||
@@ -987,12 +1007,14 @@ class DownloadUtils {
|
|||||||
}
|
}
|
||||||
case let urlError as URLError:
|
case let urlError as URLError:
|
||||||
switch urlError.code {
|
switch urlError.code {
|
||||||
case .notConnectedToInternet:
|
case .notConnectedToInternet, .networkConnectionLost, .dataNotAllowed:
|
||||||
return (String(localized: "网络连接已断开"), true)
|
return (String(localized: "网络连接已断开"), true)
|
||||||
case .timedOut:
|
case .timedOut:
|
||||||
return (String(localized: "连接超时"), true)
|
return (String(localized: "连接超时"), true)
|
||||||
case .cancelled:
|
case .cancelled:
|
||||||
return (String(localized: "下载已取消"), false)
|
return (String(localized: "下载已取消"), false)
|
||||||
|
case .cannotConnectToHost, .dnsLookupFailed:
|
||||||
|
return (String(localized: "无法连接到服务器"), true)
|
||||||
default:
|
default:
|
||||||
return (urlError.localizedDescription, true)
|
return (urlError.localizedDescription, true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class TaskPersistenceManager {
|
|||||||
: "Adobe Downloader \(sapCode)_\(version)-\(language)-\(platform)-task.json"
|
: "Adobe Downloader \(sapCode)_\(version)-\(language)-\(platform)-task.json"
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveTask(_ task: NewDownloadTask) {
|
func saveTask(_ task: NewDownloadTask) async {
|
||||||
let fileName = getTaskFileName(
|
let fileName = getTaskFileName(
|
||||||
sapCode: task.sapCode,
|
sapCode: task.sapCode,
|
||||||
version: task.version,
|
version: task.version,
|
||||||
@@ -34,12 +34,10 @@ class TaskPersistenceManager {
|
|||||||
|
|
||||||
var resumeDataDict: [String: Data]? = nil
|
var resumeDataDict: [String: Data]? = nil
|
||||||
|
|
||||||
Task {
|
if let currentPackage = task.currentPackage,
|
||||||
if let currentPackage = task.currentPackage,
|
let cancelTracker = self.cancelTracker,
|
||||||
let cancelTracker = self.cancelTracker,
|
let resumeData = await cancelTracker.getResumeData(task.id) {
|
||||||
let resumeData = await cancelTracker.getResumeData(task.id) {
|
resumeDataDict = [currentPackage.id.uuidString: resumeData]
|
||||||
resumeDataDict = [currentPackage.id.uuidString: resumeData]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let taskData = TaskData(
|
let taskData = TaskData(
|
||||||
@@ -151,13 +149,13 @@ class TaskPersistenceManager {
|
|||||||
|
|
||||||
let initialStatus: DownloadStatus
|
let initialStatus: DownloadStatus
|
||||||
switch taskData.totalStatus {
|
switch taskData.totalStatus {
|
||||||
case .completed:
|
case .completed(let info):
|
||||||
initialStatus = taskData.totalStatus
|
initialStatus = .completed(info)
|
||||||
case .failed:
|
case .failed(let info):
|
||||||
initialStatus = taskData.totalStatus
|
initialStatus = .failed(info)
|
||||||
case .downloading:
|
case .downloading:
|
||||||
initialStatus = .paused(DownloadStatus.PauseInfo(
|
initialStatus = .paused(DownloadStatus.PauseInfo(
|
||||||
reason: .other(String(localized: "程序意外退出")),
|
reason: .other(String(localized: "程序退出")),
|
||||||
timestamp: Date(),
|
timestamp: Date(),
|
||||||
resumable: true
|
resumable: true
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"(可能导致处理 Setup 组件失败)" : {
|
"(可能导致处理 Setup 组件失败)" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"(将导致无法使用安装功能)" : {
|
"(将导致无法使用安装功能)" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -286,7 +288,6 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"Debug 模式" : {
|
"Debug 模式" : {
|
||||||
"extractionState" : "stale",
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1384,7 +1385,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"将执行的命令:" : {
|
"将执行的命令:" : {
|
||||||
"extractionState" : "stale",
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1425,7 +1425,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"展开全部" : {
|
"展开全部" : {
|
||||||
"extractionState" : "stale",
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1446,6 +1445,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"已处理" : {
|
"已处理" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1456,6 +1456,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"已备份" : {
|
"已备份" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1661,7 +1662,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"折叠全部" : {
|
"折叠全部" : {
|
||||||
"extractionState" : "stale",
|
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -1889,6 +1889,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"无法连接到服务器" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"无法连接到服务器: %@" : {
|
"无法连接到服务器: %@" : {
|
||||||
"comment" : "Server unreachable",
|
"comment" : "Server unreachable",
|
||||||
@@ -2583,6 +2586,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"程序意外退出" : {
|
"程序意外退出" : {
|
||||||
|
"extractionState" : "stale",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@@ -2601,6 +2605,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"程序退出" : {
|
||||||
|
|
||||||
},
|
},
|
||||||
"程序重启后自动暂停" : {
|
"程序重启后自动暂停" : {
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
|
|||||||
Reference in New Issue
Block a user