From 82b5c886cb21183cc0a93f95300b5b0bccf1b0a6 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Fri, 20 Jun 2025 14:55:55 -0700 Subject: [PATCH] More granular websocket error handling --- QueueCube/Backend/API.swift | 22 ++++++++++++++++++---- QueueCube/Views/ContentView.swift | 1 + QueueCube/Views/MainView.swift | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/QueueCube/Backend/API.swift b/QueueCube/Backend/API.swift index be6a54a..a7e717a 100644 --- a/QueueCube/Backend/API.swift +++ b/QueueCube/Backend/API.swift @@ -162,8 +162,7 @@ struct API websocketTask.sendPing { error in if let error { - print("Ping error: \(error). Trying to reconnect.") - continuation.yield(.error(.websocketError(error))) + notifyError(error, continuation: continuation) websocketTask = spawnWebsocketTask(with: continuation) } else { continuation.yield(.event(Event(type: .receivedWebsocketPong))) @@ -204,14 +203,28 @@ struct API } } } catch { - print("Websocket Error: \(error)") - continuation.yield(.error(API.Error.websocketError(error))) + notifyError(error, continuation: continuation) } } return websocketTask } + private func notifyError(_ error: any Swift.Error, continuation: AsyncStream.Continuation) { + print("Websocket Error: \(error)") + var shouldNotifyObservers = true + let nsError = error as NSError + if nsError.code == 53 { + // This is a "connection abort", caused by backgrounding. + // Don't notify UI, just silently reconnect. + shouldNotifyObservers = false + } + + if shouldNotifyObservers { + continuation.yield(.error(.websocketError(error))) + } + } + private func request() -> RequestBuilder { RequestBuilder(url: baseURL) } @@ -247,6 +260,7 @@ struct API // Private UI events case receivedWebsocketPong + case websocketReconnected } } } diff --git a/QueueCube/Views/ContentView.swift b/QueueCube/Views/ContentView.swift index 042ebf6..30eb7ab 100644 --- a/QueueCube/Views/ContentView.swift +++ b/QueueCube/Views/ContentView.swift @@ -122,6 +122,7 @@ extension ContentView case .favoritesUpdate: await refresh(.favorites) + case .websocketReconnected: fallthrough case .metadataUpdate: fallthrough case .mpdUpdate: await refresh([.playlist, .nowPlaying, .favorites]) diff --git a/QueueCube/Views/MainView.swift b/QueueCube/Views/MainView.swift index 116a3fe..5d8a5f1 100644 --- a/QueueCube/Views/MainView.swift +++ b/QueueCube/Views/MainView.swift @@ -346,7 +346,7 @@ struct ErrorDisplayModifier: ViewModifier Rectangle() .fill(.background) - contentPlaceholderView(title: .connectionError, systemImage: "exclamationmark.triangle.fill") + contentPlaceholderView(title: "\(String(describing: error))", systemImage: "exclamationmark.triangle.fill") .tint(.label) } }