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
+99 -3
View File
@@ -26,6 +26,79 @@ public extension Profile {
}
return content
}
func encodedContentDataAsync() async throws -> Data {
let name = name
let type = type
let remoteURL = remoteURL
let autoUpdate = autoUpdate
let autoUpdateInterval = autoUpdateInterval
let lastUpdated = lastUpdated
let config = try await readAsync()
return try await BlockingIO.run {
let content = LibboxProfileContent()
content.name = name
switch type {
case .local, .icloud:
content.type = LibboxProfileTypeLocal
case .remote:
content.type = LibboxProfileTypeRemote
}
content.config = config
if type == .remote {
content.remotePath = remoteURL!
content.autoUpdate = autoUpdate
content.autoUpdateInterval = autoUpdateInterval
if let lastUpdated {
content.lastUpdated = Int64(lastUpdated.timeIntervalSince1970 * 1000)
}
}
guard let encoded = content.encode() else {
throw NSError(domain: "Profile", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to encode profile"])
}
return encoded
}
}
func generateShareFileAsync() async throws -> URL {
let name = name
let type = type
let remoteURL = remoteURL
let autoUpdate = autoUpdate
let autoUpdateInterval = autoUpdateInterval
let lastUpdated = lastUpdated
let config = try await readAsync()
return try await BlockingIO.run {
let content = LibboxProfileContent()
content.name = name
switch type {
case .local, .icloud:
content.type = LibboxProfileTypeLocal
case .remote:
content.type = LibboxProfileTypeRemote
}
content.config = config
if type == .remote {
content.remotePath = remoteURL!
content.autoUpdate = autoUpdate
content.autoUpdateInterval = autoUpdateInterval
if let lastUpdated {
content.lastUpdated = Int64(lastUpdated.timeIntervalSince1970 * 1000)
}
}
return try content.generateShareFile()
}
}
func generateJSONShareFileAsync(name: String) async throws -> URL {
let filename = name
let config = try await readAsync()
return try await BlockingIO.run {
try config.generateShareFile(name: filename)
}
}
}
public func dateFromTimestamp(_ timestamp: Int64) -> Date {
@@ -57,17 +130,34 @@ public extension LibboxProfileContent {
@discardableResult
func importProfile() async throws -> Profile {
let name = name
let type = type
let config = config
let remotePath = remotePath
let autoUpdate = autoUpdate
let autoUpdateInterval = autoUpdateInterval
let lastUpdated = lastUpdated
let nextProfileID = try await ProfileManager.nextID()
let profileConfigDirectory = FilePath.sharedDirectory.appendingPathComponent("configs", isDirectory: true)
try FileManager.default.createDirectory(at: profileConfigDirectory, withIntermediateDirectories: true)
let profileConfig = profileConfigDirectory.appendingPathComponent("config_\(nextProfileID).json")
try config.write(to: profileConfig, atomically: true, encoding: .utf8)
var lastUpdatedAt: Date?
if lastUpdated > 0 {
lastUpdatedAt = dateFromTimestamp(lastUpdated)
}
try await BlockingIO.run {
try FileManager.default.createDirectory(at: profileConfigDirectory, withIntermediateDirectories: true)
try config.write(to: profileConfig, atomically: true, encoding: .utf8)
}
let uniqueProfileName = try await ProfileManager.uniqueName(name)
let profile = Profile(name: uniqueProfileName, type: ProfileType(rawValue: Int(type))!, path: profileConfig.relativePath, remoteURL: remotePath, autoUpdate: autoUpdate, autoUpdateInterval: autoUpdateInterval, lastUpdated: lastUpdatedAt)
let profile = Profile(
name: uniqueProfileName,
type: ProfileType(rawValue: Int(type))!,
path: profileConfig.relativePath,
remoteURL: remotePath,
autoUpdate: autoUpdate,
autoUpdateInterval: autoUpdateInterval,
lastUpdated: lastUpdatedAt
)
try await ProfileManager.create(profile)
await SharedPreferences.selectedProfileID.set(profile.mustID)
return profile
@@ -190,6 +280,12 @@ public extension UTType {
public let filename: String
public let contentType: UTType
public init(data: Data, filename: String, contentType: UTType) {
self.data = data
self.filename = filename
self.contentType = contentType
}
public init(profile: ProfileExportDocument) {
data = profile.data
filename = profile.filename