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

Fix presence leave call on used channels #425

Merged
merged 3 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
---
changelog:
- date: 2024-12-12
version: v8.3.2
changes:
- type: bug
text: "Fix issue with `Subscription` and `SubscriptionSet` when one can unsubscribe channel / group which is still in use by another."
- type: bug
text: "Fix particular `TypeError` emitted when browser forcefully closes long-poll connection before its timeout and reported as bad request. This type of error will be reported as a network error."
- type: bug
text: "Fix issue because of which `node-fetch` used default agent, which after Node.js 19+ has `keepAlive` enabled by default."
- date: 2024-11-18
version: v8.3.1
changes:
Expand Down Expand Up @@ -1072,7 +1081,7 @@ supported-platforms:
- 'Ubuntu 14.04 and up'
- 'Windows 7 and up'
version: 'Pubnub Javascript for Node'
version: '8.3.1'
version: '8.3.2'
sdks:
- full-name: PubNub Javascript SDK
short-name: Javascript
Expand All @@ -1088,7 +1097,7 @@ sdks:
- distribution-type: source
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/archive/refs/tags/v8.3.1.zip
location: https://github.com/pubnub/javascript/archive/refs/tags/v8.3.2.zip
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down Expand Up @@ -1759,7 +1768,7 @@ sdks:
- distribution-type: library
distribution-repository: GitHub release
package-name: pubnub.js
location: https://github.com/pubnub/javascript/releases/download/v8.3.1/pubnub.8.3.1.js
location: https://github.com/pubnub/javascript/releases/download/v8.3.2/pubnub.8.3.2.js
requires:
- name: 'agentkeepalive'
min-version: '3.5.2'
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v8.3.2
December 12 2024

#### Fixed
- Fix issue with `Subscription` and `SubscriptionSet` when one can unsubscribe channel / group which is still in use by another.
- Fix particular `TypeError` emitted when browser forcefully closes long-poll connection before its timeout and reported as bad request. This type of error will be reported as a network error.
- Fix issue because of which `node-fetch` used default agent, which after Node.js 19+ has `keepAlive` enabled by default.

## v8.3.1
November 18 2024

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ Watch [Getting Started with PubNub JS SDK](https://app.dashcam.io/replay/64ee0d2
npm install pubnub
```
* or download one of our builds from our CDN:
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.3.1.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.3.1.min.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.3.2.js
* https://cdn.pubnub.com/sdk/javascript/pubnub.8.3.2.min.js

2. Configure your keys:

Expand Down
71 changes: 67 additions & 4 deletions dist/web/pubnub.js
Original file line number Diff line number Diff line change
Expand Up @@ -2916,7 +2916,10 @@
message = 'Network issues';
}
else if (errorName === 'TypeError') {
category = StatusCategory$1.PNBadRequestCategory;
if (message.indexOf('Load failed') !== -1 || message.indexOf('Failed to fetch') != -1)
category = StatusCategory$1.PNNetworkIssuesCategory;
else
category = StatusCategory$1.PNBadRequestCategory;
}
else if (errorName === 'FetchError') {
const errorCode = error.code;
Expand Down Expand Up @@ -3948,7 +3951,7 @@
return base.PubNubFile;
},
get version() {
return '8.3.1';
return '8.3.2';
},
getVersion() {
return this.version;
Expand Down Expand Up @@ -9892,15 +9895,23 @@
*/
subscribe(subscribeParameters) {
const timetoken = subscribeParameters === null || subscribeParameters === void 0 ? void 0 : subscribeParameters.timetoken;
this.pubnub.registerSubscribeCapable(this);
this.pubnub.subscribe(Object.assign({ channels: this.channelNames, channelGroups: this.groupNames }, (timetoken !== null && timetoken !== '' && { timetoken: timetoken })));
}
/**
* Stop real-time events processing.
*/
unsubscribe() {
this.pubnub.unregisterSubscribeCapable(this);
const { channels, channelGroups } = this.pubnub.getSubscribeCapableEntities();
// Identify channels and groups from which PubNub client can safely unsubscribe.
const filteredChannelGroups = this.groupNames.filter((cg) => !channelGroups.includes(cg));
const filteredChannels = this.channelNames.filter((ch) => !channels.includes(ch));
if (filteredChannels.length === 0 && filteredChannelGroups.length === 0)
return;
this.pubnub.unsubscribe({
channels: this.channelNames,
channelGroups: this.groupNames,
channels: filteredChannels,
channelGroups: filteredChannelGroups,
});
}
/**
Expand Down Expand Up @@ -12566,6 +12577,7 @@
// Prepare for real-time events announcement.
this.listenerManager = new ListenerManager();
this.eventEmitter = new EventEmitter(this.listenerManager);
this.subscribeCapable = new Set();
if (this._configuration.enableEventEngine) {
{
let heartbeatInterval = this._configuration.getHeartbeatInterval();
Expand Down Expand Up @@ -12998,7 +13010,9 @@
* @param [isOffline] - Whether `offline` presence should be notified or not.
*/
destroy(isOffline) {
var _a;
{
(_a = this.subscribeCapable) === null || _a === void 0 ? void 0 : _a.clear();
if (this.subscriptionManager) {
this.subscriptionManager.unsubscribeAll(isOffline);
this.subscriptionManager.disconnect();
Expand Down Expand Up @@ -13127,6 +13141,53 @@
}
return [];
}
/**
* Register subscribe capable object with active subscription.
*
* @param subscribeCapable - {@link Subscription} or {@link SubscriptionSet} object.
*
* @internal
*/
registerSubscribeCapable(subscribeCapable) {
{
if (!this.subscribeCapable || this.subscribeCapable.has(subscribeCapable))
return;
this.subscribeCapable.add(subscribeCapable);
}
}
/**
* Unregister subscribe capable object with inactive subscription.
*
* @param subscribeCapable - {@link Subscription} or {@link SubscriptionSet} object.
*
* @internal
*/
unregisterSubscribeCapable(subscribeCapable) {
{
if (!this.subscribeCapable || !this.subscribeCapable.has(subscribeCapable))
return;
this.subscribeCapable.delete(subscribeCapable);
}
}
/**
* Retrieve list of subscribe capable entities currently used in subscription.
*
* @returns Channels and channel groups currently used in subscription.
*
* @internal
*/
getSubscribeCapableEntities() {
{
const entities = { channels: [], channelGroups: [] };
if (!this.subscribeCapable)
return entities;
for (const subscribeCapable of this.subscribeCapable) {
entities.channelGroups.push(...subscribeCapable.channelGroups);
entities.channels.push(...subscribeCapable.channels);
}
return entities;
}
}
/**
* Subscribe to specified channels and groups real-time events.
*
Expand Down Expand Up @@ -13205,7 +13266,9 @@
* Unsubscribe from all channels and groups.
*/
unsubscribeAll() {
var _a;
{
(_a = this.subscribeCapable) === null || _a === void 0 ? void 0 : _a.clear();
if (this.subscriptionManager)
this.subscriptionManager.unsubscribeAll();
else if (this.eventEngine)
Expand Down
4 changes: 2 additions & 2 deletions dist/web/pubnub.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion lib/core/components/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ const makeConfiguration = (base, setupCryptoModule) => {
return base.PubNubFile;
},
get version() {
return '8.3.1';
return '8.3.2';
},
getVersion() {
return this.version;
Expand Down
60 changes: 60 additions & 0 deletions lib/core/pubnub-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ class PubNubCore {
// Prepare for real-time events announcement.
this.listenerManager = new listener_manager_1.ListenerManager();
this.eventEmitter = new eventEmitter_1.default(this.listenerManager);
this.subscribeCapable = new Set();
if (this._configuration.enableEventEngine) {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled') {
let heartbeatInterval = this._configuration.getHeartbeatInterval();
Expand Down Expand Up @@ -609,7 +610,10 @@ class PubNubCore {
* @param [isOffline] - Whether `offline` presence should be notified or not.
*/
destroy(isOffline) {
var _a;
if (process.env.SUBSCRIBE_MODULE !== 'disabled') {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled')
(_a = this.subscribeCapable) === null || _a === void 0 ? void 0 : _a.clear();
if (this.subscriptionManager) {
this.subscriptionManager.unsubscribeAll(isOffline);
this.subscriptionManager.disconnect();
Expand Down Expand Up @@ -755,6 +759,59 @@ class PubNubCore {
throw new Error('Subscription error: subscription module disabled');
return [];
}
/**
* Register subscribe capable object with active subscription.
*
* @param subscribeCapable - {@link Subscription} or {@link SubscriptionSet} object.
*
* @internal
*/
registerSubscribeCapable(subscribeCapable) {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled') {
if (!this.subscribeCapable || this.subscribeCapable.has(subscribeCapable))
return;
this.subscribeCapable.add(subscribeCapable);
}
else
throw new Error('Subscription error: subscription event engine module disabled');
}
/**
* Unregister subscribe capable object with inactive subscription.
*
* @param subscribeCapable - {@link Subscription} or {@link SubscriptionSet} object.
*
* @internal
*/
unregisterSubscribeCapable(subscribeCapable) {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled') {
if (!this.subscribeCapable || !this.subscribeCapable.has(subscribeCapable))
return;
this.subscribeCapable.delete(subscribeCapable);
}
else
throw new Error('Subscription error: subscription event engine module disabled');
}
/**
* Retrieve list of subscribe capable entities currently used in subscription.
*
* @returns Channels and channel groups currently used in subscription.
*
* @internal
*/
getSubscribeCapableEntities() {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled') {
const entities = { channels: [], channelGroups: [] };
if (!this.subscribeCapable)
return entities;
for (const subscribeCapable of this.subscribeCapable) {
entities.channelGroups.push(...subscribeCapable.channelGroups);
entities.channels.push(...subscribeCapable.channels);
}
return entities;
}
else
throw new Error('Subscription error: subscription event engine module disabled');
}
/**
* Subscribe to specified channels and groups real-time events.
*
Expand Down Expand Up @@ -841,7 +898,10 @@ class PubNubCore {
* Unsubscribe from all channels and groups.
*/
unsubscribeAll() {
var _a;
if (process.env.SUBSCRIBE_MODULE !== 'disabled') {
if (process.env.SUBSCRIBE_EVENT_ENGINE_MODULE !== 'disabled')
(_a = this.subscribeCapable) === null || _a === void 0 ? void 0 : _a.clear();
if (this.subscriptionManager)
this.subscriptionManager.unsubscribeAll();
else if (this.eventEngine)
Expand Down
12 changes: 10 additions & 2 deletions lib/entities/SubscribeCapable.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ class SubscribeCapable {
*/
subscribe(subscribeParameters) {
const timetoken = subscribeParameters === null || subscribeParameters === void 0 ? void 0 : subscribeParameters.timetoken;
this.pubnub.registerSubscribeCapable(this);
this.pubnub.subscribe(Object.assign({ channels: this.channelNames, channelGroups: this.groupNames }, (timetoken !== null && timetoken !== '' && { timetoken: timetoken })));
}
/**
* Stop real-time events processing.
*/
unsubscribe() {
this.pubnub.unregisterSubscribeCapable(this);
const { channels, channelGroups } = this.pubnub.getSubscribeCapableEntities();
// Identify channels and groups from which PubNub client can safely unsubscribe.
const filteredChannelGroups = this.groupNames.filter((cg) => !channelGroups.includes(cg));
const filteredChannels = this.channelNames.filter((ch) => !channels.includes(ch));
if (filteredChannels.length === 0 && filteredChannelGroups.length === 0)
return;
this.pubnub.unsubscribe({
channels: this.channelNames,
channelGroups: this.groupNames,
channels: filteredChannels,
channelGroups: filteredChannelGroups,
});
}
/**
Expand Down
5 changes: 4 additions & 1 deletion lib/errors/pubnub-api-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ class PubNubAPIError extends Error {
message = 'Network issues';
}
else if (errorName === 'TypeError') {
category = categories_1.default.PNBadRequestCategory;
if (message.indexOf('Load failed') !== -1 || message.indexOf('Failed to fetch') != -1)
category = categories_1.default.PNNetworkIssuesCategory;
else
category = categories_1.default.PNBadRequestCategory;
}
else if (errorName === 'FetchError') {
const errorCode = error.code;
Expand Down
11 changes: 4 additions & 7 deletions lib/transport/node-transport.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,19 +182,16 @@ class NodeTransport {
* @internal
*/
agentForTransportRequest(req) {
// Don't configure any agents if keep alive not requested.
if (!this.keepAlive && !this.proxyConfiguration)
return undefined;
// Create proxy agent (if possible).
if (this.proxyConfiguration)
return this.proxyAgent ? this.proxyAgent : (this.proxyAgent = new proxy_agent_1.ProxyAgent(this.proxyConfiguration));
// Create keep alive agent.
const useSecureAgent = req.origin.startsWith('https:');
const agentOptions = Object.assign({ keepAlive: this.keepAlive }, (this.keepAlive ? this.keepAliveSettings : {}));
if (useSecureAgent && this.httpsAgent === undefined)
this.httpsAgent = new https_1.Agent(Object.assign({ keepAlive: true }, this.keepAliveSettings));
else if (!useSecureAgent && this.httpAgent === undefined) {
this.httpAgent = new http_1.Agent(Object.assign({ keepAlive: true }, this.keepAliveSettings));
}
this.httpsAgent = new https_1.Agent(agentOptions);
else if (!useSecureAgent && this.httpAgent === undefined)
this.httpAgent = new http_1.Agent(agentOptions);
return useSecureAgent ? this.httpsAgent : this.httpAgent;
}
/**
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pubnub",
"version": "8.3.1",
"version": "8.3.2",
"author": "PubNub <[email protected]>",
"description": "Publish & Subscribe Real-time Messaging with PubNub",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion src/core/components/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export const makeConfiguration = (
return base.PubNubFile;
},
get version(): string {
return '8.3.1';
return '8.3.2';
},
getVersion(): string {
return this.version;
Expand Down
Loading
Loading