fix(macos): enforce node bridge timeouts

This commit is contained in:
Peter Steinberger
2025-12-27 00:02:41 +01:00
parent d0293649cd
commit 4daf75a469
3 changed files with 33 additions and 27 deletions

View File

@@ -177,18 +177,20 @@ actor MacNodeBridgePairingClient {
purpose: String, purpose: String,
operation: @escaping @Sendable () async throws -> T) async throws -> T operation: @escaping @Sendable () async throws -> T) async throws -> T
{ {
let task = Task { try await operation() } try await withThrowingTaskGroup(of: T.self) { group in
let timeout = Task { group.addTask { try await operation() }
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) group.addTask {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
throw NSError(domain: "Bridge", code: 0, userInfo: [
NSLocalizedDescriptionKey: "\(purpose) timed out",
])
}
let result = try await group.next()
group.cancelAll()
if let result { return result }
throw NSError(domain: "Bridge", code: 0, userInfo: [ throw NSError(domain: "Bridge", code: 0, userInfo: [
NSLocalizedDescriptionKey: "\(purpose) timed out", NSLocalizedDescriptionKey: "\(purpose) timed out",
]) ])
} }
defer { timeout.cancel() }
return try await withTaskCancellationHandler(operation: {
try await task.value
}, onCancel: {
timeout.cancel()
})
} }
} }

View File

@@ -315,16 +315,18 @@ actor MacNodeBridgeSession {
seconds: Double, seconds: Double,
operation: @escaping @Sendable () async throws -> T) async throws -> T operation: @escaping @Sendable () async throws -> T) async throws -> T
{ {
let task = Task { try await operation() } try await withThrowingTaskGroup(of: T.self) { group in
let timeout = Task { group.addTask {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) try await operation()
}
group.addTask {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
throw TimeoutError(message: "operation timed out")
}
let result = try await group.next()
group.cancelAll()
if let result { return result }
throw TimeoutError(message: "operation timed out") throw TimeoutError(message: "operation timed out")
} }
defer { timeout.cancel() }
return try await withTaskCancellationHandler(operation: {
try await task.value
}, onCancel: {
timeout.cancel()
})
} }
} }

View File

@@ -253,19 +253,21 @@ final class MacNodeModeCoordinator {
seconds: Double, seconds: Double,
operation: @escaping @Sendable () async throws -> T) async throws -> T operation: @escaping @Sendable () async throws -> T) async throws -> T
{ {
let task = Task { try await operation() } try await withThrowingTaskGroup(of: T.self) { group in
let timeout = Task { group.addTask { try await operation() }
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000)) group.addTask {
try await Task.sleep(nanoseconds: UInt64(seconds * 1_000_000_000))
throw NSError(domain: "Bridge", code: 22, userInfo: [
NSLocalizedDescriptionKey: "operation timed out",
])
}
let result = try await group.next()
group.cancelAll()
if let result { return result }
throw NSError(domain: "Bridge", code: 22, userInfo: [ throw NSError(domain: "Bridge", code: 22, userInfo: [
NSLocalizedDescriptionKey: "operation timed out", NSLocalizedDescriptionKey: "operation timed out",
]) ])
} }
defer { timeout.cancel() }
return try await withTaskCancellationHandler(operation: {
try await task.value
}, onCancel: {
timeout.cancel()
})
} }
private func resolveBridgeEndpoint(timeoutSeconds: Double) async -> NWEndpoint? { private func resolveBridgeEndpoint(timeoutSeconds: Double) async -> NWEndpoint? {