Skip to content

Conversation

@ohassine
Copy link
Member

@ohassine ohassine commented Aug 20, 2025

EpicWPB-8645 [Android] Infrastructure code and developer experience


PR Submission Checklist for internal contributors

  • The PR Title

    • conforms to the style of semantic commits messages¹ supported in Wire's Github Workflow²
    • contains a reference JIRA issue number like SQPIT-764
    • answers the question: If merged, this PR will: ... ³
  • The PR Description

    • is free of optional paragraphs and you have filled the relevant parts to the best of your ability

What's new in this PR?

Issues

Ktor update was reverted in this commit d30f3df because it's not possible to build a release app

Causes (Optional)

Some proguard rules are missing

Solutions

Added them

Needs releases with:

  • GitHub link to other pull request

Testing

Test Coverage (Optional)

  • I have added automated test to this contribution

How to Test

Briefly describe how this change was tested and if applicable the exact steps taken to verify that it works as expected.

Notes (Optional)

Specify here any other facts that you think are important for this issue.

Attachments (Optional)

Attachments like images, videos, etc. (drag and drop in the text box)


PR Post Submission Checklist for internal contributors (Optional)

  • Wire's Github Workflow has automatically linked the PR to a JIRA issue

PR Post Merge Checklist for internal contributors

  • If any soft of configuration variable was introduced by this PR, it has been added to the relevant documents and the CI jobs have been updated.

References
  1. https://sparkbox.com/foundry/semantic_commit_messages
  2. https://github.com/wireapp/.github#usage
  3. E.g. feat(conversation-list): Sort conversations by most emojis in the title #SQPIT-764.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 20, 2025

Test Results

0 tests   - 4 050   0 ✅  - 3 939   0s ⏱️ - 5m 56s
0 suites  -   684   0 💤  -   111 
0 files    -   684   0 ❌ ±    0 

Results for commit 00c1198. ± Comparison against base commit 48d592d.

♻️ This comment has been updated with latest results.

@github-actions
Copy link
Contributor

github-actions bot commented Aug 20, 2025

🐰 Bencher Report

Branchbump-ktor
Testbedubuntu-latest

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkLatencymicroseconds (µs)
com.wire.kalium.benchmarks.logic.CoreLogicBenchmark.createObjectInFiles📈 view plot
⚠️ NO THRESHOLD
704.07 µs
com.wire.kalium.benchmarks.logic.CoreLogicBenchmark.createObjectInMemory📈 view plot
⚠️ NO THRESHOLD
465,426.31 µs
com.wire.kalium.benchmarks.persistence.MessagesNoPragmaTuneBenchmark.messageInsertionBenchmark📈 view plot
⚠️ NO THRESHOLD
1,482,051.96 µs
com.wire.kalium.benchmarks.persistence.MessagesNoPragmaTuneBenchmark.queryMessagesBenchmark📈 view plot
⚠️ NO THRESHOLD
28,462.86 µs
🐰 View full continuous benchmarking report in Bencher

@codecov-commenter
Copy link

codecov-commenter commented Aug 20, 2025

Codecov Report

❌ Patch coverage is 3.57143% with 27 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.57%. Comparing base (48d592d) to head (00c1198).

Files with missing lines Patch % Lines
.../network/api/v0/authenticated/NotificationApiV0.kt 0.00% 7 Missing ⚠️
.../network/api/v9/authenticated/NotificationApiV9.kt 0.00% 7 Missing ⚠️
...com/wire/kalium/network/KaliumKtorCustomLogging.kt 0.00% 5 Missing ⚠️
...in/com/wire/kalium/network/KaliumObservingUtils.kt 0.00% 2 Missing ⚠️
.../kotlin/com/wire/kalium/cells/data/CellsApiImpl.kt 0.00% 1 Missing ⚠️
...in/kotlin/com/wire/kalium/network/NetworkClient.kt 0.00% 1 Missing ⚠️
.../networkContainer/AuthenticatedNetworkContainer.kt 0.00% 1 Missing ⚠️
.../com/wire/kalium/network/session/SessionManager.kt 0.00% 1 Missing ⚠️
...tlin/com/wire/kalium/network/utils/NetworkUtils.kt 50.00% 1 Missing ⚠️
...lin/com/wire/kalium/network/utils/ObfuscateUtil.kt 0.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3590      +/-   ##
===========================================
- Coverage    57.58%   57.57%   -0.01%     
===========================================
  Files         1781     1781              
  Lines        59263    59265       +2     
  Branches      5770     5774       +4     
===========================================
- Hits         34125    34124       -1     
- Misses       22711    22714       +3     
  Partials      2427     2427              
Files with missing lines Coverage Δ
.../kalium/network/api/v0/authenticated/AssetApiV0.kt 59.13% <ø> (ø)
...kalium/network/serialization/ByteArrayConverter.kt 80.00% <ø> (ø)
.../kotlin/com/wire/kalium/cells/data/CellsApiImpl.kt 10.61% <0.00%> (ø)
...in/kotlin/com/wire/kalium/network/NetworkClient.kt 57.57% <0.00%> (ø)
.../networkContainer/AuthenticatedNetworkContainer.kt 18.38% <0.00%> (ø)
.../com/wire/kalium/network/session/SessionManager.kt 94.73% <0.00%> (-5.27%) ⬇️
...tlin/com/wire/kalium/network/utils/NetworkUtils.kt 21.91% <50.00%> (ø)
...lin/com/wire/kalium/network/utils/ObfuscateUtil.kt 0.00% <0.00%> (ø)
...in/com/wire/kalium/network/KaliumObservingUtils.kt 0.00% <0.00%> (ø)
...com/wire/kalium/network/KaliumKtorCustomLogging.kt 0.00% <0.00%> (ø)
... and 2 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 48d592d...00c1198. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

val observer: ResponseHandler = observer@{
if (level == LogLevel.NONE || it.call.attributes.contains(DisableLogging)) {
return@observer
client.receivePipeline.intercept(HttpReceivePipeline.After) { response ->
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you test with this logger enabled, i remember using intercept will consume the response stream and later stages will not have anything to read

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I can see the response in logs

@ohassine ohassine requested a review from MohamadJaara August 25, 2025 14:25
@sonarqubecloud
Copy link

@ohassine ohassine requested a review from MohamadJaara August 26, 2025 09:21
@MohamadJaara MohamadJaara requested a review from Copilot August 26, 2025 12:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR updates Ktor from version 2.3.10 to 3.2.3 and resolves related API compatibility issues that prevented building release apps. The update includes necessary proguard rules and code changes to adapt to breaking changes in the Ktor API.

  • Updates Ktor version from 2.3.10 to 3.2.3 with accompanying dependency updates
  • Adapts code to handle Ktor 3.x API changes including deprecated methods and new property names
  • Adds comprehensive proguard rules to support the new Ktor version in release builds

Reviewed Changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
gradle/libs.versions.toml Updates Ktor version and related dependencies (kermit, cells-sdk)
network/consumer-proguard-rules.pro Adds Ktor-specific proguard rules to prevent obfuscation issues in release builds
network/src/commonMain/kotlin/com/wire/kalium/network/session/SessionManager.kt Updates API usage from deprecated content to rawContent property
network/src/commonMain/kotlin/com/wire/kalium/network/serialization/ByteArrayConverter.kt Replaces deprecated serializeNullable with serialize method
network/src/commonMain/kotlin/com/wire/kalium/network/utils/NetworkUtils.kt Changes from deprecated pathSegments to rawSegments property
network/src/commonMain/kotlin/com/wire/kalium/network/KaliumKtorCustomLogging.kt Refactors response logging to use new API patterns
network/src/commonMain/kotlin/com/wire/kalium/network/KaliumObservingUtils.kt Updates channel closing method from close() to flushAndClose()
Multiple test files Adds null safety checks for refresh tokens

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

import io.ktor.utils.io.ByteReadChannel
import io.mockative.Mockable
import kotlin.coroutines.CoroutineContext
import io.ktor.utils.io.InternalAPI
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using @InternalAPI annotation suggests this code relies on internal Ktor APIs that may change in future versions. Consider finding a stable public API alternative or document this dependency risk.

Suggested change
import io.ktor.utils.io.InternalAPI

Copilot uses AI. Check for mistakes.
xerialDriver = "3.48.0.0"
kotlinx-io = "0.5.3"
cells-sdk = "0.1.1-alpha10"
cells-sdk = "0.1.1-alpha15"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
cells-sdk = "0.1.1-alpha15"
cells-sdk = "0.1.1-alpha15.02"

This newer version has artifacts for all apple targets we support. So... no more warnings and we can ditch x64 and use simulatorArm64 instead.

override val responseTime: GMTDate = response.responseTime
override val content: ByteReadChannel = response.content

@InternalAPI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the goal of adding this @InternalAPI annotation?

If it's delicate, we can/should create an annotation of our own.

@RequiresOptIn(
    level = RequiresOptIn.Level.ERROR,
    message = "Some explanation here."
)
@Target(
    AnnotationTarget.CLASS,
    AnnotationTarget.TYPEALIAS,
    AnnotationTarget.FUNCTION,
    AnnotationTarget.PROPERTY,
    AnnotationTarget.FIELD,
    AnnotationTarget.CONSTRUCTOR,
    AnnotationTarget.PROPERTY_SETTER,
    AnnotationTarget.PROPERTY_SETTER
)
public annotation class InternalNetworkAPI

@yamilmedina
Copy link
Contributor

@claude review

@github-actions
Copy link
Contributor

github-actions bot commented Nov 5, 2025

Pull Request Review - Ktor 3.2.3 Upgrade

Overview

This PR upgrades Ktor from version 2.3.10 to 3.2.3, addressing issues with ProGuard rules that prevented building release apps. The changes also include updates to Kermit (2.0.3 → 2.0.6) and Cells SDK (0.1.1-alpha10 → 0.1.1-alpha15).

Summary

Recommendation: Approve with minor observations

The PR properly addresses the ProGuard configuration issues and adapts the codebase to Ktor 3.x API changes. The implementation is sound with good attention to detail in API migration.


Detailed Review

1. Dependencies Update ✅

Files: gradle/libs.versions.toml

  • Ktor: 2.3.10 → 3.2.3 (major version bump)
  • Kermit: 2.0.3 → 2.0.6 (minor update)
  • Cells SDK: 0.1.1-alpha10 → 0.1.1-alpha15

Assessment: Major version upgrades require careful testing, especially for networking libraries. The Ktor 3.x upgrade includes breaking API changes that have been properly addressed.


2. ProGuard Rules ✅

File: network/consumer-proguard-rules.pro

Added 22 new rules to prevent obfuscation of Ktor 3.x classes:

  • HttpTimeout configuration classes
  • ByteReadChannel and I/O utilities
  • Core Ktor utilities package

Assessment: The ProGuard rules are comprehensive and follow best practices. These rules are essential for preventing runtime crashes in release builds.


3. API Migration Changes ✅

A. WebSocket Configuration

File: network/src/commonMain/kotlin/com/wire/kalium/network/NetworkClient.kt:149

// Old (Ktor 2.x)
pingInterval = WEBSOCKET_PING_INTERVAL_MILLIS  // Long value

// New (Ktor 3.x)
pingInterval = WEBSOCKET_PING_INTERVAL_MILLIS.milliseconds  // Duration type

Assessment: ✅ Correct migration to Kotlin Duration API. This is a breaking change in Ktor 3.x that has been properly handled.

B. WebSocket Close Handling

Files: NotificationApiV0.kt, NotificationApiV9.kt

// Old
.onCompletion {
    defaultClientWebSocketSession.close()
    emit(WebSocketEvent.Close(it))
}

// New
.onCompletion { cause ->
    val closeReason = if (cause == null || cause is CancellationException) {
        CloseReason(CloseReason.Codes.NORMAL, "Normal closure")
    } else {
        CloseReason(CloseReason.Codes.INTERNAL_ERROR, "Error: ${cause.message}")
    }
    defaultClientWebSocketSession.close(closeReason)
    emit(WebSocketEvent.Close(cause))
}

Assessment: ✅ Excellent improvement! Ktor 3.x requires explicit close reasons. This implementation:

  • Properly distinguishes between normal closure and errors
  • Uses standard WebSocket close codes
  • Handles cancellation gracefully

C. Content Converter API

File: network/src/commonMain/kotlin/com/wire/kalium/network/serialization/ByteArrayConverter.kt:41

// Old
override suspend fun serializeNullable(...)

// New  
override suspend fun serialize(...)

Assessment: ✅ Correct API migration. Ktor 3.x renamed this method, properly updated.

D. HTTP Response Content Access

File: network/src/commonMain/kotlin/com/wire/kalium/network/session/SessionManager.kt:86

// Old
override val content: ByteReadChannel = response.content

// New
@InternalAPI
override val rawContent: ByteReadChannel get() = response.rawContent

Assessment: ✅ Correct migration to the new property name. The @InternalAPI annotation is properly used.

E. URL Path Segments

Files: NetworkUtils.kt, ObfuscateUtil.kt

// Old
pathSegments = baseUrl.pathSegments

// New
pathSegments = baseUrl.rawSegments

Assessment: ✅ Proper migration. Ktor 3.x changed the property name for raw path segments.

F. Logging Plugin

File: KaliumKtorCustomLogging.kt

Replaced ResponseObserver pattern with direct pipeline interception:

// Old - Used ResponseObserver.install()

// New - Direct pipeline interception
client.receivePipeline.intercept(HttpReceivePipeline.After) { response ->
    // Log response body
    logger.logResponseBody(response.contentType(), ByteReadChannel(response.readRawBytes()))
}

Assessment: ✅ Correct approach for Ktor 3.x. The ResponseObserver API changed, and this is the recommended pattern.

G. I/O Utilities

File: KaliumObservingUtils.kt

// Old
log.close()

// New
log.flushAndClose()

Assessment: ✅ Better practice - ensures data is flushed before closing.


4. Null Safety Improvements ✅

Files: Test files and AuthenticatedNetworkContainer.kt

// Old
oldRefreshToken = oldTokens\!\!.refreshToken

// New
oldRefreshToken = oldTokens\!\!.refreshToken ?: error("Old refresh token is null\!")

Assessment: ✅ Improved error handling with explicit error messages, making debugging easier.


5. Test Adjustments ✅

A. Build Configuration

File: logic/build.gradle.kts

Improved test configuration structure with better nesting and organization.

Assessment: ✅ Good refactoring for clarity.

B. Test Dependencies

Files: cells/build.gradle.kts, network/build.gradle.kts

Added ktor-contentNegotiation to test dependencies.

Assessment: ✅ Necessary for tests that verify content negotiation behavior.

C. API Call Changes

File: cells/src/commonMain/kotlin/com/wire/kalium/cells/data/CellsApiImpl.kt:326

// Old
nodeServiceApi.listNamespaceValues(namespace = TAGS_METADATA, operationValues = listOf())

// New
nodeServiceApi.listNamespaceValues(namespace = TAGS_METADATA)

Assessment: ✅ Simplification - removed unnecessary empty list parameter.


Potential Concerns & Recommendations

1. Testing Coverage ⚠️

Observation: The PR description states "I have not added automated tests to this contribution"

Recommendation:

  • Ensure thorough manual testing of WebSocket connections
  • Test token refresh scenarios
  • Verify release builds work correctly with ProGuard
  • Consider adding integration tests for WebSocket close scenarios

2. Breaking Changes Documentation 📝

Recommendation: Consider documenting the major API changes in release notes:

  • Duration-based WebSocket ping intervals
  • New WebSocket close reason handling
  • ContentConverter API changes

3. Performance Consideration 💡

File: KaliumKtorCustomLogging.kt:165

logger.logResponseBody(response.contentType(), ByteReadChannel(response.readRawBytes()))

Observation: readRawBytes() loads the entire response into memory.

Impact: This is fine for most APIs, but could be a concern for large file downloads. Consider if this affects any asset download scenarios.

4. Import Organization 🔧

File: NetworkClient.kt:47-48

Minor: Import order could be cleaned up (Duration import appears after usage)

import kotlin.time.Duration.Companion.milliseconds
import io.ktor.client.plugins.websocket.pingInterval

Security Assessment 🔒

✅ No security concerns identified:

  • ProGuard rules do not expose sensitive code
  • WebSocket close handling is secure
  • Token refresh logic maintains null safety
  • No hardcoded credentials or sensitive data

Best Practices Compliance ✅

  • ✅ Proper error handling with meaningful messages
  • ✅ Consistent API migration across all affected files
  • ✅ Appropriate use of Kotlin features (Duration, null safety)
  • ✅ Clean separation of concerns maintained
  • ✅ Proper use of internal APIs with annotations

Conclusion

This is a well-executed upgrade to Ktor 3.2.3. The changes demonstrate:

  • Good understanding of Ktor's breaking changes
  • Attention to detail in API migration
  • Improved error handling
  • Proper ProGuard configuration

The main gap is automated test coverage for the new behaviors, particularly WebSocket close scenarios. Otherwise, the implementation is solid.

Final Recommendation:APPROVE - pending successful CI builds and manual testing verification.


Review completed by Claude Code

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 5, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants