fix: add ping timers to prevent websocket disconnect (#35)

This commit is contained in:
Owen Gretzinger
2025-07-21 16:16:30 -04:00
committed by GitHub
parent c03fa953c9
commit 0e4ac1705b
2 changed files with 37 additions and 0 deletions
+27
View File
@@ -29,6 +29,9 @@ class AudioManager: NSObject, ObservableObject {
// Add current interim transcripts per source
private var currentInterim: [AudioSource: String] = [.mic: "", .system: ""]
// Add ping timers to keep WebSocket connections alive
private var pingTimers: [AudioSource: Timer] = [:]
override init() {
super.init()
@@ -87,6 +90,10 @@ class AudioManager: NSObject, ObservableObject {
systemSocketTask?.cancel(with: .normalClosure, reason: nil)
systemSocketTask = nil
// Invalidate ping timers
pingTimers.values.forEach { $0.invalidate() }
pingTimers.removeAll()
// Reset state
// (isRecording already cleared in stopRecording)
@@ -268,6 +275,10 @@ class AudioManager: NSObject, ObservableObject {
systemSocketTask?.cancel(with: .normalClosure, reason: nil)
systemSocketTask = nil
// Invalidate ping timers
pingTimers.values.forEach { $0.invalidate() }
pingTimers.removeAll()
print("Recording stopped")
}
@@ -321,6 +332,22 @@ class AudioManager: NSObject, ObservableObject {
// Add connection monitoring
task.resume()
// Set up ping timer to keep connection alive
pingTimers[source]?.invalidate()
let pingTimer = Timer.scheduledTimer(withTimeInterval: 30.0, repeats: true) { [weak self] _ in
guard let self = self else { return }
let task = source == .mic ? self.micSocketTask : self.systemSocketTask
guard let socket = task, socket.state == .running else { return }
socket.sendPing { error in
if let error = error {
print("❌ Ping failed for \(source): \(error)")
} else {
print("🏓 Ping sent for \(source)")
}
}
}
pingTimers[source] = pingTimer
let thisSession = sessionID
// Monitor connection state (ignore if session changed or recording stopped)
DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self, weak task] in
+10
View File
@@ -98,6 +98,16 @@ class ErrorHandler {
}
}
// Handle POSIX socket errors (e.g., "Socket is not connected")
if let nsError = error as NSError?, nsError.domain == NSPOSIXErrorDomain {
switch nsError.code {
case 57: // ENOTCONN - Socket is not connected
return true
default:
return false
}
}
// WebSocket close codes
if let closeCode = (error as NSError?)?.userInfo["closeCode"] as? Int {
return closeCode < 4000 // Only retry for non-API errors