mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-08 21:09:23 +08:00
iOS: streamline notify timeouts
This commit is contained in:
committed by
Mariano Belinky
parent
761188cd1d
commit
f72ac60b01
@@ -2,7 +2,6 @@ import AVFoundation
|
||||
import Contacts
|
||||
import CoreLocation
|
||||
import CoreMotion
|
||||
import Darwin
|
||||
import EventKit
|
||||
import Foundation
|
||||
import OpenClawKit
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import OpenClawKit
|
||||
import Network
|
||||
import Observation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
|
||||
// Wrap errors without pulling non-Sendable types into async notification paths.
|
||||
private struct NotificationCallError: Error, Sendable {
|
||||
let message: String
|
||||
}
|
||||
|
||||
// Ensures notification requests return promptly even if the system prompt blocks.
|
||||
private final class NotificationInvokeLatch<T: Sendable>: @unchecked Sendable {
|
||||
private let lock = NSLock()
|
||||
private var continuation: CheckedContinuation<Result<T, NotificationCallError>, Never>?
|
||||
@@ -1011,7 +1012,12 @@ final class NodeAppModel {
|
||||
let latch = NotificationInvokeLatch<T>()
|
||||
var opTask: Task<Void, Never>?
|
||||
var timeoutTask: Task<Void, Never>?
|
||||
let result = await withCheckedContinuation { (cont: CheckedContinuation<Result<T, NotificationCallError>, Never>) in
|
||||
defer {
|
||||
opTask?.cancel()
|
||||
timeoutTask?.cancel()
|
||||
}
|
||||
let clamped = max(0.0, timeoutSeconds)
|
||||
return await withCheckedContinuation { (cont: CheckedContinuation<Result<T, NotificationCallError>, Never>) in
|
||||
latch.setContinuation(cont)
|
||||
opTask = Task { @MainActor in
|
||||
do {
|
||||
@@ -1022,16 +1028,12 @@ final class NodeAppModel {
|
||||
}
|
||||
}
|
||||
timeoutTask = Task.detached {
|
||||
let clamped = max(0.0, timeoutSeconds)
|
||||
if clamped > 0 {
|
||||
try? await Task.sleep(nanoseconds: UInt64(clamped * 1_000_000_000))
|
||||
}
|
||||
latch.resume(.failure(NotificationCallError(message: "notification request timed out")))
|
||||
}
|
||||
}
|
||||
opTask?.cancel()
|
||||
timeoutTask?.cancel()
|
||||
return result
|
||||
}
|
||||
|
||||
private func handleDeviceInvoke(_ req: BridgeInvokeRequest) async throws -> BridgeInvokeResponse {
|
||||
|
||||
@@ -43,6 +43,7 @@ public actor GatewayNodeSession {
|
||||
return await onInvoke(request)
|
||||
}
|
||||
|
||||
// Use an explicit latch so timeouts win even if onInvoke blocks (e.g., permission prompts).
|
||||
final class InvokeLatch: @unchecked Sendable {
|
||||
private let lock = NSLock()
|
||||
private var continuation: CheckedContinuation<BridgeInvokeResponse, Never>?
|
||||
@@ -72,6 +73,10 @@ public actor GatewayNodeSession {
|
||||
let latch = InvokeLatch()
|
||||
var onInvokeTask: Task<Void, Never>?
|
||||
var timeoutTask: Task<Void, Never>?
|
||||
defer {
|
||||
onInvokeTask?.cancel()
|
||||
timeoutTask?.cancel()
|
||||
}
|
||||
let response = await withCheckedContinuation { (cont: CheckedContinuation<BridgeInvokeResponse, Never>) in
|
||||
latch.setContinuation(cont)
|
||||
onInvokeTask = Task.detached {
|
||||
@@ -90,8 +95,6 @@ public actor GatewayNodeSession {
|
||||
))
|
||||
}
|
||||
}
|
||||
onInvokeTask?.cancel()
|
||||
timeoutTask?.cancel()
|
||||
timeoutLogger.info("node invoke race resolved id=\(request.id, privacy: .public) ok=\(response.ok, privacy: .public)")
|
||||
return response
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user