Skip to content

Commit

Permalink
Support presence message extras
Browse files Browse the repository at this point in the history
Signed-off-by: Lewis Marshall <[email protected]>
  • Loading branch information
lmars committed Aug 8, 2023
1 parent 53ad2ec commit 5baf94d
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 10 deletions.
16 changes: 10 additions & 6 deletions ably.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2454,7 +2454,7 @@ declare namespace Types {
/**
* Enters the presence set for the channel, passing a `data` payload. A `clientId` is required to be present on a channel.
*
* @param data - The payload associated with the presence member.
* @param data - The data payload or {@link PresenceMessage} associated with the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
enter(data?: any, callback?: errorCallback): void;
Expand All @@ -2467,14 +2467,14 @@ declare namespace Types {
/**
* Updates the `data` payload for a presence member. If called before entering the presence set, this is treated as an {@link PresenceAction.ENTER} event.
*
* @param data - The payload to update for the presence member.
* @param data - The data payload or {@link PresenceMessage} object to update for the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
update(data?: any, callback?: errorCallback): void;
/**
* Leaves the presence set for the channel. A client must have previously entered the presence set before they can leave it.
*
* @param data - The payload associated with the presence member.
* @param data - The data payload or {@link PresenceMessage} associated with the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
leave(data?: any, callback?: errorCallback): void;
Expand All @@ -2488,7 +2488,7 @@ declare namespace Types {
* Enters the presence set of the channel for a given `clientId`. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard `clientId`.
*
* @param clientId - The ID of the client to enter into the presence set.
* @param data - The payload associated with the presence member.
* @param data - The data payload or {@link PresenceMessage} associated with the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
enterClient(clientId: string, data?: any, callback?: errorCallback): void;
Expand All @@ -2503,15 +2503,15 @@ declare namespace Types {
* Updates the `data` payload for a presence member using a given `clientId`. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard `clientId`.
*
* @param clientId - The ID of the client to update in the presence set.
* @param data - The payload to update for the presence member.
* @param data - The data payload or {@link PresenceMessage} object to update for the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
updateClient(clientId: string, data?: any, callback?: errorCallback): void;
/**
* Leaves the presence set of the channel for a given `clientId`. Enables a single client to update presence on behalf of any number of clients using a single connection. The library must have been instantiated with an API key or a token bound to a wildcard `clientId`.
*
* @param clientId - The ID of the client to leave the presence set for.
* @param data - The payload associated with the presence member.
* @param data - The data payload or {@link PresenceMessage} associated with the presence member.
* @param callback - A function which will be called upon completion of the operation. If the operation succeeded, then the function will be called with `null`. If it failed, the function will be called with information about the error.
*/
leaveClient(clientId: string, data?: any, callback?: errorCallback): void;
Expand Down Expand Up @@ -3208,6 +3208,10 @@ declare namespace Types {
* This will typically be empty as all presence messages received from Ably are automatically decoded client-side using this value. However, if the message encoding cannot be processed, this attribute will contain the remaining transformations not applied to the data payload.
*/
encoding: string;
/**
* A JSON object of arbitrary key-value pairs that may contain metadata, and/or ancillary payloads. Valid payloads include `headers`.
*/
extras: any;
/**
* A unique ID assigned to each `PresenceMessage` by Ably.
*/
Expand Down
6 changes: 2 additions & 4 deletions src/common/lib/client/realtimepresence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,8 @@ class RealtimePresence extends Presence {
'channel = ' + channel.name + ', id = ' + id + ', client = ' + (clientId || '(implicit) ' + getClientId(this))
);

const presence = PresenceMessage.fromValues({
action: action,
data: data,
});
const presence = PresenceMessage.fromData(data);
presence.action = action;
if (id) {
presence.id = id;
}
Expand Down
15 changes: 15 additions & 0 deletions src/common/lib/types/presencemessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class PresenceMessage {
connectionId?: string;
data?: string | Buffer | Uint8Array;
encoding?: string;
extras?: any;
size?: number;

static Actions = ['absent', 'present', 'enter', 'leave', 'update'];
Expand Down Expand Up @@ -53,6 +54,7 @@ class PresenceMessage {
action: number;
data: string | Buffer | Uint8Array;
encoding?: string;
extras?: any;
} {
/* encode data to base64 if present and we're returning real JSON;
* although msgpack calls toJSON(), we know it is a stringify()
Expand All @@ -78,6 +80,7 @@ class PresenceMessage {
action: toActionValue(this.action as string),
data: data,
encoding: encoding,
extras: this.extras,
};
}

Expand All @@ -95,6 +98,9 @@ class PresenceMessage {
result += '; data (buffer)=' + Platform.BufferUtils.base64Encode(this.data);
else result += '; data (json)=' + JSON.stringify(this.data);
}
if (this.extras) {
result += '; extras=' + JSON.stringify(this.extras);
}
result += ']';
return result;
}
Expand Down Expand Up @@ -155,6 +161,15 @@ class PresenceMessage {
});
}

static fromData(data: unknown): PresenceMessage {
if (data instanceof PresenceMessage) {
return data;
}
return PresenceMessage.fromValues({
data,
});
}

static getMessagesSize = Message.getMessagesSize;
}

Expand Down
38 changes: 38 additions & 0 deletions test/realtime/presence.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, helper, async
var createPM = Ably.Realtime.ProtocolMessage.fromDeserialized;
var closeAndFinish = helper.closeAndFinish;
var monitorConnection = helper.monitorConnection;
var PresenceMessage = Ably.Realtime.PresenceMessage;

function extractClientIds(presenceSet) {
return utils
Expand Down Expand Up @@ -370,6 +371,43 @@ define(['ably', 'shared_helper', 'async', 'chai'], function (Ably, helper, async
monitorConnection(done, clientRealtime);
});

/*
* Attach to channel, enter presence channel with extras and check received
* PresenceMessage has extras.
*/
it('presenceMessageExtras', function (done) {
var clientRealtime = helper.AblyRealtime({ clientId: testClientId, tokenDetails: authToken });
var channelName = 'presenceMessageExtras';
var clientChannel = clientRealtime.channels.get(channelName);
var presence = clientChannel.presence;
presence.subscribe(
function (presenceMessage) {
try {
expect(presenceMessage.extras).to.deep.equal(
{ headers: { key: 'value' } },
'extras should have headers "key=value"'
);
} catch (err) {
closeAndFinish(done, clientRealtime, err);
return;
}
closeAndFinish(done, clientRealtime);
},
function onPresenceSubscribe(err) {
if (err) {
closeAndFinish(done, clientRealtime, err);
return;
}
clientChannel.presence.enter(
PresenceMessage.fromValues({
extras: { headers: { key: 'value' } },
})
);
}
);
monitorConnection(done, clientRealtime);
});

/*
* Enter presence channel (without attaching), detach, then enter again to reattach
*/
Expand Down

0 comments on commit 5baf94d

Please sign in to comment.