@@ -450,25 +450,34 @@ public class StreamVideo: ObservableObject, @unchecked Sendable {
450
450
} else {
451
451
throw ClientError . Unknown ( )
452
452
}
453
- var connected = false
454
- var timeout = false
455
- let control = DefaultTimer . schedule ( timeInterval: 30 , queue: . sdk) {
456
- timeout = true
457
- }
458
- log. debug ( " Listening for WS connection " )
459
- webSocketClient? . onConnected = {
460
- control. cancel ( )
461
- connected = true
462
- log. debug ( " WS connected " )
463
- }
464
453
465
- while ( !connected && !timeout) {
466
- try await Task . sleep ( nanoseconds: 100_000 )
467
- }
468
-
469
- if timeout {
470
- log. debug ( " Timeout while waiting for WS connection opening " )
471
- throw ClientError . NetworkError ( )
454
+ log. debug ( " Listening for WS connection " )
455
+ var continuationHandler : ( ( ) -> Void ) ? = nil
456
+ try await withThrowingTaskGroup ( of: Void . self) { group in
457
+ group. addTask {
458
+ try await Task . sleep ( nanoseconds: 30 * 1_000_000_000 )
459
+ log. debug ( " Timeout while waiting for WS connection opening " )
460
+ continuationHandler = nil
461
+ throw ClientError . NetworkError ( )
462
+ }
463
+ group. addTask {
464
+ try await withCheckedThrowingContinuation { ( continuation: CheckedContinuation < Void , Error > ) in
465
+ continuationHandler = {
466
+ continuation. resume ( returning: ( ) )
467
+ }
468
+ webSocketClient? . onConnected = { [ weak self] in
469
+ self ? . log. debug ( " WS connected " )
470
+ // Only resume if the handler still exists
471
+ if let continuationHandler {
472
+ continuationHandler ( )
473
+ continuationHandler = nil
474
+ }
475
+ }
476
+ }
477
+ }
478
+ // race between “onConnected” and 30s timeout: whichever finishes first “wins”
479
+ try await group. next ( )
480
+ group. cancelAll ( )
472
481
}
473
482
}
474
483
0 commit comments