Skip to content

Commit e32dd86

Browse files
authored
[Fix]Remove unnecessary operation during tests and fix flakiness (#784)
1 parent 0db6951 commit e32dd86

File tree

9 files changed

+188
-45
lines changed

9 files changed

+188
-45
lines changed

Sources/StreamVideo/Call.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,34 @@ public class Call: @unchecked Sendable, WSEventsSubscriber {
158158
case let .joined(joinResponse) = currentStage.context.output {
159159
return joinResponse
160160
} else if
161-
currentStage.id == .joining,
162-
case let .join(input) = currentStage.context.input {
163-
return try await input
164-
.deliverySubject
161+
currentStage.id == .joining {
162+
return try await stateMachine
163+
.publisher
164+
.tryCompactMap {
165+
switch $0.id {
166+
case .joined:
167+
guard
168+
let stage = $0 as? Call.StateMachine.Stage.JoinedStage
169+
else {
170+
throw ClientError()
171+
}
172+
switch stage.context.output {
173+
case let .joined(response):
174+
return response
175+
default:
176+
throw ClientError()
177+
}
178+
case .error:
179+
guard
180+
let stage = $0 as? Call.StateMachine.Stage.ErrorStage
181+
else {
182+
throw ClientError()
183+
}
184+
throw stage.error
185+
default:
186+
return nil
187+
}
188+
}
165189
.nextValue(timeout: CallConfiguration.timeout.join)
166190
} else {
167191
let deliverySubject = PassthroughSubject<JoinCallResponse, Error>()

Sources/StreamVideo/StreamVideo.swift

Lines changed: 65 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -126,18 +126,41 @@ public class StreamVideo: ObservableObject, @unchecked Sendable {
126126
videoConfig: videoConfig,
127127
tokenProvider: tokenProvider ?? { _ in },
128128
pushNotificationsConfig: pushNotificationsConfig,
129-
environment: Environment()
129+
environment: Environment(),
130+
autoConnectOnInit: true
130131
)
131132
}
132-
133+
134+
convenience init(
135+
apiKey: String,
136+
user: User,
137+
token: UserToken,
138+
videoConfig: VideoConfig = VideoConfig(),
139+
pushNotificationsConfig: PushNotificationsConfig = .default,
140+
tokenProvider: UserTokenProvider? = nil,
141+
autoConnectOnInit: Bool
142+
) {
143+
self.init(
144+
apiKey: apiKey,
145+
user: user,
146+
token: token,
147+
videoConfig: videoConfig,
148+
tokenProvider: tokenProvider ?? { _ in },
149+
pushNotificationsConfig: pushNotificationsConfig,
150+
environment: Environment(),
151+
autoConnectOnInit: autoConnectOnInit
152+
)
153+
}
154+
133155
init(
134156
apiKey: String,
135157
user: User,
136158
token: UserToken,
137159
videoConfig: VideoConfig = VideoConfig(),
138160
tokenProvider: @escaping UserTokenProvider,
139161
pushNotificationsConfig: PushNotificationsConfig,
140-
environment: Environment
162+
environment: Environment,
163+
autoConnectOnInit: Bool
141164
) {
142165
self.apiKey = APIKey(apiKey)
143166
state = State(user: user)
@@ -188,32 +211,12 @@ public class StreamVideo: ObservableObject, @unchecked Sendable {
188211
coordinatorClient.middlewares.append(anonymousAuth)
189212
}
190213
prefetchLocation()
191-
connectTask = Task {
192-
if user.type == .guest {
193-
do {
194-
try Task.checkCancellation()
195-
let guestInfo = try await loadGuestUserInfo(for: user, apiKey: apiKey)
196-
197-
self.state.user = guestInfo.user
198-
self.token = guestInfo.token
199-
self.tokenProvider = guestInfo.tokenProvider
200214

201-
try Task.checkCancellation()
202-
try await self.connectUser(isInitial: true)
203-
} catch {
204-
log.error("Error connecting as guest", error: error)
205-
}
206-
} else if user.type != .anonymous {
207-
do {
208-
try Task.checkCancellation()
209-
try await self.connectUser(isInitial: true)
210-
} catch {
211-
log.error(error)
212-
}
213-
}
215+
if autoConnectOnInit {
216+
initialConnectIfRequired(apiKey: apiKey)
214217
}
215218
}
216-
219+
217220
deinit {
218221
connectTask?.cancel()
219222
connectTask = nil
@@ -418,7 +421,42 @@ public class StreamVideo: ObservableObject, @unchecked Sendable {
418421
}
419422

420423
// MARK: - private
421-
424+
425+
/// When initializing we perform an automatic connection attempt.
426+
///
427+
/// - Important: This behaviour is only enabled for non-test environments. This is to reduce the
428+
/// noise in logs and avoid unnecessary network operations with the backend.
429+
private func initialConnectIfRequired(apiKey: String) {
430+
guard connectTask == nil else {
431+
return
432+
}
433+
434+
connectTask = Task {
435+
if user.type == .guest {
436+
do {
437+
try Task.checkCancellation()
438+
let guestInfo = try await loadGuestUserInfo(for: user, apiKey: apiKey)
439+
440+
self.state.user = guestInfo.user
441+
self.token = guestInfo.token
442+
self.tokenProvider = guestInfo.tokenProvider
443+
444+
try Task.checkCancellation()
445+
try await self.connectUser(isInitial: true)
446+
} catch {
447+
log.error("Error connecting as guest", error: error)
448+
}
449+
} else if user.type != .anonymous {
450+
do {
451+
try Task.checkCancellation()
452+
try await self.connectUser(isInitial: true)
453+
} catch {
454+
log.error(error)
455+
}
456+
}
457+
}
458+
}
459+
422460
/// Creates a call controller, used for establishing and managing a call.
423461
/// - Parameters:
424462
/// - callType: the type of the call.

Sources/StreamVideo/Utils/StateMachine/Publisher+NextValue.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,11 @@ extension Publisher where Output: Sendable {
5454
receiveValue: { value in
5555
timeoutWorkItem?.cancel()
5656
if !receivedValue {
57-
continuation.resume(returning: value) // Resume only if value hasn't been received
57+
if let error = value as? Error {
58+
continuation.resume(throwing: error)
59+
} else {
60+
continuation.resume(returning: value) // Resume only if value hasn't been received
61+
}
5862
receivedValue = true
5963
}
6064
cancellable?.cancel()

0 commit comments

Comments
 (0)