fix(node): prevent iOS VoiceWake crash

This commit is contained in:
Peter Steinberger
2025-12-12 23:06:17 +00:00
parent 952d924581
commit e502ad13f9
7 changed files with 18 additions and 21 deletions

View File

@@ -82,7 +82,7 @@ actor BridgeClient {
var line = Data()
line.append(data)
line.append(0x0A)
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
try await withCheckedThrowingContinuation(isolation: nil) { (cont: CheckedContinuation<Void, Error>) in
connection.send(content: line, completion: .contentProcessed { err in
if let err { cont.resume(throwing: err) } else { cont.resume(returning: ()) }
})
@@ -104,7 +104,7 @@ actor BridgeClient {
}
private func receiveChunk(over connection: NWConnection) async throws -> Data {
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Data, Error>) in
try await withCheckedThrowingContinuation(isolation: nil) { (cont: CheckedContinuation<Data, Error>) in
connection.receive(minimumIncompleteLength: 1, maximumLength: 64 * 1024) { data, _, isComplete, error in
if let error {
cont.resume(throwing: error)

View File

@@ -19,8 +19,9 @@ final class BridgeDiscoveryModel: ObservableObject {
func start() {
if self.browser != nil { return }
let params = NWParameters.tcp
params.includePeerToPeer = true
let browser = NWBrowser(
for: .bonjour(type: ClawdisBonjour.bridgeServiceType, domain: nil),
for: .bonjour(type: ClawdisBonjour.bridgeServiceType, domain: ClawdisBonjour.bridgeServiceDomain),
using: params)
browser.stateUpdateHandler = { [weak self] state in

View File

@@ -111,7 +111,7 @@ actor BridgeSession {
var line = Data()
line.append(data)
line.append(0x0A)
try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
try await withCheckedThrowingContinuation(isolation: nil) { (cont: CheckedContinuation<Void, Error>) in
connection.send(content: line, completion: .contentProcessed { err in
if let err { cont.resume(throwing: err) } else { cont.resume(returning: ()) }
})
@@ -134,7 +134,7 @@ actor BridgeSession {
private func receiveChunk() async throws -> Data {
guard let connection = self.connection else { return Data() }
return try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Data, Error>) in
return try await withCheckedThrowingContinuation(isolation: nil) { (cont: CheckedContinuation<Data, Error>) in
connection.receive(minimumIncompleteLength: 1, maximumLength: 64 * 1024) { data, _, isComplete, error in
if let error {
cont.resume(throwing: error)

View File

@@ -57,7 +57,7 @@ final class ScreenController: ObservableObject {
if let maxWidth {
config.snapshotWidth = NSNumber(value: Double(maxWidth))
}
let image: UIImage = try await withCheckedThrowingContinuation { (cont: CheckedContinuation<UIImage, Error>) in
let image: UIImage = try await withCheckedThrowingContinuation { cont in
self.webView.takeSnapshot(with: config) { image, error in
if let error {
cont.resume(throwing: error)

View File

@@ -96,9 +96,8 @@ final class VoiceWakeManager: NSObject, ObservableObject {
inputNode.removeTap(onBus: 0)
let recordingFormat = inputNode.outputFormat(forBus: 0)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [weak self] buffer, _ in
guard let self else { return }
self.recognitionRequest?.append(buffer)
inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordingFormat) { [request] buffer, _ in
request.append(buffer)
}
self.audioEngine.prepare()
@@ -169,22 +168,18 @@ final class VoiceWakeManager: NSObject, ObservableObject {
try session.setActive(true, options: [])
}
private static func requestMicrophonePermission() async -> Bool {
await withCheckedContinuation { cont in
private nonisolated static func requestMicrophonePermission() async -> Bool {
await withCheckedContinuation(isolation: nil) { cont in
AVAudioApplication.requestRecordPermission { ok in
Task { @MainActor in
cont.resume(returning: ok)
}
cont.resume(returning: ok)
}
}
}
private static func requestSpeechPermission() async -> Bool {
await withCheckedContinuation { cont in
private nonisolated static func requestSpeechPermission() async -> Bool {
await withCheckedContinuation(isolation: nil) { cont in
SFSpeechRecognizer.requestAuthorization { status in
Task { @MainActor in
cont.resume(returning: status == .authorized)
}
cont.resume(returning: status == .authorized)
}
}
}

View File

@@ -210,7 +210,7 @@ actor BridgeConnectionHandler {
var line = Data()
line.append(data)
line.append(0x0A) // \n
let _: Void = try await withCheckedThrowingContinuation { (cont: CheckedContinuation<Void, Error>) in
let _: Void = try await withCheckedThrowingContinuation { cont in
self.connection.send(content: line, completion: .contentProcessed { err in
if let err {
cont.resume(throwing: err)

View File

@@ -24,13 +24,14 @@ actor BridgeServer {
self.store = store
let params = NWParameters.tcp
params.includePeerToPeer = true
let listener = try NWListener(using: params, on: .any)
let name = Host.current().localizedName ?? ProcessInfo.processInfo.hostName
listener.service = NWListener.Service(
name: "\(name) (Clawdis)",
type: ClawdisBonjour.bridgeServiceType,
domain: nil,
domain: ClawdisBonjour.bridgeServiceDomain,
txtRecord: nil)
listener.newConnectionHandler = { [weak self] connection in