Fix main-thread blocking I/O

This commit is contained in:
世界
2026-02-05 02:37:02 +08:00
parent 4ae421cd04
commit 2e682d746c
17 changed files with 643 additions and 237 deletions
+34 -22
View File
@@ -150,22 +150,24 @@ public struct CoreView: View {
#if os(macOS)
let helperUnavailable = Variant.useSystemExtension && HelperServiceManager.rootHelperStatus != .enabled
#endif
let dataSize: String?
#if os(macOS)
if Variant.useSystemExtension {
if helperUnavailable {
dataSize = nil
} else if let size = try? RootHelperClient.shared.getWorkingDirectorySize() {
dataSize = LibboxFormatBytes(size)
let workingDirectory = FilePath.workingDirectory
let dataSize: String? = await BlockingIO.run {
#if os(macOS)
if Variant.useSystemExtension {
if helperUnavailable {
return nil
}
guard let size = try? RootHelperClient.shared.getWorkingDirectorySize() else {
return nil
}
return LibboxFormatBytes(size)
} else {
dataSize = nil
return (try? workingDirectory.formattedSize()) ?? "Unknown"
}
} else {
dataSize = (try? FilePath.workingDirectory.formattedSize()) ?? "Unknown"
}
#else
dataSize = (try? FilePath.workingDirectory.formattedSize()) ?? "Unknown"
#endif
#else
return (try? workingDirectory.formattedSize()) ?? "Unknown"
#endif
}
await MainActor.run {
#if os(macOS)
self.helperUnavailable = helperUnavailable
@@ -208,14 +210,21 @@ public struct CoreView: View {
private func destroyWorkingDirectory() async {
do {
let workingDirectory = FilePath.workingDirectory
#if os(macOS)
if Variant.useSystemExtension {
try RootHelperClient.shared.cleanWorkingDirectory()
try await BlockingIO.run {
try RootHelperClient.shared.cleanWorkingDirectory()
}
} else {
try clearWorkingDirectoryContents()
try await BlockingIO.run {
try Self.clearWorkingDirectoryContents(at: workingDirectory)
}
}
#else
try clearWorkingDirectoryContents()
try await BlockingIO.run {
try Self.clearWorkingDirectoryContents(at: workingDirectory)
}
#if os(iOS)
if #available(iOS 16.0, *) {
await notifyFileProviderWorkingDirectoryChanged()
@@ -228,8 +237,7 @@ public struct CoreView: View {
}
}
private func clearWorkingDirectoryContents() throws {
let url = FilePath.workingDirectory
private nonisolated static func clearWorkingDirectoryContents(at url: URL) throws {
guard FileManager.default.fileExists(atPath: url.path) else {
return
}
@@ -301,11 +309,15 @@ public struct CoreView: View {
private extension URL {
func formattedSize() throws -> String? {
guard let urls = FileManager.default.enumerator(at: self, includingPropertiesForKeys: nil)?.allObjects as? [URL] else {
guard let enumerator = FileManager.default.enumerator(
at: self,
includingPropertiesForKeys: [.totalFileAllocatedSizeKey]
) else {
return nil
}
let size = try urls.lazy.reduce(0) {
try ($1.resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize ?? 0) + $0
var size = 0
while let url = enumerator.nextObject() as? URL {
size += try url.resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize ?? 0
}
let formatter = ByteCountFormatter()
formatter.countStyle = .file
@@ -38,7 +38,7 @@ public struct ServiceLogView: View {
ShareButtonCompat($viewModel.alert) {
Label("Export", systemImage: "square.and.arrow.up.fill")
} itemURL: {
try viewModel.generateShareFile()
try await viewModel.generateShareFileAsync()
}
#endif
Button(role: .destructive) {
@@ -16,14 +16,13 @@ final class ServiceLogViewModel: BaseViewModel {
}
nonisolated func loadContent() async {
var content = ""
do {
content = try String(contentsOf: FilePath.cacheDirectory.appendingPathComponent("stderr.log"))
} catch {}
if content.isEmpty {
do {
content = try String(contentsOf: FilePath.cacheDirectory.appendingPathComponent("stderr.log.old"))
} catch {}
let primaryLogURL = FilePath.cacheDirectory.appendingPathComponent("stderr.log")
let secondaryLogURL = FilePath.cacheDirectory.appendingPathComponent("stderr.log.old")
var content = await BlockingIO.run {
if let primaryContent = try? String(contentsOf: primaryLogURL), !primaryContent.isEmpty {
return primaryContent
}
return (try? String(contentsOf: secondaryLogURL)) ?? ""
}
#if DEBUG
if content.isEmpty {
@@ -53,8 +52,12 @@ final class ServiceLogViewModel: BaseViewModel {
}
nonisolated func deleteContent(dismiss: DismissAction) async {
try? FileManager.default.removeItem(at: FilePath.cacheDirectory.appendingPathComponent("stderr.log"))
try? FileManager.default.removeItem(at: FilePath.cacheDirectory.appendingPathComponent("stderr.log.old"))
let primaryLogURL = FilePath.cacheDirectory.appendingPathComponent("stderr.log")
let secondaryLogURL = FilePath.cacheDirectory.appendingPathComponent("stderr.log.old")
await BlockingIO.run {
try? FileManager.default.removeItem(at: primaryLogURL)
try? FileManager.default.removeItem(at: secondaryLogURL)
}
await MainActor.run {
dismiss()
isLoading = true
@@ -64,4 +67,11 @@ final class ServiceLogViewModel: BaseViewModel {
func generateShareFile() throws -> URL {
try content.generateShareFile(name: "service.log")
}
func generateShareFileAsync() async throws -> URL {
let content = content
return try await BlockingIO.run {
try content.generateShareFile(name: "service.log")
}
}
}