Skip to content

Commit 1ef7829

Browse files
AndyTWFclaude
andcommitted
feat: add extras parameter to Presence enter/update/leave methods
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). Also fixes a bug in enterInternalMembers() (RTP17g) where extras were dropped on automatic re-enter after reconnect. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8e5acc4 commit 1ef7829

3 files changed

Lines changed: 411 additions & 9 deletions

File tree

lib/src/main/java/io/ably/lib/realtime/Presence.java

Lines changed: 124 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import io.ably.lib.types.Callback;
1111
import io.ably.lib.types.ErrorInfo;
1212
import io.ably.lib.types.MessageDecodeException;
13+
import io.ably.lib.types.MessageExtras;
1314
import io.ably.lib.types.PaginatedResult;
1415
import io.ably.lib.types.Param;
1516
import io.ably.lib.types.PresenceMessage;
@@ -483,8 +484,27 @@ private void unsubscribeImpl(PresenceMessage.Action action, PresenceListener lis
483484
* @throws AblyException
484485
*/
485486
public void enter(Object data, CompletionListener listener) throws AblyException {
487+
enter(data, null, listener);
488+
}
489+
490+
/**
491+
* Enters the presence set for the channel, optionally passing a data payload and extras.
492+
* A clientId is required to be present on a channel.
493+
* An optional callback may be provided to notify of the success or failure of the operation.
494+
*
495+
* <p>
496+
* Spec: RTP8
497+
*
498+
* @param data The payload associated with the presence member.
499+
* @param extras The extras associated with the presence member.
500+
* @param listener A callback to notify of the success or failure of the operation.
501+
* <p>
502+
* This listener is invoked on a background thread.
503+
* @throws AblyException
504+
*/
505+
public void enter(Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
486506
Log.v(TAG, "enter(); channel = " + channel.name);
487-
updatePresence(new PresenceMessage(PresenceMessage.Action.enter, null, data), listener);
507+
updatePresence(new PresenceMessage(PresenceMessage.Action.enter, null, data, extras), listener);
488508
}
489509

490510
/**
@@ -502,8 +522,27 @@ public void enter(Object data, CompletionListener listener) throws AblyException
502522
* @throws AblyException
503523
*/
504524
public void update(Object data, CompletionListener listener) throws AblyException {
525+
update(data, null, listener);
526+
}
527+
528+
/**
529+
* Updates the data payload for a presence member, optionally passing extras.
530+
* If called before entering the presence set, this is treated as an {@link PresenceMessage.Action#enter} event.
531+
* An optional callback may be provided to notify of the success or failure of the operation.
532+
*
533+
* <p>
534+
* Spec: RTP9
535+
*
536+
* @param data The payload associated with the presence member.
537+
* @param extras The extras associated with the presence member.
538+
* @param listener A callback to notify of the success or failure of the operation.
539+
* <p>
540+
* This listener is invoked on a background thread.
541+
* @throws AblyException
542+
*/
543+
public void update(Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
505544
Log.v(TAG, "update(); channel = " + channel.name);
506-
updatePresence(new PresenceMessage(PresenceMessage.Action.update, null, data), listener);
545+
updatePresence(new PresenceMessage(PresenceMessage.Action.update, null, data, extras), listener);
507546
}
508547

509548
/**
@@ -520,8 +559,26 @@ public void update(Object data, CompletionListener listener) throws AblyExceptio
520559
* @throws AblyException
521560
*/
522561
public void leave(Object data, CompletionListener listener) throws AblyException {
562+
leave(data, null, listener);
563+
}
564+
565+
/**
566+
* Leaves the presence set for the channel, optionally passing extras.
567+
* A client must have previously entered the presence set before they can leave it.
568+
*
569+
* <p>
570+
* Spec: RTP10
571+
*
572+
* @param data The payload associated with the presence member.
573+
* @param extras The extras associated with the presence member.
574+
* @param listener a listener to notify of the success or failure of the operation.
575+
* <p>
576+
* This listener is invoked on a background thread.
577+
* @throws AblyException
578+
*/
579+
public void leave(Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
523580
Log.v(TAG, "leave(); channel = " + channel.name);
524-
updatePresence(new PresenceMessage(PresenceMessage.Action.leave, null, data), listener);
581+
updatePresence(new PresenceMessage(PresenceMessage.Action.leave, null, data, extras), listener);
525582
}
526583

527584
/**
@@ -584,6 +641,25 @@ public void enterClient(String clientId, Object data) throws AblyException {
584641
* This listener is invoked on a background thread.
585642
*/
586643
public void enterClient(String clientId, Object data, CompletionListener listener) throws AblyException {
644+
enterClient(clientId, data, null, listener);
645+
}
646+
647+
/**
648+
* Enters the presence set of the channel for a given clientId, optionally passing extras.
649+
* Enables a single client to update presence on behalf of any number of clients using a single connection.
650+
* The library must have been instantiated with an API key or a token bound to a wildcard clientId.
651+
*
652+
* <p>
653+
* Spec: RTP4, RTP14, RTP15
654+
*
655+
* @param clientId The ID of the client to enter into the presence set.
656+
* @param data The payload associated with the presence member.
657+
* @param extras The extras associated with the presence member.
658+
* @param listener A callback to notify of the success or failure of the operation.
659+
* <p>
660+
* This listener is invoked on a background thread.
661+
*/
662+
public void enterClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
587663
if(clientId == null) {
588664
String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to enter presence channel (null clientId specified)", channel.name);
589665
Log.v(TAG, errorMessage);
@@ -593,10 +669,10 @@ public void enterClient(String clientId, Object data, CompletionListener listene
593669
}
594670
}
595671
Log.v(TAG, "enterClient(); channel = " + channel.name + "; clientId = " + clientId);
596-
updatePresence(new PresenceMessage(PresenceMessage.Action.enter, clientId, data), listener);
672+
updatePresence(new PresenceMessage(PresenceMessage.Action.enter, clientId, data, extras), listener);
597673
}
598674

599-
private void enterClientWithId(String id, String clientId, Object data, CompletionListener listener) throws AblyException {
675+
private void enterClientWithId(String id, String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
600676
if(clientId == null) {
601677
String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to enter presence channel (null clientId specified)", channel.name);
602678
Log.v(TAG, errorMessage);
@@ -605,7 +681,7 @@ private void enterClientWithId(String id, String clientId, Object data, Completi
605681
return;
606682
}
607683
}
608-
PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data);
684+
PresenceMessage presenceMsg = new PresenceMessage(PresenceMessage.Action.enter, clientId, data, extras);
609685
presenceMsg.id = id;
610686
Log.v(TAG, "enterClient(); channel = " + channel.name + "; clientId = " + clientId);
611687
updatePresence(presenceMsg, listener);
@@ -658,6 +734,26 @@ public void updateClient(String clientId, Object data) throws AblyException {
658734
* This listener is invoked on a background thread.
659735
*/
660736
public void updateClient(String clientId, Object data, CompletionListener listener) throws AblyException {
737+
updateClient(clientId, data, null, listener);
738+
}
739+
740+
/**
741+
* Updates the data payload for a presence member using a given clientId, optionally passing extras.
742+
* Enables a single client to update presence on behalf of any number of clients using a single connection.
743+
* The library must have been instantiated with an API key or a token bound to a wildcard clientId.
744+
* An optional callback may be provided to notify of the success or failure of the operation.
745+
*
746+
* <p>
747+
* Spec: RTP15
748+
*
749+
* @param clientId The ID of the client to update in the presence set.
750+
* @param data The payload to update for the presence member.
751+
* @param extras The extras associated with the presence member.
752+
* @param listener A callback to notify of the success or failure of the operation.
753+
* <p>
754+
* This listener is invoked on a background thread.
755+
*/
756+
public void updateClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
661757
if(clientId == null) {
662758
String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to update presence channel (null clientId specified)", channel.name);
663759
Log.v(TAG, errorMessage);
@@ -667,7 +763,7 @@ public void updateClient(String clientId, Object data, CompletionListener listen
667763
}
668764
}
669765
Log.v(TAG, "updateClient(); channel = " + channel.name + "; clientId = " + clientId);
670-
updatePresence(new PresenceMessage(PresenceMessage.Action.update, clientId, data), listener);
766+
updatePresence(new PresenceMessage(PresenceMessage.Action.update, clientId, data, extras), listener);
671767
}
672768

673769
/**
@@ -714,6 +810,25 @@ public void leaveClient(String clientId, Object data) throws AblyException {
714810
* This listener is invoked on a background thread.
715811
*/
716812
public void leaveClient(String clientId, Object data, CompletionListener listener) throws AblyException {
813+
leaveClient(clientId, data, null, listener);
814+
}
815+
816+
/**
817+
* Leaves the presence set of the channel for a given clientId, optionally passing extras.
818+
* Enables a single client to update presence on behalf of any number of clients using a single connection.
819+
* The library must have been instantiated with an API key or a token bound to a wildcard clientId.
820+
*
821+
* <p>
822+
* Spec: RTP15
823+
*
824+
* @param clientId The ID of the client to leave the presence set for.
825+
* @param data The payload associated with the presence member.
826+
* @param extras The extras associated with the presence member.
827+
* @param listener A callback to notify of the success or failure of the operation.
828+
* <p>
829+
* This listener is invoked on a background thread.
830+
*/
831+
public void leaveClient(String clientId, Object data, MessageExtras extras, CompletionListener listener) throws AblyException {
717832
if(clientId == null) {
718833
String errorMessage = String.format(Locale.ROOT, "Channel %s: unable to leave presence channel (null clientId specified)", channel.name);
719834
Log.v(TAG, errorMessage);
@@ -723,7 +838,7 @@ public void leaveClient(String clientId, Object data, CompletionListener listene
723838
}
724839
}
725840
Log.v(TAG, "leaveClient(); channel = " + channel.name + "; clientId = " + clientId);
726-
updatePresence(new PresenceMessage(PresenceMessage.Action.leave, clientId, data), listener);
841+
updatePresence(new PresenceMessage(PresenceMessage.Action.leave, clientId, data, extras), listener);
727842
}
728843

729844
/**
@@ -934,7 +1049,7 @@ void onAttached(boolean hasPresence) {
9341049
void enterInternalMembers() {
9351050
for (final PresenceMessage item: internalPresence.members.values()) {
9361051
try {
937-
enterClientWithId(item.id, item.clientId, item.data, new CompletionListener() {
1052+
enterClientWithId(item.id, item.clientId, item.data, item.extras, new CompletionListener() {
9381053
@Override
9391054
public void onSuccess() {
9401055
}

lib/src/main/java/io/ably/lib/types/PresenceMessage.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,21 @@ public PresenceMessage(Action action, String clientId) {
106106
* @param data
107107
*/
108108
public PresenceMessage(Action action, String clientId, Object data) {
109+
this(action, clientId, data, null);
110+
}
111+
112+
/**
113+
* Construct a PresenceMessage with extras
114+
* @param action
115+
* @param clientId
116+
* @param data
117+
* @param extras
118+
*/
119+
public PresenceMessage(Action action, String clientId, Object data, MessageExtras extras) {
109120
this.action = action;
110121
this.clientId = clientId;
111122
this.data = data;
123+
this.extras = extras;
112124
}
113125

114126
/**

0 commit comments

Comments
 (0)