Skip to content

Commit

Permalink
[Fix]StreamVideo unable to connect from CallKit (#600)
Browse files Browse the repository at this point in the history
  • Loading branch information
ipavlidakis authored Nov 29, 2024
1 parent 1bf0b61 commit 90a596b
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 22 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

# Upcoming

### 🔄 Changed
### 🐞 Fixed
- When a call you receive a ringing while the app isn't running (and the screen is locked), websocket connection wasn't recovered. [#600](https://github.com/GetStream/stream-video-swift/pull/600)

# [1.14.1](https://github.com/GetStream/stream-video-swift/releases/tag/1.14.1)
_November 12, 2024_
Expand Down
129 changes: 108 additions & 21 deletions Sources/StreamVideo/WebSockets/Client/ConnectionRecoveryHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,47 @@ final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler {
private var reconnectionStrategy: RetryStrategy
private var reconnectionTimer: TimerControl?
private let keepConnectionAliveInBackground: Bool

private var reconnectionPolicies: [AutomaticReconnectionPolicy]

// MARK: - Init
init(

convenience init(
webSocketClient: WebSocketClient,
eventNotificationCenter: EventNotificationCenter,
backgroundTaskScheduler: BackgroundTaskScheduler?,
internetConnection: InternetConnection,
reconnectionStrategy: RetryStrategy,
reconnectionTimerType: Timer.Type,
keepConnectionAliveInBackground: Bool
) {
self.init(
webSocketClient: webSocketClient,
eventNotificationCenter: eventNotificationCenter,
backgroundTaskScheduler: backgroundTaskScheduler,
internetConnection: internetConnection,
reconnectionStrategy: reconnectionStrategy,
reconnectionTimerType: reconnectionTimerType,
keepConnectionAliveInBackground: keepConnectionAliveInBackground,
reconnectionPolicies: [
WebSocketAutomaticReconnectionPolicy(webSocketClient),
InternetAvailabilityReconnectionPolicy(internetConnection),
CompositeReconnectionPolicy(.or, policies: [
BackgroundStateReconnectionPolicy(backgroundTaskScheduler),
CallKitReconnectionPolicy()
])
]
)
}

init(
webSocketClient: WebSocketClient,
eventNotificationCenter: EventNotificationCenter,
backgroundTaskScheduler: BackgroundTaskScheduler?,
internetConnection: InternetConnection,
reconnectionStrategy: RetryStrategy,
reconnectionTimerType: Timer.Type,
keepConnectionAliveInBackground: Bool,
reconnectionPolicies: [AutomaticReconnectionPolicy]
) {
self.webSocketClient = webSocketClient
self.eventNotificationCenter = eventNotificationCenter
Expand All @@ -47,6 +77,7 @@ final class DefaultConnectionRecoveryHandler: ConnectionRecoveryHandler {
self.reconnectionStrategy = reconnectionStrategy
self.reconnectionTimerType = reconnectionTimerType
self.keepConnectionAliveInBackground = keepConnectionAliveInBackground
self.reconnectionPolicies = reconnectionPolicies

subscribeOnNotifications()
}
Expand Down Expand Up @@ -192,24 +223,7 @@ private extension DefaultConnectionRecoveryHandler {
}

var canReconnectAutomatically: Bool {
guard webSocketClient.connectionState.isAutomaticReconnectionEnabled else {
log.debug("Reconnection is not required (\(webSocketClient.connectionState))", subsystems: .webSocket)
return false
}

guard internetConnection.status.isAvailable else {
log.debug("Reconnection is not possible (internet ❌)", subsystems: .webSocket)
return false
}

guard backgroundTaskScheduler?.isAppActive ?? true else {
log.debug("Reconnection is not possible (app 💤)", subsystems: .webSocket)
return false
}

log.debug("Will reconnect automatically", subsystems: .webSocket)

return true
reconnectionPolicies.first { $0.canBeReconnected() == false } == nil
}
}

Expand Down Expand Up @@ -247,3 +261,76 @@ private extension DefaultConnectionRecoveryHandler {
reconnectionTimer = nil
}
}

// MARK: - Automatic Reconnection Policies

protocol AutomaticReconnectionPolicy {
func canBeReconnected() -> Bool
}

struct WebSocketAutomaticReconnectionPolicy: AutomaticReconnectionPolicy {
private var webSocketClient: WebSocketClient

init(_ webSocketClient: WebSocketClient) {
self.webSocketClient = webSocketClient
}

func canBeReconnected() -> Bool {
webSocketClient.connectionState.isAutomaticReconnectionEnabled
}
}

struct InternetAvailabilityReconnectionPolicy: AutomaticReconnectionPolicy {
private var internetConnection: InternetConnection

init(_ internetConnection: InternetConnection) {
self.internetConnection = internetConnection
}

func canBeReconnected() -> Bool {
internetConnection.status.isAvailable
}
}

struct BackgroundStateReconnectionPolicy: AutomaticReconnectionPolicy {
private var backgroundTaskScheduler: BackgroundTaskScheduler?

init(_ backgroundTaskScheduler: BackgroundTaskScheduler?) {
self.backgroundTaskScheduler = backgroundTaskScheduler
}

func canBeReconnected() -> Bool {
backgroundTaskScheduler?.isAppActive ?? true
}
}

struct CallKitReconnectionPolicy: AutomaticReconnectionPolicy {
@Injected(\.callKitService) private var callKitService

init() {}

func canBeReconnected() -> Bool {
callKitService.callCount > 0
}
}

struct CompositeReconnectionPolicy: AutomaticReconnectionPolicy {
enum Operator { case and, or }

private var `operator`: Operator
private var policies: [AutomaticReconnectionPolicy]

init(_ operator: Operator, policies: [AutomaticReconnectionPolicy]) {
self.operator = `operator`
self.policies = policies
}

func canBeReconnected() -> Bool {
switch `operator` {
case .and:
return policies.first { $0.canBeReconnected() == false } == nil
case .or:
return policies.first { $0.canBeReconnected() } != nil
}
}
}

0 comments on commit 90a596b

Please sign in to comment.