mirror of
https://github.com/nimbold/Firelink.git
synced 2026-07-26 12:08:27 +00:00
fix: resolve critical download bugs and configuration issues
- proxy: Prevent SOCKS5 proxy type from being silently converted to HTTP. - core: Remove DispatchGroup from MediaDownloadEngine to fix a hang caused by unclosed output pipes when child processes inherit file descriptors. - settings: Fix keychain primer logic to prevent wiping extension credentials on debug builds. - ui: Resolve a batch rename collision in AddDownloadsView by properly checking new filenames against the current batch sequence.
This commit is contained in:
@@ -701,7 +701,7 @@ struct AddDownloadsView: View {
|
||||
var count = 1
|
||||
let base = URL(fileURLWithPath: newName).deletingPathExtension().lastPathComponent
|
||||
let ext = URL(fileURLWithPath: newName).pathExtension
|
||||
while controller.downloads.contains(where: { $0.destinationDirectory == destURL && $0.fileName == newName }) || FileManager.default.fileExists(atPath: destURL.appendingPathComponent(newName).path) {
|
||||
while controller.downloads.contains(where: { $0.destinationDirectory == destURL && $0.fileName == newName }) || FileManager.default.fileExists(atPath: destURL.appendingPathComponent(newName).path) || finalDownloads.prefix(upTo: index).contains(where: { (overrideDirectory ?? $0.defaultDirectory) == destURL && $0.fileName == newName }) {
|
||||
newName = "\(base) (\(count))" + (ext.isEmpty ? "" : ".\(ext)")
|
||||
count += 1
|
||||
}
|
||||
|
||||
@@ -93,9 +93,6 @@ struct ProxySettings: Codable, Equatable, Sendable {
|
||||
var copy = self
|
||||
copy.host = copy.host.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
copy.port = min(max(copy.port, 1), 65_535)
|
||||
if copy.type != .http {
|
||||
copy.type = .http
|
||||
}
|
||||
return copy
|
||||
}
|
||||
|
||||
@@ -301,16 +298,13 @@ final class AppSettings: ObservableObject {
|
||||
}
|
||||
|
||||
if granted {
|
||||
if let token = KeychainCredentialStore.extensionToken() {
|
||||
extensionPairingToken = token
|
||||
} else {
|
||||
extensionPairingToken = Self.generateSecureToken()
|
||||
}
|
||||
if needsPrimer {
|
||||
showKeychainPrimer = true
|
||||
extensionPairingToken = ""
|
||||
} else {
|
||||
if let token = KeychainCredentialStore.extensionToken() {
|
||||
extensionPairingToken = token
|
||||
} else {
|
||||
extensionPairingToken = Self.generateSecureToken()
|
||||
// The didSet of extensionPairingToken will handle setting it in the keychain since isKeychainAccessGranted is true.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
extensionPairingToken = ""
|
||||
|
||||
@@ -100,16 +100,10 @@ final class MediaDownloadEngine: @unchecked Sendable {
|
||||
messageUpdate: messageUpdate
|
||||
)
|
||||
|
||||
let group = DispatchGroup()
|
||||
group.enter() // output
|
||||
group.enter() // error
|
||||
group.enter() // process
|
||||
|
||||
outputPipe.fileHandleForReading.readabilityHandler = { handle in
|
||||
let data = handle.availableData
|
||||
if data.isEmpty {
|
||||
handle.readabilityHandler = nil
|
||||
group.leave()
|
||||
} else if let text = String(data: data, encoding: .utf8) {
|
||||
outputHandler.handle(text)
|
||||
}
|
||||
@@ -119,7 +113,6 @@ final class MediaDownloadEngine: @unchecked Sendable {
|
||||
let data = handle.availableData
|
||||
if data.isEmpty {
|
||||
handle.readabilityHandler = nil
|
||||
group.leave()
|
||||
} else {
|
||||
errorBuffer.append(data)
|
||||
if let text = String(data: data, encoding: .utf8) {
|
||||
@@ -128,16 +121,15 @@ final class MediaDownloadEngine: @unchecked Sendable {
|
||||
}
|
||||
}
|
||||
|
||||
process.terminationHandler = { _ in
|
||||
group.leave()
|
||||
}
|
||||
|
||||
group.notify(queue: .global()) {
|
||||
if process.terminationStatus == 0 {
|
||||
process.terminationHandler = { finishedProcess in
|
||||
outputPipe.fileHandleForReading.readabilityHandler = nil
|
||||
errorPipe.fileHandleForReading.readabilityHandler = nil
|
||||
|
||||
if finishedProcess.terminationStatus == 0 {
|
||||
completionGate.complete(.success(Self.resolvedOutputURL(for: item, tracker: outputPathTracker)))
|
||||
} else {
|
||||
let errorString = String(data: errorBuffer.data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "Unknown Error"
|
||||
completionGate.complete(.failure(EngineError.launchFailed(Self.cleanErrorMessage(errorString, status: process.terminationStatus))))
|
||||
completionGate.complete(.failure(EngineError.launchFailed(Self.cleanErrorMessage(errorString, status: finishedProcess.terminationStatus))))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user