From 688c3634b3a37017174cfdaf9c0180d3fed755b3 Mon Sep 17 00:00:00 2001 From: Will Sewell Date: Thu, 11 Feb 2021 14:23:44 +0000 Subject: [PATCH 1/4] Support fetching channel info on trigger Adds support for a new experimental feature of the Channels API: Specifically the ability to specify an `info` parameter in a trigger body, or with an event in a batch trigger body. The server will respond with attributes in the same format as the `/channels` endpoint. The `info` param is specified in a "params" object, which is passed in as the fourth parameter to the `trigger` method. The `socket_id` parameter is specified in the same way. Note: this introduces a breaking change for users that were passing in a `socket_id`. It is not a breaking change for `triggerBatch`. `triggerBatch` has also been updated to support `socket_id` being included as part of event objects. --- README.md | 38 +++++++++++++++++++++++-- index.d.ts | 9 +++++- lib/events.js | 11 +++----- lib/pusher.js | 16 +++++++---- tests/integration/pusher/trigger.js | 44 +++++++++++++++++++++++------ 5 files changed, 92 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index b23bde1..6d5dcfe 100644 --- a/README.md +++ b/README.md @@ -160,11 +160,43 @@ You can trigger a batch of up to 10 events. ### Excluding event recipients -In order to avoid the client that triggered the event from also receiving it, the `trigger` function takes an optional `socketId` parameter. For more informaiton see: . +In order to avoid the client that triggered the event from also receiving it, a `socket_id` parameter can be added to the `params` object. For more information see: . ```javascript -const socketId = "1302.1081607" -pusher.trigger(channel, event, data, socketId) +pusher.trigger(channel, event, data, { socket_id: "1302.1081607" }) + +pusher.triggerBatch([ + { channel: channel, name: name, data: data, socket_id: "1302.1081607" }, +]) +``` + +### Fetch subscriber and user counts at the time of batch publish + +For the channels that were published to, you can request for the number of subscribers or user to be returned in the response body. + +```javascript +pusher + .trigger(channel, event, data, { info: "user_count,subscription_count" }) + .then(response => { + if (response.status !== 200) { + throw Error("unexpected status") + } + // Parse the response body as JSON + return response.json() + ) + .then(body => { + const channelsInfo = body.channels + // Do something with channelsInfo + }) + .catch(error => { + // Handle error + }) + +pusher + .triggerBatch([{ channel: channel, name: name, data: data, info: "user_count,subscription_count" }]) + .then(response => { + // As above + }) ``` ### End-to-end encryption [BETA] diff --git a/index.d.ts b/index.d.ts index 37a1839..1911e95 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,7 +10,7 @@ declare class Pusher { channel: string | Array, event: string, data: any, - socketId?: string + params?: Pusher.TriggerParams ): Promise trigger( @@ -61,10 +61,17 @@ declare namespace Pusher { export type Options = ClusterOptions | HostOptions + export interface TriggerParams { + socket_id?: string + info?: string + } + export interface BatchEvent { channel: string name: string data: any + socket_id?: string + info?: string } type ReservedParams = diff --git a/lib/events.js b/lib/events.js index ae9434e..cba393c 100644 --- a/lib/events.js +++ b/lib/events.js @@ -23,16 +23,14 @@ function encrypt(pusher, channel, data) { }) } -exports.trigger = function (pusher, channels, eventName, data, socketId) { +exports.trigger = function (pusher, channels, eventName, data, params) { if (channels.length === 1 && util.isEncryptedChannel(channels[0])) { const channel = channels[0] const event = { name: eventName, data: encrypt(pusher, channel, data), channels: [channel], - } - if (socketId) { - event.socket_id = socketId + ...params, } return pusher.post({ path: "/events", body: event }) } else { @@ -49,10 +47,9 @@ exports.trigger = function (pusher, channels, eventName, data, socketId) { name: eventName, data: ensureJSON(data), channels: channels, + ...params, } - if (socketId) { - event.socket_id = socketId - } + console.log(event) return pusher.post({ path: "/events", body: event }) } } diff --git a/lib/pusher.js b/lib/pusher.js index 2778a68..284b253 100644 --- a/lib/pusher.js +++ b/lib/pusher.js @@ -130,12 +130,14 @@ Pusher.prototype.authenticate = function (socketId, channel, data) { * @param {String|String[]} channel list of at most 100 channels * @param {String} event event name * @param data event data, objects are JSON-encoded - * @param {String} [socketId] id of a socket that should not receive the event + * @param {Object} [params] additional optional request body parameters + * @param {String} [params.socket_id] id of a socket that should not receive the event + * @param {String} [params.info] a comma separate list of attributes to be returned in the response * @see RequestError */ -Pusher.prototype.trigger = function (channels, event, data, socketId) { - if (socketId) { - validateSocketId(socketId) +Pusher.prototype.trigger = function (channels, event, data, params) { + if (params && params.socket_id) { + validateSocketId(params.socket_id) } if (!(channels instanceof Array)) { // add single channel to array for multi trigger compatibility @@ -150,7 +152,7 @@ Pusher.prototype.trigger = function (channels, event, data, socketId) { for (let i = 0; i < channels.length; i++) { validateChannel(channels[i]) } - return events.trigger(this, channels, event, data, socketId) + return events.trigger(this, channels, event, data, params) } /* Triggers a batch of events @@ -159,7 +161,9 @@ Pusher.prototype.trigger = function (channels, event, data, socketId) { * { * name: string, * channel: string, - * data: any JSON-encodable data + * data: any JSON-encodable data, + * socket_id: [optional] string, + * info: [optional] string * } */ Pusher.prototype.triggerBatch = function (batch) { diff --git a/tests/integration/pusher/trigger.js b/tests/integration/pusher/trigger.js index 0deecbd..652f33e 100644 --- a/tests/integration/pusher/trigger.js +++ b/tests/integration/pusher/trigger.js @@ -99,7 +99,7 @@ describe("Pusher", function () { .catch(done) }) - it("should add socket_id to the request body", function (done) { + it("should add params to the request body", function (done) { nock("http://api.pusherapp.com") .filteringPath(function (path) { return path @@ -107,18 +107,23 @@ describe("Pusher", function () { .replace(/auth_signature=[0-9a-f]{64}/, "auth_signature=Y") }) .post( - "/apps/1234/events?auth_key=f00d&auth_timestamp=X&auth_version=1.0&body_md5=0478e1ed73804ae1be97cfa6554cf039&auth_signature=Y", + "/apps/1234/events?auth_key=f00d&auth_timestamp=X&auth_version=1.0&body_md5=2e4f053f1c325dedbe21abd8f1852b53&auth_signature=Y", { name: "my_event", data: '{"some":"data "}', channels: ["test_channel"], socket_id: "123.567", + info: "user_count,subscription_count", } ) .reply(200, "{}") + const params = { + socket_id: "123.567", + info: "user_count,subscription_count", + } pusher - .trigger("test_channel", "my_event", { some: "data " }, "123.567") + .trigger("test_channel", "my_event", { some: "data " }, params) .then(() => done()) .catch(done) }) @@ -131,20 +136,31 @@ describe("Pusher", function () { .replace(/auth_signature=[0-9a-f]{64}/, "auth_signature=Y") }) .post( - "/apps/1234/events?auth_key=f00d&auth_timestamp=X&auth_version=1.0&body_md5=cf87d666b4a829a54fc44b313584b2d7&auth_signature=Y", + "/apps/1234/events?auth_key=f00d&auth_timestamp=X&auth_version=1.0&body_md5=d3a47b3241328a6432adf60c8e91b6fb&auth_signature=Y", { name: "my_event", data: '{"some":"data "}', channels: ["test_channel"], + info: "subscription_count", } ) - .reply(200, "OK") + .reply(200, '{"channels":{"test_channel":{"subscription_count":123}}}') pusher - .trigger("test_channel", "my_event", { some: "data " }) + .trigger( + "test_channel", + "my_event", + { some: "data " }, + { info: "subscription_count" } + ) .then((response) => { expect(response.status).to.equal(200) - done() + return response.text().then((body) => { + expect(body).to.equal( + '{"channels":{"test_channel":{"subscription_count":123}}}' + ) + done() + }) }) .catch(done) }) @@ -286,7 +302,12 @@ describe("Pusher", function () { .reply(200, "{}") pusher - .trigger("test_channel", "my_event", { some: "data " }, "123.567") + .trigger( + "test_channel", + "my_event", + { some: "data " }, + { socket_id: "123.567" } + ) .then(() => done()) .catch(done) }) @@ -317,7 +338,12 @@ describe("Pusher", function () { .reply(200) pusher - .trigger("test_channel", "my_event", { some: "data " }, "123.567") + .trigger( + "test_channel", + "my_event", + { some: "data " }, + { socket_id: "123.567" } + ) .catch((error) => { expect(error).to.be.a(Pusher.RequestError) expect(error.message).to.equal("Request failed with an error") From 1a2c418354951e0a35bb08ade0b98bdefcab69de Mon Sep 17 00:00:00 2001 From: Will Sewell Date: Tue, 16 Feb 2021 12:28:01 +0000 Subject: [PATCH 2/4] Document how to handle batch publish responses --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6d5dcfe..9181031 100644 --- a/README.md +++ b/README.md @@ -170,13 +170,15 @@ pusher.triggerBatch([ ]) ``` -### Fetch subscriber and user counts at the time of batch publish +### Fetch subscriber and user counts at the time of publish For the channels that were published to, you can request for the number of subscribers or user to be returned in the response body. +#### Regular triggering + ```javascript pusher - .trigger(channel, event, data, { info: "user_count,subscription_count" }) + .trigger("presence-my-channel", "event", "test", { info: "user_count,subscription_count" }) .then(response => { if (response.status !== 200) { throw Error("unexpected status") @@ -191,11 +193,47 @@ pusher .catch(error => { // Handle error }) +``` + +#### Batch triggering +```javascript +const batch = [ + { + channel: "my-channel", + name: "event", + data: "test1", + info: "subscription_count", + }, + { + channel: "presence-my-channel", + name: "event", + data: "test2", + info: "user_count,subscription_count", + }, +] pusher - .triggerBatch([{ channel: channel, name: name, data: data, info: "user_count,subscription_count" }]) - .then(response => { - // As above + .triggerBatch(batch) + .then((response) => { + if (response.status !== 200) { + throw Error("unexpected status") + } + // Parse the response body as JSON + return response.json() + }) + .then((body) => { + body.batch.forEach((attributes, i) => { + process.stdout.write( + `channel: ${batch[i].channel}, name: ${batch[i].name}, subscription_count: ${attributes.subscription_count}` + ) + if ("user_count" in attributes) { + process.stdout.write(`, user_count: ${attributes.user_count}`) + } + process.stdout.write("\n") + }) + }) + .catch((error) => { + console.error(error) }) ``` From b06ebd7c2cbefe7d5bf63ded665afd70d630e53c Mon Sep 17 00:00:00 2001 From: Will Sewell Date: Tue, 16 Feb 2021 15:14:28 +0000 Subject: [PATCH 3/4] Remove debug logging --- lib/events.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/events.js b/lib/events.js index cba393c..573ecdd 100644 --- a/lib/events.js +++ b/lib/events.js @@ -49,7 +49,6 @@ exports.trigger = function (pusher, channels, eventName, data, params) { channels: channels, ...params, } - console.log(event) return pusher.post({ path: "/events", body: event }) } } From 9f1fbd88e65dc8cf81796d7811e0806de8c1aa66 Mon Sep 17 00:00:00 2001 From: Will Sewell Date: Thu, 18 Feb 2021 16:28:37 +0000 Subject: [PATCH 4/4] Mark feature as experimental --- README.md | 2 +- lib/pusher.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9181031..bda9932 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,7 @@ pusher.triggerBatch([ ]) ``` -### Fetch subscriber and user counts at the time of publish +### Fetch subscriber and user counts at the time of publish [[EXPERIMENTAL](https://pusher.com/docs/lab#experimental-program)] For the channels that were published to, you can request for the number of subscribers or user to be returned in the response body. diff --git a/lib/pusher.js b/lib/pusher.js index 284b253..384763d 100644 --- a/lib/pusher.js +++ b/lib/pusher.js @@ -132,7 +132,7 @@ Pusher.prototype.authenticate = function (socketId, channel, data) { * @param data event data, objects are JSON-encoded * @param {Object} [params] additional optional request body parameters * @param {String} [params.socket_id] id of a socket that should not receive the event - * @param {String} [params.info] a comma separate list of attributes to be returned in the response + * @param {String} [params.info] a comma separate list of attributes to be returned in the response. Experimental, see https://pusher.com/docs/lab#experimental-program * @see RequestError */ Pusher.prototype.trigger = function (channels, event, data, params) { @@ -163,7 +163,7 @@ Pusher.prototype.trigger = function (channels, event, data, params) { * channel: string, * data: any JSON-encodable data, * socket_id: [optional] string, - * info: [optional] string + * info: [optional] string experimental, see https://pusher.com/docs/lab#experimental-program * } */ Pusher.prototype.triggerBatch = function (batch) {