Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

4.68.0 Release #3521

Merged
merged 10 commits into from
Dec 3, 2024
  •  
  •  
  •  
28 changes: 14 additions & 14 deletions .github/workflows/cron-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jobs:
strategy:
matrix:
include:
- ios: 18.1
xcode: 16.1
os: macos-15
device: "iPhone 16 Pro"
setup_runtime: false
- ios: 17.4
xcode: 15.4
os: macos-14
Expand Down Expand Up @@ -123,6 +128,11 @@ jobs:
strategy:
matrix:
include:
- ios: 18.1
xcode: 16.1
os: macos-15
device: "iPhone 16 Pro"
setup_runtime: false
- ios: 17.4
xcode: 15.4
os: macos-14
Expand All @@ -138,16 +148,6 @@ jobs:
os: macos-14
device: "iPhone 13 Pro"
setup_runtime: true
- ios: 14.5
xcode: 14.2
os: macos-12
device: "iPhone 12 Pro"
setup_runtime: true
- ios: 13.7
xcode: 14.2
os: macos-12
device: "iPhone 11 Pro"
setup_runtime: true
fail-fast: false
runs-on: ${{ matrix.os }}
env:
Expand Down Expand Up @@ -189,11 +189,11 @@ jobs:
fastlane/test_output/logs/*/Diagnostics/**/*.txt
fastlane/test_output/logs/*/Diagnostics/simctl_diagnostics/DiagnosticReports/*

build-xcode14:
name: Build LLC + UI (Xcode 14)
runs-on: macos-12
build-old-xcode:
name: Build LLC + UI (Xcode 15)
runs-on: macos-14
env:
XCODE_VERSION: "14.0.1"
XCODE_VERSION: "15.0.1"
steps:
- name: Connect Bot
uses: webfactory/[email protected]
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
jobs:
release:
name: Publish new release
runs-on: macos-12
runs-on: macos-15
steps:
- name: Connect Bot
uses: webfactory/[email protected]
Expand Down
26 changes: 12 additions & 14 deletions .github/workflows/smoke-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ concurrency:

env:
HOMEBREW_NO_INSTALL_CLEANUP: 1 # Disable cleanup for homebrew, we don't need it on CI
IOS_SIMULATOR_DEVICE: "iPhone 15 Pro (17.4)"
IOS_SIMULATOR_DEVICE: "iPhone 16 Pro (18.1)"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_NUM: ${{ github.event.pull_request.number }}

Expand Down Expand Up @@ -48,9 +48,9 @@ jobs:

automated-code-review:
name: Automated Code Review
runs-on: macos-12
runs-on: macos-14
env:
XCODE_VERSION: "14.0.1"
XCODE_VERSION: "15.0.1"
if: ${{ github.event_name != 'push' && github.event.inputs.snapshots != 'true' }}
steps:
- uses: actions/[email protected]
Expand All @@ -67,12 +67,12 @@ jobs:
if: startsWith(github.event.pull_request.head.ref, 'release/')
run: bundle exec fastlane pod_lint

build-xcode14:
name: Build LLC + UI (Xcode 14)
runs-on: macos-12
build-old-xcode:
name: Build LLC + UI (Xcode 15)
runs-on: macos-14
if: ${{ github.event_name != 'push' && github.event.inputs.snapshots != 'true' }}
env:
XCODE_VERSION: "14.0.1"
XCODE_VERSION: "15.0.1"
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/ruby-cache
Expand All @@ -87,7 +87,7 @@ jobs:

test-llc-debug:
name: Test LLC (Debug)
runs-on: macos-14
runs-on: macos-15
if: ${{ github.event.inputs.snapshots != 'true' }}
needs: build-test-app-and-frameworks
steps:
Expand Down Expand Up @@ -136,7 +136,7 @@ jobs:

test-ui-debug:
name: Test UI (Debug)
runs-on: macos-14
runs-on: macos-15
needs: build-test-app-and-frameworks
if: ${{ github.event_name != 'push' }}
steps:
Expand All @@ -152,7 +152,7 @@ jobs:
SKIP_BREW_BOOTSTRAP: true
- name: Run UI Tests (Debug)
run: bundle exec fastlane test_ui device:"${{ env.IOS_SIMULATOR_DEVICE }}" skip_build:true record:${{ github.event.inputs.snapshots }}
timeout-minutes: 60
timeout-minutes: 120
env:
GITHUB_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }} # to open a PR
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} # to use github cli
Expand All @@ -170,7 +170,7 @@ jobs:

allure_testops_launch:
name: Launch Allure TestOps
runs-on: macos-13
runs-on: macos-14
if: ${{ github.event_name != 'push' && github.event.inputs.snapshots != 'true' }}
needs: build-test-app-and-frameworks
outputs:
Expand All @@ -189,7 +189,7 @@ jobs:

test-e2e-debug:
name: Test E2E UI (Debug)
runs-on: macos-14
runs-on: macos-15
if: ${{ github.event_name != 'push' && github.event.inputs.snapshots != 'true' }}
needs:
- allure_testops_launch
Expand All @@ -216,8 +216,6 @@ jobs:
run: bundle exec fastlane test_e2e_mock device:"${{ env.IOS_SIMULATOR_DEVICE }}" batch:'${{ matrix.batch }}' test_without_building:true
timeout-minutes: 100
env:
XCODE_VERSION: "15.0.1" # the most stable pair of Xcode
IOS_SIMULATOR_DEVICE: "iPhone 15 Pro (17.0)" # and iOS
MATRIX_SIZE: ${{ strategy.job-total }}
STREAM_DEMO_APP_SECRET: ${{ secrets.STREAM_DEMO_APP_SECRET }}
- name: Allure TestOps Upload
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-copyright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ env:
jobs:
copyright:
name: Copyright
runs-on: macos-13
runs-on: macos-14
steps:
- uses: actions/[email protected]
- uses: ./.github/actions/ruby-cache
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### 🔄 Changed

# [4.68.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.68.0)
_December 03, 2024_

## StreamChat
### 🐞 Fixed
- Fix a rare infinite loop triggering a crash when handling database changes [#3508](https://github.com/GetStream/stream-chat-swift/pull/3508)
- Fix reconnection timeout handler not working in the token provider phase [#3513](https://github.com/GetStream/stream-chat-swift/pull/3513)
### 🔄 Changed
- Minor breaking change in the test tools. Some mock classes were made internal and now require a `@testable` annotation [#3509](https://github.com/GetStream/stream-chat-swift/pull/3509)

## StreamChatUI
### 🐞 Fixed
- Fix Channel List search bar disappearing after it loses scrollability in rare scenarios [#3515](https://github.com/GetStream/stream-chat-swift/pull/3515)

# [4.67.0](https://github.com/GetStream/stream-chat-swift/releases/tag/4.67.0)
_November 25, 2024_

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<a href="https://sonarcloud.io/summary/new_code?id=GetStream_stream-chat-swift"><img src="https://sonarcloud.io/api/project_badges/measure?project=GetStream_stream-chat-swift&metric=coverage" /></a>
</p>
<p align="center">
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-7.06%20MB-blue"/>
<img id="stream-chat-label" alt="StreamChat" src="https://img.shields.io/badge/StreamChat-7.08%20MB-blue"/>
<img id="stream-chat-ui-label" alt="StreamChatUI" src="https://img.shields.io/badge/StreamChatUI-4.96%20MB-blue"/>
</p>

Expand Down
11 changes: 7 additions & 4 deletions Sources/StreamChat/ChatClient+Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ extension ChatClient {
)
}

var reconnectionHandlerBuilder: (_ chatClientConfig: ChatClientConfig) -> StreamTimer? = {
guard let reconnectionTimeout = $0.reconnectionTimeout else { return nil }
return ScheduledStreamTimer(interval: reconnectionTimeout, fireOnStart: false, repeats: false)
}

var extensionLifecycleBuilder = NotificationExtensionLifecycle.init

var requestEncoderBuilder: (_ baseURL: URL, _ apiKey: APIKey) -> RequestEncoder = DefaultRequestEncoder.init
Expand Down Expand Up @@ -97,8 +102,7 @@ extension ChatClient {
_ extensionLifecycle: NotificationExtensionLifecycle,
_ backgroundTaskScheduler: BackgroundTaskScheduler?,
_ internetConnection: InternetConnection,
_ keepConnectionAliveInBackground: Bool,
_ reconnectionTimeoutHandler: StreamTimer?
_ keepConnectionAliveInBackground: Bool
) -> ConnectionRecoveryHandler = {
DefaultConnectionRecoveryHandler(
webSocketClient: $0,
Expand All @@ -109,8 +113,7 @@ extension ChatClient {
internetConnection: $5,
reconnectionStrategy: DefaultRetryStrategy(),
reconnectionTimerType: DefaultTimer.self,
keepConnectionAliveInBackground: $6,
reconnectionTimeoutHandler: $7
keepConnectionAliveInBackground: $6
)
}

Expand Down
48 changes: 45 additions & 3 deletions Sources/StreamChat/ChatClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public class ChatClient {
/// Used as a bridge to communicate between the host app and the notification extension. Holds the state for the app lifecycle.
let extensionLifecycle: NotificationExtensionLifecycle

/// The component responsible to timeout the user connection if it takes more time than the `ChatClientConfig.reconnectionTimeout`.
var reconnectionTimeoutHandler: StreamTimer?

/// The environment object containing all dependencies of this `Client` instance.
private let environment: Environment

Expand Down Expand Up @@ -219,12 +222,18 @@ public class ChatClient {
setupOfflineRequestQueue()
setupConnectionRecoveryHandler(with: environment)
validateIntegrity()

reconnectionTimeoutHandler = environment.reconnectionHandlerBuilder(config)
reconnectionTimeoutHandler?.onChange = { [weak self] in
self?.timeout()
}
}

deinit {
Self._activeLocalStorageURLs.mutate { $0.subtract(databaseContainer.persistentStoreDescriptions.compactMap(\.url)) }
completeConnectionIdWaiters(connectionId: nil)
completeTokenWaiters(token: nil)
reconnectionTimeoutHandler?.stop()
}

func setupTokenRefresher() {
Expand Down Expand Up @@ -254,8 +263,7 @@ public class ChatClient {
extensionLifecycle,
environment.backgroundTaskSchedulerBuilder(),
environment.internetConnection(eventNotificationCenter, environment.internetMonitor),
config.staysConnectedInBackground,
config.reconnectionTimeout.map { ScheduledStreamTimer(interval: $0, fireOnStart: false, repeats: false) }
config.staysConnectedInBackground
)
}

Expand Down Expand Up @@ -300,7 +308,9 @@ public class ChatClient {
tokenProvider: @escaping TokenProvider,
completion: ((Error?) -> Void)? = nil
) {
reconnectionTimeoutHandler?.start()
connectionRecoveryHandler?.start()
connectionRepository.initialize()

authenticationRepository.connectUser(
userInfo: userInfo,
Expand Down Expand Up @@ -393,7 +403,9 @@ public class ChatClient {
userInfo: UserInfo,
completion: ((Error?) -> Void)? = nil
) {
connectionRepository.initialize()
connectionRecoveryHandler?.start()
reconnectionTimeoutHandler?.start()
authenticationRepository.connectGuestUser(userInfo: userInfo, completion: { completion?($0) })
}

Expand All @@ -417,6 +429,8 @@ public class ChatClient {
/// Connects an anonymous user
/// - Parameter completion: The completion that will be called once the **first** user session for the given token is setup.
public func connectAnonymousUser(completion: ((Error?) -> Void)? = nil) {
connectionRepository.initialize()
reconnectionTimeoutHandler?.start()
connectionRecoveryHandler?.start()
authenticationRepository.connectAnonymousUser(
completion: { completion?($0) }
Expand Down Expand Up @@ -458,7 +472,7 @@ public class ChatClient {
completion()
}
authenticationRepository.clearTokenProvider()
authenticationRepository.cancelTimers()
authenticationRepository.reset()
}

/// Disconnects the chat client from the chat servers. No further updates from the servers
Expand Down Expand Up @@ -617,6 +631,15 @@ public class ChatClient {
completion?($0)
}
}

private func timeout() {
completeConnectionIdWaiters(connectionId: nil)
authenticationRepository.completeTokenCompletions(error: ClientError.ReconnectionTimeout())
completeTokenWaiters(token: nil)
authenticationRepository.reset()
let webSocketConnectionState = webSocketClient?.connectionState ?? .initialized
connectionRepository.disconnect(source: .timeout(from: webSocketConnectionState)) {}
}
}

extension ChatClient: AuthenticationRepositoryDelegate {
Expand Down Expand Up @@ -646,6 +669,17 @@ extension ChatClient: ConnectionStateDelegate {
)
connectionRecoveryHandler?.webSocketClient(client, didUpdateConnectionState: state)
try? backgroundWorker(of: MessageSender.self).didUpdateConnectionState(state)

switch state {
case .connecting:
if reconnectionTimeoutHandler?.isRunning == false {
reconnectionTimeoutHandler?.start()
}
case .connected:
reconnectionTimeoutHandler?.stop()
default:
break
}
}
}

Expand Down Expand Up @@ -692,6 +726,14 @@ extension ClientError {
}
}

public final class ReconnectionTimeout: ClientError {
override public var localizedDescription: String {
"""
The reconnection process has timed out after surpassing the value from `ChatClientConfig.reconnectionTimeout`.
"""
}
}

public final class MissingToken: ClientError {}
final class WaiterTimeout: ClientError {}

Expand Down
Loading
Loading