refactor: CommandClient & Connections

This commit is contained in:
世界
2026-01-16 20:08:33 +08:00
parent c479921a4f
commit 12c8bff2d4
6 changed files with 74 additions and 37 deletions
+42 -16
View File
@@ -15,43 +15,64 @@
let socketPath: String
var commandServer: LibboxCommandServer?
private enum ServiceReadyState {
case pending
case ready
case failed(Error)
}
private let serviceReadyLock = NSLock()
private var _serviceReady = false
private var serviceReadyContinuations: [CheckedContinuation<Void, Never>] = []
private var serviceReadyState = ServiceReadyState.pending
private var serviceReadyContinuations: [CheckedContinuation<Void, Error>] = []
private static let defaultNotReadyError = NSError(domain: "CommandXPC", code: -1, userInfo: [
NSLocalizedDescriptionKey: "Command server not ready",
])
init(socketPath: String) {
self.socketPath = socketPath
}
func waitForServiceReady() async {
func waitForServiceReady() async throws {
serviceReadyLock.lock()
if _serviceReady {
switch serviceReadyState {
case .ready:
serviceReadyLock.unlock()
return
}
await withCheckedContinuation { continuation in
serviceReadyContinuations.append(continuation)
case let .failed(error):
serviceReadyLock.unlock()
throw error
case .pending:
return try await withCheckedThrowingContinuation { continuation in
serviceReadyContinuations.append(continuation)
serviceReadyLock.unlock()
}
}
}
func markServiceReady() {
resolveServiceReady(.success(()))
}
func markServiceNotReady(_ error: Error? = nil) {
resolveServiceReady(.failure(error ?? Self.defaultNotReadyError))
}
private func resolveServiceReady(_ result: Result<Void, Error>) {
serviceReadyLock.lock()
_serviceReady = true
switch result {
case .success:
serviceReadyState = .ready
case let .failure(error):
serviceReadyState = .failed(error)
}
let continuations = serviceReadyContinuations
serviceReadyContinuations.removeAll()
serviceReadyLock.unlock()
for continuation in continuations {
continuation.resume()
continuation.resume(with: result)
}
}
func markServiceNotReady() {
serviceReadyLock.lock()
_serviceReady = false
serviceReadyLock.unlock()
}
func listener(_: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
let bundleID = AppConfiguration.packageName + ".standalone"
let requirement = "identifier \"\(bundleID)\" and anchor apple generic and certificate leaf[subject.OU] = \"\(AppConfiguration.teamID)\""
@@ -98,7 +119,12 @@
func extensionRequirements(reply: @escaping (Bool, Bool, NSError?) -> Void) {
Task {
await service.waitForServiceReady()
do {
try await service.waitForServiceReady()
} catch {
reply(false, false, error as NSError)
return
}
guard let commandServer = service.commandServer else {
reply(false, false, NSError(domain: "CommandXPC", code: -1, userInfo: [
NSLocalizedDescriptionKey: "Command server not available",