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

[ECO-4944] feat: add room level reaction implementation #36

Merged
merged 2 commits into from
Nov 7, 2024

Conversation

ttypic
Copy link
Collaborator

@ttypic ttypic commented Oct 24, 2024

Room level reactions implementation

Summary by CodeRabbit

  • New Features

    • Enhanced the RoomReactions functionality to allow sending and subscribing to reactions in real-time.
    • Introduced a new coroutine-based method for asynchronous message publishing in the Channel class.
    • Added functionality in the chat application to track and display received reactions.
  • Bug Fixes

    • Improved error handling in the subscribe method for incoming messages.
  • Tests

    • Added unit tests for the DefaultRoomReactions class to verify channel naming and subscription behavior.
  • Chores

    • Integrated the konfetti library for use with Jetpack Compose.
    • Updated version management for konfetti-compose to version 2.0.4.

Copy link

coderabbitai bot commented Oct 24, 2024

Walkthrough

The changes in this pull request involve significant modifications to the Room and RoomReactions classes in the Ably chat application. The DefaultRoom class now constructs the reactions instance using clientId and realtimeChannels, while the RoomReactions class has seen the implementation of methods for sending and subscribing to reactions. Additionally, a new coroutine-based function publishCoroutine has been added to the Channel class, and unit tests for DefaultRoomReactions have been introduced to validate its functionality.

Changes

File Path Change Summary
chat-android/src/main/java/com/ably/chat/Room.kt Modified DefaultRoom to replace realtimeClient with clientId and realtimeChannels in reactions.
chat-android/src/main/java/com/ably/chat/RoomReactions.kt Updated DefaultRoomReactions constructor to use clientId and realtimeChannels, implemented send and subscribe methods.
chat-android/src/main/java/com/ably/chat/Utils.kt Added new method suspend fun Channel.publishCoroutine(message: PubSubMessage).
chat-android/src/test/java/com/ably/chat/RoomReactionsTest.kt Introduced unit tests for DefaultRoomReactions, validating channel naming and subscription functionality.
example/build.gradle.kts Added dependency for konfetti library.
example/src/main/java/com/ably/chat/example/MainActivity.kt Added receivedReactions variable and modified ChatInputField for handling reactions.
gradle/libs.versions.toml Added version and library declaration for konfetti-compose.

Assessment against linked issues

Objective Addressed Explanation
Implement room level reactions (ECO-4944)

Possibly related issues

  • Implement room level reactions (Implement room level reactions #3): This issue is directly related to the implementation of room-level reactions, which is a primary focus of the changes made in this PR.

Possibly related PRs

Suggested reviewers

  • umair-ably
  • AndyTWF
  • sacOO7
  • lawrence-forooghian

Poem

In the chat room where bunnies play,
Reactions hop in a joyful way.
With messages sent, and laughter shared,
Our new features show how much we cared.
So let's celebrate this code delight,
As we chat and react, all day and night! 🐰✨


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.

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 (5)
chat-android/src/main/java/com/ably/chat/Utils.kt (1)

38-51: LGTM! Well-structured coroutine implementation.

The implementation follows good practices:

  • Consistent with existing coroutine patterns in the codebase
  • Proper error handling and propagation
  • Clean integration with Ably's completion-based API

Consider adding KDoc documentation to match the style of other utility functions:

+/**
+ * Publishes a message to the channel using coroutines.
+ *
+ * @param message The message to publish
+ * @throws AblyException if the publish operation fails
+ */
 suspend fun Channel.publishCoroutine(message: PubSubMessage) = suspendCoroutine { continuation ->
chat-android/src/test/java/com/ably/chat/RoomReactionsTest.kt (3)

41-56: Enhance channel name test coverage

While the current test verifies the basic channel name format, consider adding test cases for:

  1. Edge cases: empty roomId, special characters in roomId
  2. Negative cases: null roomId

Example additional test:

@Test
fun `channel name handles special characters in roomId`() = runTest {
    val roomReactions = DefaultRoomReactions(
        roomId = "foo:bar",
        clientId = "client1",
        realtimeChannels = realtimeChannels,
    )

    assertEquals(
        "foo:bar::$chat::$reactions",
        roomReactions.channel.name,
    )
}

58-108: Enhance subscription test coverage

The subscription test is thorough but could be improved in several areas:

  1. Verify subscription cleanup/unsubscribe
  2. Test non-empty metadata mapping
  3. Add explicit test for isSelf=true case

Consider adding these test cases:

@Test
fun `should handle subscription cleanup`() = runTest {
    val subscription = roomReactions.subscribe { }
    subscription.unsubscribe()
    verify { realtimeChannel.unsubscribe("roomReaction", any()) }
}

@Test
fun `should map self reactions correctly`() = runTest {
    // Test with clientId matching the room's clientId
    // to verify isSelf is true
}

Also, consider testing the metadata mapping with non-empty data:

 data = JsonObject().apply {
     addProperty("type", "like")
+    add("metadata", JsonObject().apply {
+        addProperty("count", 1)
+    })
 }

18-18: Add class-level documentation

Consider adding KDoc documentation to describe the test class purpose and its relationship to the specifications being tested (CHA-ER1, CHA-ER3a).

Example:

/**
 * Tests for [DefaultRoomReactions] implementation verifying:
 * - Channel name formatting (CHA-ER1)
 * - Reaction subscription handling (CHA-ER3a)
 */
class RoomReactionsTest {
chat-android/src/main/java/com/ably/chat/Room.kt (1)

Line range hint 133-143: Consider adding error handling to attach/detach methods.

While the implementation is correct, consider adding error handling to gracefully handle failures during attach/detach operations. This is particularly important for maintaining room state consistency.

Consider wrapping the operations in a try-catch block:

 override suspend fun attach() {
+    try {
         messages.channel.attachCoroutine()
         typing.channel.attachCoroutine()
         reactions.channel.attachCoroutine()
+    } catch (e: Exception) {
+        // Handle or propagate the error appropriately
+        throw RoomException("Failed to attach to room channels", e)
+    }
 }

 override suspend fun detach() {
+    try {
         messages.channel.detachCoroutine()
         typing.channel.detachCoroutine()
         reactions.channel.detachCoroutine()
+    } catch (e: Exception) {
+        // Handle or propagate the error appropriately
+        throw RoomException("Failed to detach from room channels", e)
+    }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 7aab3fb and 66b5cc7.

📒 Files selected for processing (4)
  • chat-android/src/main/java/com/ably/chat/Room.kt (1 hunks)
  • chat-android/src/main/java/com/ably/chat/RoomReactions.kt (2 hunks)
  • chat-android/src/main/java/com/ably/chat/Utils.kt (1 hunks)
  • chat-android/src/test/java/com/ably/chat/RoomReactionsTest.kt (1 hunks)
🔇 Additional comments (2)
chat-android/src/main/java/com/ably/chat/Room.kt (1)

108-109: Improved dependency injection pattern!

The change from passing realtimeClient to passing specific components (clientId and realtimeChannels) is a good architectural improvement that:

  • Reduces coupling by only exposing required dependencies
  • Makes the code more testable
  • Follows interface segregation principle

Let's verify the consistency of this pattern across the codebase:

✅ Verification successful

Based on the shell script results, I can now generate the final response:

Verified: Consistent dependency injection pattern across codebase

The new pattern of passing specific components (clientId and realtimeChannels) instead of the entire realtimeClient is consistently implemented:

  • All DefaultRoomReactions instantiations in both production and test code follow this pattern
  • The only other usage of realtimeClient.channels in Typing.kt is for a different component and doesn't affect this change
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if realtimeClient is still directly passed to DefaultRoomReactions
# or if other components are using the new pattern consistently

# Search for DefaultRoomReactions instantiation
ast-grep --pattern 'DefaultRoomReactions($$$)'

# Search for other usages of realtimeClient.auth.clientId and realtimeClient.channels
rg 'realtimeClient\.(auth\.clientId|channels)' -A 2

Length of output: 2416

chat-android/src/main/java/com/ably/chat/RoomReactions.kt (1)

108-109: ⚠️ Potential issue

Update DefaultRoomReactions constructor usage throughout the codebase

The constructor of DefaultRoomReactions has changed to accept clientId and realtimeChannels instead of realtimeClient. Ensure that all instantiations of DefaultRoomReactions are updated to match the new constructor signature to prevent any instantiation errors.

Run the following script to find all usages of DefaultRoomReactions:

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 (4)
chat-android/src/main/java/com/ably/chat/RoomReactions.kt (2)

107-114: LGTM! Consider documenting the channel name format.

The constructor changes improve dependency injection by accepting only the required dependencies. However, the channel name format ($roomId::$chat::$reactions) could benefit from documentation explaining its structure and any constraints.

Consider adding a comment explaining:

  • The purpose of each segment in the channel name
  • Any restrictions on the roomId format
  • Reference to the specification that defines this format

Line range hint 157-159: Implement onDiscontinuity to handle connection state changes.

The onDiscontinuity method is crucial for handling connection state changes and ensuring reliable reaction delivery.

Would you like me to help implement this method? I can provide a solution that:

  • Monitors channel state changes
  • Notifies listeners of connectivity issues
  • Handles reconnection scenarios
example/src/main/java/com/ably/chat/example/MainActivity.kt (2)

88-97: Add error handling for room operations

While the room attachment logic is correctly implemented, consider adding error handling for the attach/detach operations to gracefully handle potential failures.

 DisposableEffect(Unit) {
     coroutineScope.launch {
-        room.attach()
+        try {
+            room.attach()
+        } catch (e: Exception) {
+            // Handle attachment failure
+            Log.e("MainActivity", "Failed to attach to room", e)
+        }
     }
     onDispose {
         coroutineScope.launch {
-            room.detach()
+            try {
+                room.detach()
+            } catch (e: Exception) {
+                Log.e("MainActivity", "Failed to detach from room", e)
+            }
         }
     }
 }

163-164: Enhance reaction display accessibility

The current text display of reactions should include content description for screen readers and consider using proper emoji semantic markup.

-Text("Received reactions: ${receivedReactions.joinToString()}", modifier = Modifier.padding(16.dp))
+Text(
+    text = "Received reactions: ${receivedReactions.joinToString()}",
+    modifier = Modifier
+        .padding(16.dp)
+        .semantics {
+            contentDescription = "Received reactions: ${receivedReactions.size} reactions"
+        }
+)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 66b5cc7 and f2da984.

📒 Files selected for processing (4)
  • chat-android/src/main/java/com/ably/chat/RoomReactions.kt (2 hunks)
  • example/build.gradle.kts (1 hunks)
  • example/src/main/java/com/ably/chat/example/MainActivity.kt (7 hunks)
  • gradle/libs.versions.toml (2 hunks)
🔇 Additional comments (4)
example/build.gradle.kts (1)

70-70: LGTM! Verify version catalog entry.

The addition of the konfetti-compose library aligns well with implementing visual feedback for room-level reactions.

Let's verify the version catalog entry exists:

✅ Verification successful

✓ Version catalog entry for konfetti-compose is properly configured

The version catalog entry for konfetti-compose is correctly set up with both the version declaration (2.0.4) and the library declaration referencing the version.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify konfetti-compose entry in version catalog
# Expected: Entry for konfetti-compose version and library declaration

# Test: Search for konfetti-compose in version catalog
rg "konfetti-compose" gradle/libs.versions.toml

Length of output: 173

chat-android/src/main/java/com/ably/chat/RoomReactions.kt (1)

154-155: LGTM! Proper subscription cleanup implemented.

The implementation correctly handles subscription cleanup by returning a Subscription object that unsubscribes the listener when disposed.

example/src/main/java/com/ably/chat/example/MainActivity.kt (2)

40-40: LGTM: Proper setup for reactions functionality

The new import and state management for reactions are correctly implemented using Compose state management best practices.

Also applies to: 83-83


Line range hint 83-164: Verify reaction implementation completeness

While the basic room-level reaction functionality is implemented, please verify:

  1. Reaction persistence across app restarts
  2. Proper synchronization across different clients
  3. Rate limiting for reaction sending
  4. Handling of network disconnections

@ttypic ttypic force-pushed the ECO-4944/room-level-reactions branch from f2da984 to 7d14c1c Compare October 25, 2024 12:27
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: 3

🧹 Outside diff range and nitpick comments (2)
chat-android/src/main/java/com/ably/chat/RoomReactions.kt (2)

111-112: Improve documentation for the channel name format.

The channel name format $roomId::$chat::$reactions appears to be an implementation detail referenced by "(CHA-ER1)". Consider adding a documentation comment explaining the format's significance and any constraints on the roomId parameter.


Line range hint 157-159: Implement onDiscontinuity method.

The onDiscontinuity method is currently unimplemented. This method is required by the EmitsDiscontinuities interface and should handle connection state changes or other discontinuities in the reaction stream.

Would you like me to help implement this method or create a GitHub issue to track this task?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between f2da984 and 7d14c1c.

📒 Files selected for processing (4)
  • chat-android/src/main/java/com/ably/chat/RoomReactions.kt (2 hunks)
  • example/build.gradle.kts (1 hunks)
  • example/src/main/java/com/ably/chat/example/MainActivity.kt (7 hunks)
  • gradle/libs.versions.toml (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • example/build.gradle.kts
  • gradle/libs.versions.toml
🔇 Additional comments (4)
chat-android/src/main/java/com/ably/chat/RoomReactions.kt (1)

150-150: Ensure thread-safe access to clientId.

The comparison pubSubMessage.clientId == clientId assumes that clientId won't change during the lifetime of the subscription. Consider making clientId immutable by declaring it as private val to prevent potential race conditions.

example/src/main/java/com/ably/chat/example/MainActivity.kt (3)

40-40: LGTM: Import added for reaction functionality

The import is correctly placed and necessary for the new reaction feature.


118-126: Reference existing review comment

The previous review comment about enhancing reaction handling robustness is still applicable to this code segment.


158-162: Reference existing review comment

The previous review comment about adding error handling and loading state for reaction sending is still applicable to this code segment.

@ttypic ttypic requested review from AndyTWF and sacOO7 November 5, 2024 13:37
@sacOO7
Copy link
Contributor

sacOO7 commented Nov 6, 2024

@ttypic The overall PR looks promising. While we have some unit tests to verify room reaction behavior, there's still some ambiguity regarding their end-to-end functionality.

Referring to the ably test pyramid guidelines, we're missing the crucial middle layer of integration tests. With the upcoming beta release and the limited time available, integrating chat-UTS into the Kotlin ecosystem seems unlikely at this point.

In the meantime, we should ensure a way to test the chat feature using the Ably sandbox. As discussed and agreed earlier, we should start incorporating integration tests within this PR itself. Setting up the sandbox should only take 2-3 hours max, but will provide significant value, enhancing our confidence in both the short and long term.

The goal is to have a feature-specific integration test that assures us the feature will work in a production environment. While we will eventually integrate UTS, having an in-house testing framework as a backup is always better.

You might like to assign this issue to yourself -> #26, wdyt

Copy link
Contributor

@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

sacOO7

This comment was marked as off-topic.

Copy link
Contributor

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants