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

feat: OkHttp implementation for making HTTP calls and WebSocket connections #1035

Merged
merged 5 commits into from
Oct 7, 2024

Conversation

ttypic
Copy link
Contributor

@ttypic ttypic commented Sep 25, 2024

Resolves #120

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced support for using the Ably SDK under a proxy, with detailed instructions in the README.
    • Added a new network-client-okhttp module to enhance HTTP and WebSocket connections.
    • Implemented classes for HTTP calls and WebSocket clients using the OkHttp library.
    • Enhanced WebSocket functionality with ping listener support in the new classes.
    • Added a retry mechanism for tests to improve reliability.
  • Documentation

    • Enhanced README with proxy configuration details and examples.
  • Chores

    • Updated project settings to include the new network-client-okhttp module.
    • Added integration tests for OkHttp configurations in the CI workflow.

@ttypic ttypic requested a review from sacOO7 September 25, 2024 11:41
Copy link

coderabbitai bot commented Sep 25, 2024

Walkthrough

The changes introduce a new module, network-client-okhttp, implementing HTTP and WebSocket functionality using the OkHttp library. The README.md file has been updated to include instructions for using the Ably SDK under a proxy. Build configuration files have been modified to include necessary dependencies, and new classes and utility methods have been added to facilitate HTTP calls and WebSocket connections, including proxy settings and SSL configurations.

Changes

Files Change Summary
README.md Added a section on using the Ably SDK under a proxy, including configuration instructions and a Java example.
gradle/libs.versions.toml Introduced a new dependency for the okhttp library (version "4.12.0") and test-retry library (version "1.6.0").
network-client-default/build.gradle.kts Changed dependency scope from api to implementation for network-client-core.
network-client-okhttp/build.gradle.kts Created a new build configuration for the network-client-okhttp module, specifying dependencies and Java compatibility.
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java Implemented WebSocket client functionality using OkHttp.
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java Introduced OkHttpWebSocketEngine for creating WebSocket clients.
settings.gradle.kts Added inclusion of the network-client-okhttp module in the project configuration.
.github/workflows/integration-test.yml Introduced new jobs for integration testing with OkHttp configuration.
build.gradle.kts Added test.retry plugin for enhanced testing capabilities.
java/build.gradle.kts Enhanced testing framework with retry capabilities and conditional dependency management.
android/src/androidTest/java/io/ably/lib/test/RetryTestRule.java Added a new class RetryTestRule to implement test retry functionality.
android/src/androidTest/java/io/ably/lib/test/android/AndroidPushTest.java Integrated RetryTestRule into AndroidPushTest class for improved test reliability.

Assessment against linked issues

Objective Addressed Explanation
Expand proxy support for HTTP and WebSocket connections (#120)
Allow manual proxy configuration for HTTP and WebSocket (#120)

Poem

In the meadow where the bunnies play,
New changes hop in, brightening the day.
With OkHttp, we call and connect,
WebSockets dancing, all perfect!
Proxy settings, oh what a treat,
A joyful leap, our work's complete! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot temporarily deployed to staging/pull/1035/features September 25, 2024 11:42 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc September 25, 2024 11:43 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (16)
network-client-okhttp/gradle.properties (1)

1-4: LGTM with a minor suggestion for improvement.

The Gradle properties for the network-client-okhttp module are well-defined and consistent with the PR objectives. The artifact ID, name, and packaging are appropriate for the module.

Consider expanding the POM_DESCRIPTION to provide more specific information about the OkHttp implementation:

-POM_DESCRIPTION=Default implementation for HTTP client
+POM_DESCRIPTION=Default implementation of HTTP client and WebSocket connections using OkHttp

This change would more accurately reflect the module's capabilities, including both HTTP and WebSocket functionality.

network-client-okhttp/build.gradle.kts (2)

7-10: Consider using a more recent Java version.

The Java compatibility is set to version 1.8, which ensures broad compatibility. However, for a new module, you might want to consider using a more recent Java version to leverage newer language features and performance improvements.

If possible, consider upgrading to a newer Java version (e.g., Java 11 or 17) for this module. This could be done by updating the version:

 java {
-    sourceCompatibility = JavaVersion.VERSION_1_8
-    targetCompatibility = JavaVersion.VERSION_1_8
+    sourceCompatibility = JavaVersion.VERSION_11
+    targetCompatibility = JavaVersion.VERSION_11
 }

12-15: LGTM: Dependencies are correctly specified.

The dependencies section is well-structured:

  • The dependency on :network-client-core is appropriate for extending core networking functionality.
  • Using OkHttp is a good choice for implementing HTTP and WebSocket functionality.

Consider specifying the API dependency type for OkHttp if you're only using its public API:

 dependencies {
     implementation(project(":network-client-core"))
-    implementation(libs.okhttp)
+    api(libs.okhttp)
 }

This change would make the OkHttp API available to consumers of your library without them needing to declare a direct dependency on OkHttp.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngineFactory.java (1)

4-7: LGTM: create method implementation is correct.

The create method correctly implements the factory pattern, creating and returning a new OkHttpWebSocketEngine instance with the provided configuration.

Consider adding a null check for the config parameter to prevent potential NullPointerExceptions:

 @Override
 public WebSocketEngine create(WebSocketEngineConfig config) {
+    if (config == null) {
+        throw new IllegalArgumentException("WebSocketEngineConfig cannot be null");
+    }
     return new OkHttpWebSocketEngine(config);
 }
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngineFactory.java (2)

6-11: LGTM: create method implementation is correct. Consider adding error handling.

The create method correctly implements the factory pattern for creating HttpEngine instances. It properly uses the OkHttpClient.Builder and injects proxy settings using a utility method.

Consider adding error handling or parameter validation for the config object to make the method more robust. For example:

 @Override
 public HttpEngine create(HttpEngineConfig config) {
+    if (config == null) {
+        throw new IllegalArgumentException("HttpEngineConfig cannot be null");
+    }
     OkHttpClient.Builder connectionBuilder = new OkHttpClient.Builder();
     OkHttpUtils.injectProxySetting(config.getProxy(), connectionBuilder);
     return new OkHttpEngine(connectionBuilder.build(), config);
 }

1-17: Overall implementation looks good. Consider adding JavaDoc comments.

The OkHttpEngineFactory class is well-implemented, correctly following the factory pattern and providing a clean way to create OkHttp-based HTTP engines. The code is concise and easy to understand.

To improve documentation, consider adding JavaDoc comments to the class and its methods. This will enhance code readability and provide better context for developers using this class. For example:

/**
 * A factory for creating OkHttp-based HTTP engines.
 * This class implements the HttpEngineFactory interface to provide
 * OkHttp-specific HTTP engine instances.
 */
public class OkHttpEngineFactory implements HttpEngineFactory {
    /**
     * Creates a new HttpEngine instance configured with OkHttp.
     *
     * @param config The configuration for the HTTP engine.
     * @return A new OkHttpEngine instance.
     * @throws IllegalArgumentException if config is null.
     */
    @Override
    public HttpEngine create(HttpEngineConfig config) {
        // ... existing implementation ...
    }

    /**
     * Returns the type of this engine factory.
     *
     * @return EngineType.OKHTTP
     */
    @Override
    public EngineType getEngineType() {
        // ... existing implementation ...
    }
}
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (2)

9-11: Consider adding a null check for the config parameter.

The constructor correctly initializes the config field, but it doesn't validate the input. To prevent potential NullPointerExceptions later in the code, consider adding a null check.

Here's a suggested implementation:

 public OkHttpWebSocketEngine(WebSocketEngineConfig config) {
+    if (config == null) {
+        throw new IllegalArgumentException("WebSocketEngineConfig cannot be null");
+    }
     this.config = config;
 }

13-26: Consider adding exception handling.

The create method doesn't handle any exceptions that might occur during the setup process, such as IllegalArgumentException for invalid URLs or SSLException for SSL configuration issues. Consider wrapping the method body in a try-catch block and throwing a more specific exception that aligns with the WebSocketEngine interface.

Here's a suggested implementation:

 @Override
 public WebSocketClient create(String url, WebSocketListener listener) {
+    try {
         OkHttpClient.Builder connectionBuilder = new OkHttpClient.Builder();
         Request.Builder requestBuilder = new Request.Builder().url(url);
         OkHttpUtils.injectProxySetting(config.getProxy(), connectionBuilder);
         if (config.getSslSocketFactory() != null) {
             connectionBuilder.sslSocketFactory(config.getSslSocketFactory());
         }
         return new OkHttpWebSocketClient(connectionBuilder.build(), requestBuilder.build(), listener);
+    } catch (IllegalArgumentException e) {
+        throw new WebSocketException("Invalid URL: " + url, e);
+    } catch (Exception e) {
+        throw new WebSocketException("Failed to create WebSocket client", e);
+    }
 }
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpCall.java (1)

19-39: LGTM: Well-implemented execute() method with robust error handling.

The execute() method is well-implemented:

  • It correctly converts the OkHttp Response to the expected HttpResponse format.
  • The use of try-with-resources ensures proper resource management.
  • Exception handling is appropriate, distinguishing between connection-related issues and other IOExceptions.
  • Null checks for response body and content type are good practices.

Consider extracting the HttpResponse building logic into a separate private method for better readability and maintainability. For example:

private HttpResponse buildHttpResponse(Response response) throws IOException {
    return HttpResponse.builder()
        .headers(response.headers().toMultimap())
        .code(response.code())
        .message(response.message())
        .body(
            response.body() != null && response.body().contentType() != null
                ? new HttpBody(response.body().contentType().toString(), response.body().bytes())
                : null
        )
        .build();
}

Then, you can simplify the execute() method:

@Override
public HttpResponse execute() {
    try (Response response = call.execute()) {
        return buildHttpResponse(response);
    } catch (ConnectException | SocketTimeoutException | UnknownHostException | NoRouteToHostException fce) {
        throw new FailedConnectionException(fce);
    } catch (IOException ioe) {
        throw new RuntimeException(ioe);
    }
}
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java (2)

30-50: LGTM: Well-implemented conversion method with minor improvement suggestions.

The toOkhttpRequest method effectively converts a custom HttpRequest to an OkHttp Request. It correctly handles the URL, method, body, and headers.

Some minor suggestions for improvement:

  1. Consider adding null checks for the request parameter and its components (url, method) to prevent NullPointerExceptions.
  2. You might want to handle potential exceptions when parsing the content type.

Here's a suggested improvement:

 public static Request toOkhttpRequest(HttpRequest request) {
+    if (request == null || request.getUrl() == null || request.getMethod() == null) {
+        throw new IllegalArgumentException("Request, URL, and method must not be null");
+    }
     Request.Builder builder = new Request.Builder()
         .url(request.getUrl());

     RequestBody body = null;

     if (request.getBody() != null) {
-        body = RequestBody.create(request.getBody().getContent(), MediaType.parse(request.getBody().getContentType()));
+        MediaType mediaType = null;
+        try {
+            mediaType = MediaType.parse(request.getBody().getContentType());
+        } catch (IllegalArgumentException e) {
+            // Log the error or use a default media type
+        }
+        body = RequestBody.create(request.getBody().getContent(), mediaType);
     }

     builder.method(request.getMethod(), body);
     for (Map.Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
         String headerName = entry.getKey();
         List<String> values = entry.getValue();
         for (String headerValue : values) {
             builder.addHeader(headerName, headerValue);
         }
     }

     return builder.build();
 }

These changes add null checks and handle potential exceptions when parsing the content type, making the method more robust.


1-51: Overall, good implementation with some areas for improvement.

The OkHttpUtils class provides useful utility methods for working with the OkHttp library. Here's a summary of the review:

  1. The injectProxySetting method has a critical logical error that needs to be fixed. Additionally, consider implementing support for different proxy types and authentication methods.

  2. The toOkhttpRequest method is well-implemented but could benefit from additional null checks and exception handling for improved robustness.

  3. The overall structure and organization of the class are good, with clear separation of concerns between the two main methods.

Please address the issues in injectProxySetting and consider implementing the suggested improvements for both methods to enhance the overall quality and reliability of this utility class.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java (1)

10-19: LGTM: Fields and constructor are well-structured.

The use of final fields for dependencies is a good practice. The constructor properly initializes all final fields, and the webSocket field is correctly left mutable for later initialization.

Consider adding JavaDoc comments for the class and constructor to improve code documentation:

/**
 * OkHttp implementation of the WebSocketClient interface.
 */
public class OkHttpWebSocketClient implements WebSocketClient {
    // ... fields ...

    /**
     * Constructs an OkHttpWebSocketClient with the specified OkHttpClient, Request, and WebSocketListener.
     *
     * @param connection The OkHttpClient to use for the WebSocket connection.
     * @param request The Request object containing the WebSocket URL and headers.
     * @param listener The WebSocketListener to handle WebSocket events.
     */
    public OkHttpWebSocketClient(OkHttpClient connection, Request request, WebSocketListener listener) {
        // ... constructor body ...
    }
}
gradle/libs.versions.toml (1)

42-42: LGTM: OkHttp library declared correctly

The OkHttp library is correctly declared with the proper group, name, and version reference.

Consider adding OkHttp to the common bundle if it's going to be used across multiple modules:

 [bundles]
-common = ["msgpack", "vcdiff-core"]
+common = ["msgpack", "vcdiff-core", "okhttp"]

This would make it easier to include OkHttp in multiple build files with a single reference.

README.md (3)

503-517: LGTM! Consider adding a version check recommendation.

The new section provides clear instructions for adding the OkHttp dependency for proxy support. This is a valuable addition to the README.

Consider adding a note recommending users to check for the latest version of the network-client-okhttp dependency, as library versions may change over time.


525-562: LGTM! Comprehensive example for proxy configuration.

The Java example provided is clear, well-commented, and covers both REST and Realtime client configurations. It also includes optional proxy authentication, which is valuable for users with authenticated proxies.

Consider adding a brief comment explaining that users should replace the placeholder values (e.g., "your-proxy-host", "your-username") with their actual proxy details. This will help prevent confusion for less experienced users.


564-572: LGTM! Useful additional resources provided.

The additional resources section provides relevant links that will be helpful for users seeking more information about the Ably SDK, OkHttp, and proxy servers in general.

Consider adding a link to Ably's documentation specifically about proxy configuration, if such a page exists. This would provide users with more Ably-specific information about using proxies with the SDK.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6f38c17 and e53b6e7.

📒 Files selected for processing (13)
  • README.md (1 hunks)
  • gradle/libs.versions.toml (2 hunks)
  • network-client-default/build.gradle.kts (1 hunks)
  • network-client-okhttp/build.gradle.kts (1 hunks)
  • network-client-okhttp/gradle.properties (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpCall.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngineFactory.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngineFactory.java (1 hunks)
  • settings.gradle.kts (1 hunks)
🔇 Additional comments not posted (26)
settings.gradle.kts (1)

16-16: LGTM: New module added successfully.

The addition of the "network-client-okhttp" module is in line with the PR objectives to implement OkHttp for HTTP calls and WebSocket connections. The placement of the new module is logical and consistent with the existing structure.

Let's verify if there are corresponding build files for the new module:

✅ Verification successful

Verified: Build configuration file exists for "network-client-okhttp".
The presence of build.gradle.kts in the network-client-okhttp module ensures proper build setup.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for the existence of build files for the new module

# Test: Check if build.gradle.kts exists for the new module
fd -t f "build.gradle.kts" network-client-okhttp

# Test: Check if build.gradle exists for the new module (in case Groovy DSL is used)
fd -t f "build.gradle" network-client-okhttp

# If neither file is found, it might indicate missing build configuration

Length of output: 171

network-client-default/build.gradle.kts (1)

13-13: Verify impact of dependency scope change on consumer modules

The change from api to implementation for the network-client-core dependency improves encapsulation and potentially build performance. However, it may break existing code in modules that depend on network-client-default if they were directly using classes from network-client-core.

Please run the following script to identify potential issues:

This change enhances modularity but may require updates in consumer modules. Please review the script output and update any affected modules to directly depend on network-client-core if necessary.

Consider documenting this architectural change in the project's changelog or migration guide, as it may require action from developers using this module.

✅ Verification successful

Dependency scope change verified and safe

The change from api to implementation for the network-client-core dependency does not affect any consumer modules. No additional dependencies on network-client-core were found outside the network-client-default module.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for usage of network-client-core classes in other modules

# Find all Java and Kotlin files outside the network-client-core and network-client-default directories
files=$(fd -e java -e kt . --exclude 'network-client-core' --exclude 'network-client-default')

# Search for imports of network-client-core classes in these files
echo "Checking for imports of network-client-core classes in other modules:"
rg "import.*network\.client\.core" $files

# If any results are found, they will be displayed above
echo "If any results are shown above, those files may need to be updated to directly depend on network-client-core."

Length of output: 23655

network-client-okhttp/build.gradle.kts (1)

1-5: LGTM: Appropriate plugins are applied.

The plugins section is well-structured:

  • The java-library plugin is correctly applied for a library project.
  • Using aliases for Lombok and Maven Publish plugins is a good practice for version management.
network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngineFactory.java (3)

1-3: LGTM: Class structure and package declaration are appropriate.

The OkHttpWebSocketEngineFactory class is well-structured and correctly implements the WebSocketEngineFactory interface. The naming convention clearly indicates its purpose, and the package declaration is consistent with the file path.


9-12: LGTM: getEngineType method implementation is correct and concise.

The getEngineType method correctly returns the appropriate EngineType.OKHTTP value, adhering to the interface contract.


1-13: Overall, excellent implementation of OkHttpWebSocketEngineFactory.

The class successfully implements the WebSocketEngineFactory interface for OkHttp, providing clean and concise methods for creating WebSocket engines and identifying the engine type. The code is well-structured and easy to understand, making it a solid addition to the io.ably.lib.network package.

A minor suggestion was made to add a null check in the create method, but otherwise, the implementation is robust and follows good coding practices.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngineFactory.java (2)

1-5: LGTM: Class structure and package declaration are correct.

The OkHttpEngineFactory class is properly structured, implements the HttpEngineFactory interface, and is in the correct package. The import statement for OkHttpClient is appropriate for its usage.


13-16: LGTM: getEngineType method is correctly implemented.

The getEngineType method properly overrides the interface method and returns the correct engine type (EngineType.OKHTTP). The implementation is simple and effective.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (2)

1-7: LGTM: Class structure and imports are well-defined.

The class structure is appropriate for implementing a WebSocket engine using OkHttp. The use of a configuration object (WebSocketEngineConfig) allows for flexible setup, which is a good practice. The imports are correctly specified and relevant to the class functionality.


13-26: LGTM: The create method is well-implemented.

The method correctly sets up the OkHttpClient with the provided configuration, including proxy settings and SSL socket factory. The use of builder pattern for both OkHttpClient and Request is a good practice.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngine.java (4)

1-7: LGTM: Import statements are appropriate.

The import statements are concise and relevant to the class functionality. Good job on keeping the imports clean and focused.


8-16: LGTM: Class declaration and fields are well-structured.

The OkHttpEngine class correctly implements the HttpEngine interface. The private final fields client and config are appropriately encapsulated. The constructor properly initializes these fields.


28-31: LGTM: isUsingProxy method is correctly implemented.

The isUsingProxy method is simple and effective. It correctly checks the config object to determine if a proxy is being used.


1-32: Overall, the OkHttpEngine implementation is solid with room for minor improvements.

The OkHttpEngine class provides a good implementation of the HttpEngine interface using the OkHttp library. The code is well-structured and follows good practices such as proper encapsulation and use of utility methods.

Key points:

  1. The import statements and class structure are clean and appropriate.
  2. The isUsingProxy method is correctly implemented.
  3. The call method is functional but could benefit from optimization and error handling as suggested in the previous comment.

Consider implementing the suggested improvements to enhance the robustness and efficiency of the call method. Otherwise, the implementation is sound and ready for use.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpCall.java (4)

1-10: LGTM: Imports are appropriate and concise.

The imports are well-organized and include all necessary classes for the implementation. There are no unused imports.


12-17: LGTM: Class structure is well-designed.

The OkHttpCall class has a good structure:

  • It implements the HttpCall interface, promoting loose coupling.
  • It uses dependency injection through the constructor, which is a good practice for testability and flexibility.
  • The call field is correctly marked as private final, ensuring encapsulation and immutability.

41-44: LGTM: Simple and correct cancel() method implementation.

The cancel() method is implemented correctly:

  • It properly delegates the cancellation to the underlying OkHttp Call object.
  • The implementation is simple and straightforward, which is appropriate for this method.

1-45: Overall, excellent implementation of OkHttpCall.

The OkHttpCall class provides a solid implementation of the HttpCall interface using the OkHttp library. Key strengths include:

  1. Good class structure with proper interface implementation and dependency injection.
  2. Robust error handling in the execute() method.
  3. Correct use of try-with-resources for proper resource management.
  4. Appropriate null checks and exception handling.

The implementation successfully bridges the gap between the HttpCall interface and the OkHttp library, providing the necessary functionality for making HTTP calls in the Ably SDK.

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java (2)

1-14: LGTM: Import statements are appropriate and concise.

The import statements are well-organized and include all necessary classes for the functionality provided by this utility class.


16-28: ⚠️ Potential issue

Fix logical error and consider improvements in proxy configuration.

There are several issues and potential improvements in this method:

  1. There's a logical error in the first condition check. It should return if proxyConfig is null, not if it's not null.
  2. The proxy type is hardcoded to HTTP. Consider allowing different proxy types.
  3. The method doesn't handle cases where the proxy authentication type is not BASIC.

Here's a suggested improvement:

 public static void injectProxySetting(ProxyConfig proxyConfig, OkHttpClient.Builder connectionBuilder) {
-    if (proxyConfig != null) return;
+    if (proxyConfig == null) return;
-    connectionBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyConfig.getHost(), proxyConfig.getPort())));
+    Proxy.Type proxyType = proxyConfig.getType() != null ? proxyConfig.getType() : Proxy.Type.HTTP;
+    connectionBuilder.proxy(new Proxy(proxyType, new InetSocketAddress(proxyConfig.getHost(), proxyConfig.getPort())));
-    if (proxyConfig.getUsername() == null || proxyConfig.getAuthType() != ProxyAuthType.BASIC) return;
+    if (proxyConfig.getUsername() == null) return;
+    switch (proxyConfig.getAuthType()) {
+        case BASIC:
             String username = proxyConfig.getUsername();
             String password = proxyConfig.getPassword();
             connectionBuilder.proxyAuthenticator((route, response) -> {
@@ -25,6 +27,9 @@ public static void injectProxySetting(ProxyConfig proxyConfig, OkHttpClient.Buil
                     .header("Proxy-Authorization", credential)
                     .build();
             });
+            break;
+        // Add cases for other authentication types if needed
+    }
 }

This improvement fixes the logical error, allows for different proxy types, and provides a structure to handle different authentication types in the future.

To ensure that the ProxyConfig class has the necessary methods and fields, please run the following script:

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java (3)

1-9: LGTM: Imports and class declaration look good.

The imports are appropriate for the OkHttp WebSocket implementation, and the class structure follows Java conventions. The OkHttpWebSocketClient implementing the WebSocketClient interface indicates good design practices, allowing for potential alternative implementations.


42-50: LGTM: Send methods are implemented correctly.

The send methods for both byte arrays and strings are implemented correctly, using the appropriate WebSocket send methods. The use of ByteString.of(bytes) for sending byte arrays is an efficient approach.


1-85: Overall, excellent implementation of OkHttpWebSocketClient.

The OkHttpWebSocketClient class provides a robust and well-structured implementation of the WebSocketClient interface using the OkHttp library. The code follows good practices, such as immutability where possible, proper event delegation, and correct use of the OkHttp WebSocket API.

The suggested improvements, including enhanced documentation, slight modification to the cancel method, and more detailed error handling, are minor and can be easily incorporated to further enhance the quality of the implementation.

Great job on creating a solid foundation for WebSocket communication in the Ably SDK!

gradle/libs.versions.toml (1)

20-20: LGTM: OkHttp version added correctly

The addition of OkHttp version 4.12.0 is appropriate. This is the latest stable version, which is a good choice for new implementations.

README.md (2)

519-523: LGTM! Clear explanation of proxy configuration.

This segment effectively explains how to configure proxy settings using the ClientOptions object after adding the OkHttp dependency. The information is accurate and well-connected to the previous step.


503-572: Excellent addition to the README!

The new section on using the Ably SDK under a proxy is a valuable addition to the documentation. It provides clear instructions, a comprehensive example, and relevant resources. This information will be particularly useful for users working in restricted network environments.

The structure and content of the new section align well with the rest of the README, maintaining consistency in style and depth of information.

@ttypic ttypic force-pushed the ECO-4208/proxy-support-okhttp branch from e53b6e7 to 30b7385 Compare September 27, 2024 12:16
@github-actions github-actions bot temporarily deployed to staging/pull/1035/features September 27, 2024 12:17 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc September 27, 2024 12:18 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Outside diff range and nitpick comments (5)
network-client-core/gradle.properties (1)

1-4: LGTM! Consider enhancing the POM_DESCRIPTION.

The Gradle properties file is well-structured and contains appropriate values for the network-client-core module. The artifact ID, name, and packaging type are correctly specified.

Consider expanding the POM_DESCRIPTION to provide more detailed information about the module's purpose and functionality. This could help differentiate it from the POM_NAME and offer more context to developers. For example:

 POM_ARTIFACT_ID=network-client-core
 POM_NAME=Core HTTP client abstraction
-POM_DESCRIPTION=Core HTTP client abstraction
+POM_DESCRIPTION=Core abstraction layer for HTTP client implementations, providing a unified interface for making HTTP requests and WebSocket connections
 POM_PACKAGING=jar
network-client-core/build.gradle.kts (1)

1-4: LGTM! Consider adding publication configuration.

The addition of the Maven Publish plugin is appropriate for this library module. It aligns with the PR objectives by enabling the publication of the enhanced network client core, which now includes expanded proxy support.

To fully utilize the Maven Publish plugin, consider adding a publishing block to configure the publication details. For example:

publishing {
    publications {
        create<MavenPublication>("maven") {
            from(components["java"])
            groupId = "com.your.group"
            artifactId = "network-client-core"
            version = "1.0.0" // Or use a version variable
        }
    }
}

This configuration will ensure that when you publish, the artifact details are correctly set.

README.md (2)

515-515: Ensure consistency in version numbers across the README.

The version number for the OkHttp dependency (1.2.43) is different from the version mentioned in the installation section (1.2.42). Consider updating all version references to ensure consistency throughout the document.


563-563: Consider adding troubleshooting information for proxy usage.

While the instructions for setting up proxy configuration are clear, it might be helpful to include some common troubleshooting steps or potential issues users might encounter when using the SDK behind a proxy. This could help users quickly resolve any problems they face during implementation.

lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (1)

64-64: Improve Method Naming Convention

The method isSupportPingListener() might be better named supportsPingListener() to adhere to standard Java naming conventions for boolean methods. This enhances readability and makes the code more intuitive.

Consider renaming the method:

- params.heartbeats = !this.webSocketEngine.isSupportPingListener();
+ params.heartbeats = !this.webSocketEngine.supportsPingListener();
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between e53b6e7 and 30b7385.

📒 Files selected for processing (19)
  • README.md (1 hunks)
  • gradle/libs.versions.toml (2 hunks)
  • lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (4 hunks)
  • network-client-core/build.gradle.kts (1 hunks)
  • network-client-core/gradle.properties (1 hunks)
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngine.java (1 hunks)
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngineFactory.java (1 hunks)
  • network-client-default/build.gradle.kts (1 hunks)
  • network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java (1 hunks)
  • network-client-okhttp/build.gradle.kts (1 hunks)
  • network-client-okhttp/gradle.properties (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpCall.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngineFactory.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngineFactory.java (1 hunks)
  • settings.gradle.kts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (11)
  • gradle/libs.versions.toml
  • network-client-default/build.gradle.kts
  • network-client-okhttp/build.gradle.kts
  • network-client-okhttp/gradle.properties
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpCall.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngine.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpEngineFactory.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketClient.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngineFactory.java
  • settings.gradle.kts
🧰 Additional context used
🪛 ast-grep
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java

[warning] 79-79: 'An insecure SSL context was detected. TLS versions 1.0, 1.1, and all
SSL versions are considered weak encryption and are deprecated. Use
SSLContext.getInstance("TLSv1.2") for the best security.'
Context: SSLContext.getInstance("TLS")
Note: [CWE-326] Inadequate Encryption Strength [REFERENCES]
- https://tools.ietf.org/html/rfc7568
- https://tools.ietf.org/id/draft-ietf-tls-oldversions-deprecate-02.html

🔇 Additional comments (8)
network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java (1)

21-24: New method added to support ping listener functionality.

The isSupportPingListener() method has been added to the DefaultWebSocketEngine class, implementing the WebSocketEngine interface. This method always returns true, indicating that this WebSocket engine supports ping listener functionality.

Consider the following points:

  1. The method name follows the Java naming convention for boolean methods (starts with "is").
  2. The implementation is straightforward and consistent.
  3. This addition might impact how ping operations are handled in the WebSocket communication.

To ensure this change is consistent with the interface and other implementations, let's verify the WebSocketEngine interface and check for other implementations:

✅ Verification successful

Verification Complete: No Issues Found

The isSupportPingListener() method in DefaultWebSocketEngine correctly implements the WebSocketEngine interface and is consistent with other implementations. No issues detected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify WebSocketEngine interface and its implementations

# Check the WebSocketEngine interface
echo "Checking WebSocketEngine interface:"
rg --type java -A 5 "interface WebSocketEngine"

# Find other implementations of WebSocketEngine
echo "Finding other WebSocketEngine implementations:"
rg --type java -A 5 "class \w+ implements WebSocketEngine"

Length of output: 4471

network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (4)

1-11: LGTM: Class declaration and constructor are well-implemented.

The class structure is appropriate, implementing the WebSocketEngine interface. The use of a final field for configuration ensures immutability, which is a good practice. The constructor correctly initializes the configuration.


13-26: LGTM: The create method is well-implemented.

The method correctly sets up the OkHttpClient and Request, applies proxy settings, and conditionally sets the SSL socket factory. This implementation provides the necessary flexibility for different configurations.


28-31: Verify if lack of ping listener support is intentional.

The isSupportPingListener method always returns false, indicating that this WebSocket engine does not support a ping listener. Please confirm if this is intentional or if ping support should be implemented.


19-19: Verify the implementation of OkHttpUtils.injectProxySetting.

A previous review comment highlighted a potential logical error in the injectProxySetting method. Please ensure that this method is correctly implemented to apply proxy settings when a valid proxyConfig is provided.

Run the following script to verify the implementation:

✅ Verification successful

Verification Successful: OkHttpUtils.injectProxySetting is correctly implemented.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the implementation of OkHttpUtils.injectProxySetting

# Test: Search for the method implementation
rg -A 10 'void injectProxySetting' network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpUtils.java

Length of output: 877

network-client-core/src/main/java/io/ably/lib/network/WebSocketEngineFactory.java (1)

19-19: LGTM! Verify consistency across the codebase.

The class name change from "OkWebSocketEngineFactory" to "OkHttpWebSocketEngineFactory" aligns with the PR objective of implementing OkHttp for WebSocket connections. This change provides more clarity about the underlying implementation.

To ensure consistency across the codebase, please run the following verification script:

Consider adding a comment explaining the use of reflection here. For example:

// Use reflection to load the OkHttp WebSocket engine factory if available
Class<?> okWebSocketFactoryClass = Class.forName("io.ably.lib.network.OkHttpWebSocketEngineFactory");

This would improve code maintainability by clarifying the purpose of this reflection-based approach.

✅ Verification successful

Verification Successful!

The class OkHttpWebSocketEngineFactory has been correctly renamed and all references to OkWebSocketEngineFactory have been updated across the codebase. No inconsistencies or leftover references were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the class name change consistency and usage

# Check if the new class exists
echo "Checking for the new OkHttpWebSocketEngineFactory class:"
fd --type f --extension java OkHttpWebSocketEngineFactory.java

# Search for any remaining references to the old class name
echo "Searching for any remaining references to OkWebSocketEngineFactory:"
rg --type java "OkWebSocketEngineFactory"

# Search for usages of the new class name
echo "Searching for usages of OkHttpWebSocketEngineFactory:"
rg --type java "OkHttpWebSocketEngineFactory"

Length of output: 991

README.md (1)

503-563: LGTM: Clear and comprehensive instructions for proxy configuration.

The new section on using the Ably SDK under a proxy is well-structured and provides clear instructions. The Java example is comprehensive and demonstrates both REST and Realtime usage, which is helpful for users.

lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (1)

63-67: Good Refactoring for Code Maintainability

Extracting the WebSocket engine creation into a separate method createWebSocketEngine enhances code organization and readability. This refactoring simplifies the constructor and promotes better maintainability.

Copy link
Collaborator

@sacOO7 sacOO7 left a comment

Choose a reason for hiding this comment

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

Can we add integration tests for OkHttp proxy?
Also, it will be great if we can have OkHttp integration tests running ( for both rest and realtime ) by enabling some type of flag on CI ?

@github-actions github-actions bot temporarily deployed to staging/pull/1035/features October 3, 2024 10:20 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc October 3, 2024 10:21 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (7)
build.gradle.kts (1)

10-10: LGTM. Consider documenting the purpose of the test retry plugin.

The addition of the test.retry plugin is a good choice for a network-focused project, as it can help manage flaky tests often associated with network operations. This aligns well with the PR's focus on implementing OkHttp for HTTP and WebSocket connections.

Consider adding a brief comment explaining the purpose of this plugin and how it should be used in subprojects. This will help other developers understand its intended use in the context of your project.

.github/workflows/integration-test.yml (3)

52-65: LGTM! Consider adding an artifact upload step.

The new check-rest-okhttp job is well-structured and consistent with the existing jobs. The use of the -Pokhttp flag aligns with the PR objectives to implement OkHttp for HTTP calls.

Consider adding an artifact upload step similar to the check-rest job for consistency and to preserve build reports:

- uses: actions/upload-artifact@v3
  if: always()
  with:
    name: java-build-reports-rest-okhttp
    path: java/build/reports/

67-80: LGTM! Consider adding an artifact upload step.

The new check-realtime-okhttp job is well-structured and consistent with the existing jobs. The use of the -Pokhttp flag aligns with the PR objectives to implement OkHttp for WebSocket connections.

Consider adding an artifact upload step similar to the check-realtime job for consistency and to preserve build reports:

- uses: actions/upload-artifact@v3
  if: always()
  with:
    name: java-build-reports-realtime-okhttp
    path: java/build/reports/

52-80: Great job on maintaining consistency across jobs!

The new check-rest-okhttp and check-realtime-okhttp jobs are well-aligned with the existing jobs in terms of structure and setup. This consistency is excellent for maintainability.

As the number of jobs increases, you might want to consider parallelizing them or using a matrix strategy if build times become an issue. This could potentially reduce the overall workflow execution time.

Also, ensure that adding these new jobs doesn't significantly increase the total CI time, which could impact developer productivity. Monitor the workflow execution times and optimize if necessary.

java/build.gradle.kts (3)

24-28: LGTM: Flexible network client configuration

The conditional logic for including either the default or OkHttp-based network client is a good approach. It allows for flexible configuration and gradual adoption of the new OkHttp implementation.

Consider adding a comment explaining how to enable the OkHttp client, for example:

// To use the OkHttp client, set the "okhttp" property when running Gradle
// e.g., ./gradlew build -Pokhttp
if (findProperty("okhttp") == null) {
    runtimeOnly(project(":network-client-default"))
} else {
    runtimeOnly(project(":network-client-okhttp"))
}

This will make it easier for developers to understand how to switch between implementations.


67-72: LGTM: Retry configuration for testRealtimeSuite

The addition of retry logic to the testRealtimeSuite task is a good improvement. It will help manage potentially flaky tests, which is particularly important for network-related tests like WebSocket connections.

Consider adding a comment explaining the retry strategy:

retry {
    // Retry up to 2 times, allowing a maximum of 4 failures
    // Don't fail if a test passes or is skipped after a retry
    maxRetries.set(2)
    maxFailures.set(4)
    failOnPassedAfterRetry.set(false)
    failOnSkippedAfterRetry.set(false)
}

This will help other developers understand the rationale behind these settings.


86-91: LGTM: Retry configuration for testRestSuite

The addition of retry logic to the testRestSuite task is consistent with the testRealtimeSuite task, which is good. However, there's an opportunity to reduce code duplication here.

Consider refactoring the retry configuration into a separate function:

fun Test.addRetryConfig() {
    retry {
        maxRetries.set(2)
        maxFailures.set(4)
        failOnPassedAfterRetry.set(false)
        failOnSkippedAfterRetry.set(false)
    }
}

tasks.register<Test>("testRealtimeSuite") {
    // ... other configurations ...
    addRetryConfig()
}

tasks.register<Test>("testRestSuite") {
    // ... other configurations ...
    addRetryConfig()
}

This refactoring will make it easier to maintain consistent retry configurations across different test tasks.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 30b7385 and 0718012.

📒 Files selected for processing (4)
  • .github/workflows/integration-test.yml (1 hunks)
  • build.gradle.kts (1 hunks)
  • gradle/libs.versions.toml (3 hunks)
  • java/build.gradle.kts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • gradle/libs.versions.toml
🔇 Additional comments (2)
java/build.gradle.kts (2)

6-6: LGTM: Test retry plugin added

The addition of the test retry plugin is a good improvement. It will help manage flaky tests and improve the reliability of the CI/CD pipeline, which is especially important when dealing with network-related tests like those for HTTP and WebSocket connections.


Line range hint 1-91: Overall assessment: Well-structured changes that align with PR objectives

The modifications to build.gradle.kts effectively support the implementation of OkHttp for HTTP calls and WebSocket connections, while also enhancing the testing framework. The changes include:

  1. Addition of the test retry plugin
  2. Flexible configuration for network client implementation
  3. Retry configurations for both Realtime and REST test suites

These changes contribute positively to the project's goals of expanding proxy support and improving test reliability. The suggestions provided in the review comments, if implemented, will further enhance code clarity and maintainability.

@github-actions github-actions bot temporarily deployed to staging/pull/1035/features October 3, 2024 11:26 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc October 3, 2024 11:26 Inactive
@ttypic ttypic force-pushed the ECO-4208/proxy-support-okhttp branch from 9661a9c to 0718012 Compare October 3, 2024 11:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (4)
android/src/androidTest/java/io/ably/lib/test/RetryTestRule.java (1)

8-13: Consider improving field name and comment clarity.

The implementation looks good, but there are a couple of suggestions for improvement:

  1. The field name timesToRunTestCount could be more descriptive. Consider renaming it to maxAttempts or maxExecutions to better reflect its purpose.

  2. The comment could be more explicit. Consider updating it to:

    /**
     * Represents the maximum number of times a test will be executed.
     * If the constructor parameter 'times' is 0, this will be set to 1,
     * meaning the test will run once without retries.
     */

These changes would enhance the readability and maintainability of the code.

android/src/androidTest/java/io/ably/lib/test/android/AndroidPushTest.java (3)

Line range hint 1-1004: Consider refactoring long test methods

Some test methods in this file are quite long and complex. For example, the push_activate() method starting at line 183 is over 100 lines long. Consider refactoring these methods into smaller, more focused test cases or extracting common setup code into helper methods. This would improve readability and maintainability of the tests.


Line range hint 365-367: Review and enable or remove commented-out test

There's a commented-out test case (RSH3a2a) with a note about an issue (#739). Consider reviewing this test, and either enable it if the issue has been resolved, or remove it if it's no longer relevant. Keeping commented-out code can lead to confusion and clutter in the long run.


Line range hint 8-8: Update deprecated Android test runner

The file is using android.support.test.runner.AndroidJUnit4, which is part of the deprecated Android Support Library. Consider updating to the AndroidX test libraries and using androidx.test.ext.junit.runners.AndroidJUnit4 instead. This will ensure better compatibility with newer Android versions and access to the latest testing features.

🛑 Comments failed to post (3)
android/src/androidTest/java/io/ably/lib/test/RetryTestRule.java (3)

14-20: 🛠️ Refactor suggestion

Consider clarifying constructor logic.

The constructors are well-implemented, but the logic in the parameterized constructor could be more explicit:

public RetryTestRule(int times) {
    this.timesToRunTestCount = Math.max(1, times + 1);
}

This change ensures that timesToRunTestCount is always at least 1, making the logic more robust and eliminating the need for the comment about times = 0.


22-25: 🛠️ Refactor suggestion

Consider simplifying the apply method.

The current implementation of the apply method is correct, but it can be simplified:

@Override
public Statement apply(Statement base, Description description) {
    return new Statement() {
        @Override
        public void evaluate() throws Throwable {
            // ... (rest of the logic from the current `statement` method)
        }
    };
}

This change eliminates the need for the separate statement method, making the code more concise and easier to follow.


27-51: ⚠️ Potential issue

Fix string interpolation and improve error messages.

The retry logic is well-implemented, but there are a few issues to address:

  1. The error messages use string interpolation syntax that's not valid in Java. Use String.format() or StringBuilder instead.
  2. The variable runCount is not defined. Use the loop variable i instead.
  3. The error messages could be more informative.

Here's a suggested improvement:

private Statement statement(Statement base, Description description) {
    return new Statement() {
        @Override
        public void evaluate() throws Throwable {
            Throwable latestException = null;

            for (int i = 0; i < timesToRunTestCount; i++) {
                try {
                    base.evaluate();
                    return;
                } catch (Throwable t) {
                    latestException = t;
                    System.err.println(String.format("%s: test failed on attempt %d of %d",
                        description.getMethodName(), i + 1, timesToRunTestCount));
                    t.printStackTrace();
                }
            }

            if (latestException != null) {
                System.err.println(String.format("%s: giving up after %d attempts",
                    description.getDisplayName(), timesToRunTestCount));
                throw latestException;
            }
        }
    };
}

These changes correct the string interpolation issues, use the correct variables, and provide more precise error messages.

@github-actions github-actions bot temporarily deployed to staging/pull/1035/features October 3, 2024 11:32 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc October 3, 2024 11:33 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/features October 3, 2024 16:59 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/1035/javadoc October 3, 2024 16:59 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (1)

177-185: LGTM with a suggestion: Method to disable activity checks for testing

The turnOffActivityCheckIfPingListenerIsNotSupported method provides a useful way to disable activity checks for specific test scenarios. This can be valuable for testing edge cases and ensuring proper behavior under various conditions.

Consider adding a safeguard to ensure this method is only called in test environments:

protected void turnOffActivityCheckIfPingListenerIsNotSupported() {
+   if (!isTestEnvironment()) {
+       Log.w(TAG, "Attempting to turn off activity check in non-test environment");
+       return;
+   }
    if (!webSocketEngine.isPingListenerSupported()) activityCheckTurnedOff = true;
}

+ private boolean isTestEnvironment() {
+     // Implement logic to determine if running in a test environment
+     // For example, checking for a specific system property or environment variable
+ }

This addition would prevent accidental usage in production environments.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 9661a9c and f75ca55.

📒 Files selected for processing (5)
  • lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (6 hunks)
  • lib/src/test/java/io/ably/lib/test/util/MockWebsocketFactory.java (1 hunks)
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngine.java (1 hunks)
  • network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngine.java
  • network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java
🧰 Additional context used
📓 Learnings (1)
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (1)
Learnt from: ttypic
PR: ably/ably-java#1035
File: lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java:110-110
Timestamp: 2024-10-03T10:38:33.504Z
Learning: In the `WebSocketTransport` constructor, synchronization is not necessary when initializing `webSocketClient` because it's not accessed by multiple threads at that point.
🪛 ast-grep
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java

[warning] 80-80: 'An insecure SSL context was detected. TLS versions 1.0, 1.1, and all
SSL versions are considered weak encryption and are deprecated. Use
SSLContext.getInstance("TLSv1.2") for the best security.'
Context: SSLContext.getInstance("TLS")
Note: [CWE-326] Inadequate Encryption Strength [REFERENCES]
- https://tools.ietf.org/html/rfc7568
- https://tools.ietf.org/id/draft-ietf-tls-oldversions-deprecate-02.html

🔇 Additional comments (4)
lib/src/test/java/io/ably/lib/test/util/MockWebsocketFactory.java (1)

158-158: Approved, but please provide more context.

The addition of turnOffActivityCheckIfPingListenerIsNotSupported() seems to be a deliberate change to handle a specific case in the mock WebSocket behavior. This change is likely beneficial for certain test scenarios.

However, to ensure clarity and maintainability:

  1. Could you provide more information about the purpose and impact of this change? Specifically:

    • What prompted the need for this addition?
    • How does it affect the behavior of the mock WebSocket in tests?
  2. Consider adding a comment above this line to explain its purpose and when it's necessary. This will help other developers understand the reasoning behind this call.

To better understand the context of this change, could you run the following command to find where this method is defined and how it's used elsewhere in the codebase?

✅ Verification successful

To gain a clearer understanding of the turnOffActivityCheckIfPingListenerIsNotSupported method's role and its usage within the codebase, please execute the following command:


Change Verified Successfully

The addition of turnOffActivityCheckIfPingListenerIsNotSupported() in MockWebsocketFactory.java is appropriate and effectively mocks the specific behavior related to activity checks when ping listeners are not supported. This change is localized to the test utilities and does not impact other parts of the codebase.

  • No additional usages of the method were found outside the test file and its definition, ensuring no unintended side effects.
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for the definition and usage of turnOffActivityCheckIfPingListenerIsNotSupported
rg --type java -e "turnOffActivityCheckIfPingListenerIsNotSupported" -g "!test"

Length of output: 215


Script:

# Search for all usages of turnOffActivityCheckIfPingListenerIsNotSupported
rg --type java -e "turnOffActivityCheckIfPingListenerIsNotSupported"

Length of output: 334

lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (3)

21-22: LGTM: New imports for exception handling

The addition of KeyManagementException and NoSuchAlgorithmException imports is appropriate for the enhanced SSL/TLS handling in the createWebSocketEngine method.


54-56: LGTM: New fields for WebSocket engine and activity check control

The addition of webSocketEngine and activityCheckTurnedOff fields supports the new OkHttp implementation and provides flexibility in managing activity checks.


64-66: LGTM: Enhanced constructor with WebSocket engine initialization

The constructor now properly initializes the webSocketEngine and configures heartbeats based on the engine's capabilities. This change improves the flexibility and maintainability of the WebSocket transport implementation.

@ttypic ttypic force-pushed the ECO-4208/proxy-support-okhttp branch from f75ca55 to 1d04fc4 Compare October 3, 2024 19:23
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (5)
java/build.gradle.kts (2)

24-28: LGTM: Conditional network client dependency

The conditional logic for including either :network-client-default or :network-client-okhttp is well-implemented. This flexibility aligns with the PR objectives and allows for easy switching between implementations.

Consider adding a comment explaining the purpose of this conditional logic for better code readability. For example:

// Choose between default and OkHttp network client implementations
// Set the 'okhttp' property to use the OkHttp implementation
if (findProperty("okhttp") == null) {
    runtimeOnly(project(":network-client-default"))
} else {
    runtimeOnly(project(":network-client-okhttp"))
}

86-91: LGTM: Retry configuration added to testRestSuite

The addition of retry configuration to the testRestSuite task is consistent with the changes made to testRealtimeSuite. This ensures uniform behavior across different test suites, which is good for maintaining consistency in the testing process.

To reduce code duplication, consider extracting the retry configuration into a separate function or property that can be reused. For example:

val testRetryConfig: Action<TestRetryTaskExtension> = Action {
    maxRetries.set(3)
    maxFailures.set(8)
    failOnPassedAfterRetry.set(false)
    failOnSkippedAfterRetry.set(false)
}

tasks.register<Test>("testRealtimeSuite") {
    // ... other configurations ...
    retry(testRetryConfig)
}

tasks.register<Test>("testRestSuite") {
    // ... other configurations ...
    retry(testRetryConfig)
}

This approach would make it easier to maintain and update the retry configuration for all test tasks.

lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (3)

64-67: LGTM: Constructor updated to use centralized WebSocket engine creation

The changes to the constructor improve the initialization process by centralizing the WebSocket engine creation and configuration. This is a good practice for maintainability and flexibility.

Consider adding a comment explaining the logic behind setting params.heartbeats. For example:

// Enable heartbeats if the WebSocket engine doesn't support ping listeners
params.heartbeats = !this.webSocketEngine.isPingListenerSupported();

This would make the code more self-documenting.


177-185: Approve new activity check control with suggestions

The addition of turnOffActivityCheckIfPingListenerIsNotSupported and the corresponding change in flagActivity provide good flexibility for handling different WebSocket implementations, especially for testing scenarios.

However, consider the following improvements:

  1. The method name turnOffActivityCheckIfPingListenerIsNotSupported is quite long. Consider a shorter name like disableActivityCheckIfNeeded.

  2. Since this method is primarily for testing, consider using the @VisibleForTesting annotation to make its purpose clearer.

  3. In flagActivity, the condition !activityCheckTurnedOff could be renamed to something more positive like activityCheckEnabled for better readability.

Example:

@VisibleForTesting
protected void disableActivityCheckIfNeeded() {
    activityCheckEnabled = webSocketEngine.isPingListenerSupported();
}

// In flagActivity method:
if (activityTimerTask == null && connectionManager.maxIdleInterval != 0 && activityCheckEnabled) {
    // ... existing code ...
}

These changes would improve code readability and make the testing-related nature of the method more explicit.

Also applies to: 333-333


Line range hint 1-411: Overall assessment: Significant improvements with minor suggestions

The changes to WebSocketTransport.java represent a substantial improvement in WebSocket handling:

  1. Centralized WebSocket engine creation and configuration.
  2. Improved flexibility for different WebSocket implementations.
  3. Better testability with the new activity check control.

Key suggestions for improvement:

  1. Enhance TLS security by specifying a minimum version (TLSv1.2).
  2. Improve naming and documentation for the new activity check control method.
  3. Add explanatory comments for some of the new logic.

These changes align well with the PR objectives of expanding proxy support and enhancing WebSocket connections. They provide a solid foundation for the new OkHttp implementation while maintaining compatibility with other WebSocket engines.

🧰 Tools
🪛 ast-grep

[warning] 80-80: 'An insecure SSL context was detected. TLS versions 1.0, 1.1, and all
SSL versions are considered weak encryption and are deprecated. Use
SSLContext.getInstance("TLSv1.2") for the best security.'
Context: SSLContext.getInstance("TLS")
Note: [CWE-326] Inadequate Encryption Strength [REFERENCES]
- https://tools.ietf.org/html/rfc7568
- https://tools.ietf.org/id/draft-ietf-tls-oldversions-deprecate-02.html

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f75ca55 and 1d04fc4.

📒 Files selected for processing (8)
  • build.gradle.kts (1 hunks)
  • gradle/libs.versions.toml (3 hunks)
  • java/build.gradle.kts (4 hunks)
  • lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (6 hunks)
  • lib/src/test/java/io/ably/lib/test/util/MockWebsocketFactory.java (1 hunks)
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngine.java (1 hunks)
  • network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java (1 hunks)
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • build.gradle.kts
  • gradle/libs.versions.toml
  • lib/src/test/java/io/ably/lib/test/util/MockWebsocketFactory.java
  • network-client-core/src/main/java/io/ably/lib/network/WebSocketEngine.java
  • network-client-default/src/main/java/io/ably/lib/network/DefaultWebSocketEngine.java
  • network-client-okhttp/src/main/java/io/ably/lib/network/OkHttpWebSocketEngine.java
🧰 Additional context used
📓 Learnings (1)
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (1)
Learnt from: ttypic
PR: ably/ably-java#1035
File: lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java:110-110
Timestamp: 2024-10-03T10:38:33.504Z
Learning: In the `WebSocketTransport` constructor, synchronization is not necessary when initializing `webSocketClient` because it's not accessed by multiple threads at that point.
🪛 ast-grep
lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java

[warning] 80-80: 'An insecure SSL context was detected. TLS versions 1.0, 1.1, and all
SSL versions are considered weak encryption and are deprecated. Use
SSLContext.getInstance("TLSv1.2") for the best security.'
Context: SSLContext.getInstance("TLS")
Note: [CWE-326] Inadequate Encryption Strength [REFERENCES]
- https://tools.ietf.org/html/rfc7568
- https://tools.ietf.org/id/draft-ietf-tls-oldversions-deprecate-02.html

🔇 Additional comments (5)
java/build.gradle.kts (3)

6-6: LGTM: Test retry plugin added

The addition of the test retry plugin is a good improvement. It will help handle potentially flaky tests, increasing the overall reliability of the test suite.


67-72: LGTM: Retry configuration added to testRealtimeSuite

The addition of retry configuration to the testRealtimeSuite task is a good improvement. The settings (max 3 retries, max 8 failures, not failing on passed or skipped tests after retry) are reasonable and will help handle potentially flaky tests, increasing the overall reliability of the test suite.


Line range hint 1-108: Overall assessment: Well-implemented changes to build configuration

The changes to build.gradle.kts effectively support the PR objectives by:

  1. Adding the test retry plugin for improved test reliability.
  2. Implementing conditional logic for network client selection, allowing for OkHttp integration.
  3. Configuring retry settings for both Realtime and REST test suites.

These modifications enhance the project's build and test processes, aligning well with the goal of expanding proxy support and implementing OkHttp for HTTP calls and WebSocket connections.

lib/src/main/java/io/ably/lib/transport/WebSocketTransport.java (2)

4-5: LGTM: New imports and fields added

The new imports and field declarations are appropriate for the changes made in the class. They support the new WebSocket engine management and SSL/TLS handling.

Also applies to: 21-22, 54-56


111-111: LGTM: Updated connect method

The change to use this.webSocketEngine.create() for creating the WebSocket client aligns well with the new centralized WebSocket engine management. The synchronization is correctly maintained, ensuring thread safety.

@ttypic ttypic requested a review from sacOO7 October 7, 2024 09:23
Copy link
Collaborator

@sacOO7 sacOO7 left a comment

Choose a reason for hiding this comment

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

LGTM, Btw, you can take a look at RabbitAI comments?
Some of those look sensible to implement

Base automatically changed from ECO-4208/proxy-support to main October 7, 2024 14:45
@ttypic ttypic merged commit b6831e7 into main Oct 7, 2024
9 of 12 checks passed
@ttypic ttypic deleted the ECO-4208/proxy-support-okhttp branch October 7, 2024 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Expand proxy support: Authenticated Proxy and Websockets (HTTP CONNECT tunnel)
2 participants