Hello,
I'm working on adding a URLSessionWebSocketTask
based web socket connection to have live data in a single view. When the user navigates to it, the connection is established and live data is received. The task is being cancelled when this view disappears:
task.cancel(with: .goingAway, reason: nil)
After calling resume()
on the task, I ping the server to see if the connection works before sending any messages. I opt to use async API instead of closure based wherever possible. Foundation provides both APIs for most URLSessionWebSocketTask
's methods, but for some reason it misses async version of sendPing.
Such method, however, is available in swift-corelibs-foundation
project here. So I've added a similar code locally:
extension URLSessionWebSocketTask {
func sendPing() async throws {
let _: Void = try await withCheckedThrowingContinuation { continuation in
sendPing { error in
if let error {
continuation.resume(throwing: error)
} else {
continuation.resume()
}
}
}
}
}
The issue that I have is that if the user navigates from the view after sendPing
was called, but before pong is received, pongReceiveHandler
is called twice with error:
Error Domain=NSPOSIXErrorDomain Code=53 "Software caused connection abort" UserInfo={NSDescription=Software caused connection abort}
This results in an exception:
Fatal error: SWIFT TASK CONTINUATION MISUSE: sendPing() tried to resume its continuation more than once, throwing Error Domain=NSPOSIXErrorDomain Code=53 "Software caused connection abort" UserInfo={NSDescription=Software caused connection abort}!
There are no issues when the task is cancelled after successful ping.
The documentation does not state that pongReceiveHandler
is always called only once, but by looking at the code in swift-corelibs-foundation
I think that it should be the case.
Am I misusing sendPing
, or is it a bug in the Foundation? Perhaps there is no func sendPing() async throws
for some reason?
I use Xcode 15.3 with Swift 5.10.
Great thanks for any help.
Best Regards, Michal Pastwa