1313// limitations under the License.
1414
1515import Foundation
16+ private import FirebaseCoreInternal
1617
1718final class AsyncWebSocket : NSObject , @unchecked Sendable , URLSessionWebSocketDelegate {
1819 private let webSocketTask : URLSessionWebSocketTask
1920 private let stream : AsyncThrowingStream < URLSessionWebSocketTask . Message , Error >
2021 private let continuation : AsyncThrowingStream < URLSessionWebSocketTask . Message , Error > . Continuation
2122 private var continuationFinished = false
2223 private let continuationLock = NSLock ( )
23-
24- private var _closeError : WebSocketClosedError ? = nil
25- private let closeErrorLock = NSLock ( )
26- private( set) var closeError : WebSocketClosedError ? {
27- get { closeErrorLock. withLock { _closeError } }
28- set { closeErrorLock. withLock { _closeError = newValue } }
29- }
24+ private var closeError : UnfairLock < WebSocketClosedError ? >
3025
3126 init ( urlSession: URLSession = GenAIURLSession . default, urlRequest: URLRequest ) {
3227 webSocketTask = urlSession. webSocketTask ( with: urlRequest)
3328 ( stream, continuation) = AsyncThrowingStream < URLSessionWebSocketTask . Message , Error >
3429 . makeStream ( )
30+ closeError = UnfairLock ( nil )
3531 }
3632
3733 deinit {
38- webSocketTask . cancel ( with : . goingAway , reason : nil )
34+ disconnect ( )
3935 }
4036
4137 func connect( ) -> AsyncThrowingStream < URLSessionWebSocketTask . Message , Error > {
4238 webSocketTask. resume ( )
43- closeError = nil
39+ closeError. withLock { $0 = nil }
4440 startReceiving ( )
4541 return stream
4642 }
4743
4844 func disconnect( ) {
49- if closeError != nil { return }
45+ if closeError. value ( ) != nil { return }
5046
5147 close ( code: . goingAway, reason: nil )
5248 }
5349
5450 func send( _ message: URLSessionWebSocketTask . Message ) async throws {
55- if let closeError {
51+ if let closeError = closeError . value ( ) {
5652 throw closeError
5753 }
5854 try await webSocketTask. send ( message)
5955 }
6056
6157 private func startReceiving( ) {
6258 Task {
63- while !Task. isCancelled && self . webSocketTask. isOpen && self . closeError == nil {
59+ while !Task. isCancelled && self . webSocketTask. isOpen && self . closeError. value ( ) == nil {
6460 do {
6561 let message = try await webSocketTask. receive ( )
6662 continuation. yield ( message)
@@ -73,7 +69,9 @@ final class AsyncWebSocket: NSObject, @unchecked Sendable, URLSessionWebSocketDe
7369
7470 private func close( code: URLSessionWebSocketTask . CloseCode , reason: Data ? ) {
7571 let error = WebSocketClosedError ( closeCode: code, closeReason: reason)
76- closeError = error
72+ closeError. withLock {
73+ $0 = error
74+ }
7775
7876 webSocketTask. cancel ( with: code, reason: reason)
7977
0 commit comments