Conversation
WalkthroughAdds support for MessageExtras across Presence APIs and PresenceMessage: new overloads for enter/update/leave (including clientId variants), PresenceMessage gains an extras field with serialization/deserialization, tests added, and Kotlin interface/adapter updated to accept and forward extras. Changes
Sequence DiagramsequenceDiagram
participant Client
participant Presence
participant PresenceMessage
participant Network
Client->>Presence: enter(data, extras, listener)
Presence->>PresenceMessage: new PresenceMessage(action, clientId, data, extras)
PresenceMessage-->>Presence: constructed (includes extras)
Presence->>Network: serialize PresenceMessage (JSON/msgpack includes extras)
Network-->>Presence: deliver PresenceMessage payload
Presence->>PresenceMessage: deserialize/read (extract extras)
Presence-->>Client: emit PresenceMessage (with extras)
Client->>Client: listener.onSuccess()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Add extras field to PresenceMessage type with support for both msgpack and JSON serialization/deserialization. Includes end-to-end test verifying extras round-trip through presence enter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
dabc3d8 to
8e5acc4
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@lib/src/main/java/io/ably/lib/types/PresenceMessage.java`:
- Around line 293-309: The read method in PresenceMessage currently throws when
extras is the JSON literal null; update PresenceMessage.read to treat JsonNull
as absent by checking extrasElement.isJsonNull() (or instanceof JsonNull) and
skipping the extras parsing instead of erroring, so only non-null JsonObject
values are passed to MessageExtras.read; reference the EXTRAS lookup, the
extrasElement variable, and MessageExtras.read when making this change.
Add MessageExtras overloads to enter(), update(), leave() and their *Client variants so callers can pass extras without dropping down to updatePresence(PresenceMessage, CompletionListener). Existing methods delegate to the new overloads with null extras (fully backward-compatible). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update RealtimePresence interface and RealtimePresenceAdapter to accept MessageExtras on enter, update, leave and their *Client variants, matching the new Java overloads. The extras parameter defaults to null so existing callers are unaffected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Treat `"extras": null` as absent rather than throwing a MessageDecodeException. This avoids a hard failure when incoming JSON explicitly sets extras to null. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
787ea3b to
a646200
Compare
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
lib/src/main/java/io/ably/lib/realtime/Presence.java (1)
675-688:⚠️ Potential issue | 🟠 MajorPreserve
extraswhen re-entering internal members after reconnect.
enterInternalMembers()replays presence viaenterClientWithId, which currently drops extras. This breaks RTP17g and loses per-message metadata on reconnect.🔧 Proposed fix
- private void enterClientWithId(String id, String clientId, Object data, CompletionListener listener) throws AblyException { + private void enterClientWithId(String id, String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException { if(clientId == null) { String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to enter presence channel (null clientId specified)", channel.name); Log.v(TAG, errorMessage); if(listener != null) { listener.onError(new ErrorInfo(errorMessage, 40000)); return; } } - PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data); + PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data, extras); presenceMsg.id = id; Log.v(TAG, "enterClient(); channel = " + channel.name + "; clientId = " + clientId); updatePresence(presenceMsg, listener); }- enterClientWithId(item.id, item.clientId, item.data, new CompletionListener() { + enterClientWithId(item.id, item.clientId, item.data, item.extras, new CompletionListener() {Also applies to: 1049-1064
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/src/main/java/io/ably/lib/realtime/Presence.java` around lines 675 - 688, enterClientWithId currently drops per-message metadata (extras) when rebuilding PresenceMessage, breaking RTP17g; modify the replay path so the original PresenceMessage.extras are preserved: update enterClientWithId and its callers (notably enterInternalMembers and the other replay location around the 1049-1064 area) to accept or obtain the original PresenceMessage.extras and set presenceMsg.extras = originalExtras before calling updatePresence; reference Presence.enterClientWithId, Presence.enterInternalMembers, and the PresenceMessage.extras field so all replayed messages carry the same extras as the original.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@lib/src/main/java/io/ably/lib/realtime/Presence.java`:
- Around line 675-688: enterClientWithId currently drops per-message metadata
(extras) when rebuilding PresenceMessage, breaking RTP17g; modify the replay
path so the original PresenceMessage.extras are preserved: update
enterClientWithId and its callers (notably enterInternalMembers and the other
replay location around the 1049-1064 area) to accept or obtain the original
PresenceMessage.extras and set presenceMsg.extras = originalExtras before
calling updatePresence; reference Presence.enterClientWithId,
Presence.enterInternalMembers, and the PresenceMessage.extras field so all
replayed messages carry the same extras as the original.
Summary
This change adds full support for
MessageExtrason presence messages:PresenceMessage.extrasfield (TP3i) — allows presence messages to carry arbitrary metadata and ancillary payloads, with serialization support in both MessagePack and JSON formats.MessageExtrasoverloads toenter(),update(),leave()and their*Clientvariants so callers can pass extras without dropping down toupdatePresence(PresenceMessage, CompletionListener).RealtimePresenceinterface andRealtimePresenceAdapterwith theextrasparameter (defaulting tonull).PresenceMessage.read()now handles"extras": nullgracefully instead of throwing.CHA-1243
Prerequisite to ably/ably-chat-kotlin#193
Closes #736
Closes #753
Key Changes
PresenceMessage.javaextrasfield of typeMessageExtras(TP3i)PresenceMessage(Action, String, Object, MessageExtras); existing 3-arg constructor delegates to it withextras = nullclone()to copy theextrasfieldextrasin both MessagePack (writeMsgpack/readMsgpack) and JSON (read/Serializer) formatsnullextras gracefully and type-checks for valid JSON objectPresence.javaMessageExtras extrasparameter:enter(Object data, MessageExtras extras, CompletionListener listener)— RTP8update(Object data, MessageExtras extras, CompletionListener listener)— RTP9leave(Object data, MessageExtras extras, CompletionListener listener)— RTP10enterClient(String clientId, Object data, MessageExtras extras, CompletionListener listener)— RTP15updateClient(String clientId, Object data, MessageExtras extras, CompletionListener listener)— RTP15leaveClient(String clientId, Object data, MessageExtras extras, CompletionListener listener)— RTP15nullextras (fully backward-compatible, no ambiguity — different arity)RealtimePresence.kt/RealtimePresenceAdapter.ktextras: MessageExtras? = nullparameter to all 6 presence methods in the Kotlin interface and adapterRealtimePresenceTest.javapresence_enter_with_extras— existing test for extras viaupdatePresence()directlypresence_enter_with_extras_convenience— new: testsenter(data, extras, listener)presence_update_with_extras— new: testsupdate(data, extras, listener)presence_leave_with_extras— new: testsleave(data, extras, listener)presence_enterClient_with_extras— new: testsenterClient(clientId, data, extras, listener)Backward Compatibility
All changes are fully backward-compatible. No existing method signatures change. Java overload resolution is clean since the new methods differ in arity from the existing ones.
🤖 Generated with Claude Code
Summary by CodeRabbit