Skip to content

Fix rapid subscribe aggregate #461

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"parser" : "typescript",
"parser": "typescript",
"semi": true,
"printWidth": 120,
"singleQuote": true,
Expand Down
1,685 changes: 907 additions & 778 deletions dist/web/pubnub.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/web/pubnub.min.js

Large diffs are not rendered by default.

348 changes: 279 additions & 69 deletions dist/web/pubnub.worker.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/web/pubnub.worker.min.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions lib/core/constants/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ var StatusCategory;
* - Wi-Fi hotspot authorization page.
*/
StatusCategory["PNMalformedResponseCategory"] = "PNMalformedResponseCategory";
/**
* Server can't process request.
*
* There can be few sources of unexpected return with success code:
* - potentially an ongoing incident;
* - proxy server / VPN.
*/
StatusCategory["PNServerErrorCategory"] = "PNServerErrorCategory";
/**
* Something strange happened; please check the logs.
*/
Expand Down
29 changes: 18 additions & 11 deletions lib/core/pubnub-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ class PubNubCore {
setAuthKey(authKey) {
this.logger.debug('PubNub', `Set auth key: ${authKey}`);
this._configuration.setAuthKey(authKey);
if (this.onAuthenticationChange)
this.onAuthenticationChange(authKey);
}
/**
* Get a PubNub client user identifier.
Expand All @@ -469,6 +471,8 @@ class PubNubCore {
}
this.logger.debug('PubNub', `Set user ID: ${value}`);
this._configuration.userId = value;
if (this.onUserIdChange)
this.onUserIdChange(this._configuration.userId);
}
/**
* Get a PubNub client user identifier.
Expand All @@ -488,13 +492,7 @@ class PubNubCore {
* @throws Error empty user identifier has been provided.
*/
setUserId(value) {
if (!value || typeof value !== 'string' || value.trim().length === 0) {
const error = new Error('Missing or invalid userId parameter. Provide a valid string userId');
this.logger.error('PubNub', () => ({ messageType: 'error', message: error }));
throw error;
}
this.logger.debug('PubNub', `Set user ID: ${value}`);
this._configuration.userId = value;
this.userId = value;
}
/**
* Real-time updates filtering expression.
Expand Down Expand Up @@ -562,16 +560,18 @@ class PubNubCore {
* @param interval - New presence request heartbeat intervals.
*/
set heartbeatInterval(interval) {
var _a;
this.logger.debug('PubNub', `Set heartbeat interval: ${interval}`);
this._configuration.setHeartbeatInterval(interval);
if (this.onHeartbeatIntervalChange)
this.onHeartbeatIntervalChange((_a = this._configuration.getHeartbeatInterval()) !== null && _a !== void 0 ? _a : 0);
}
/**
* Change a heartbeat requests interval.
*
* @param interval - New presence request heartbeat intervals.
*/
setHeartbeatInterval(interval) {
this.logger.debug('PubNub', `Set heartbeat interval: ${interval}`);
this.heartbeatInterval = interval;
}
/**
Expand Down Expand Up @@ -1073,9 +1073,14 @@ class PubNubCore {
message: { subscription: subscription, subscriptions },
details: `Unregister event handle capable:`,
}));
if (!subscriptions ||
subscriptions.length === 0 ||
(subscriptions && subscription instanceof subscription_set_1.SubscriptionSet && subscriptions === subscriptions))
// Check whether only subscription object has been passed to be unregistered.
let shouldDeleteEventHandler = !subscriptions || subscriptions.length === 0;
// Check whether subscription set is unregistering with all managed Subscription objects,
if (!shouldDeleteEventHandler &&
subscription instanceof subscription_set_1.SubscriptionSet &&
subscription.subscriptions.length === (subscriptions === null || subscriptions === void 0 ? void 0 : subscriptions.length))
shouldDeleteEventHandler = subscription.subscriptions.every((sub) => subscriptions.includes(sub));
if (shouldDeleteEventHandler)
delete this.eventHandleCapable[subscription.state.id];
let subscriptionInput;
if (!subscriptions || subscriptions.length === 0) {
Expand Down Expand Up @@ -2149,6 +2154,8 @@ class PubNubCore {
set token(token) {
if (this.tokenManager)
this.tokenManager.setToken(token);
if (this.onAuthenticationChange)
this.onAuthenticationChange(token);
}
/**
* Set current access token.
Expand Down
18 changes: 3 additions & 15 deletions lib/entities/subscription-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,12 @@ class SubscriptionBase {
* Create a subscription object from the state.
*
* @param state - Subscription state object.
* @param subscriptionType - Actual subscription object type.
*
* @internal
*/
constructor(state) {
constructor(state, subscriptionType = 'Subscription') {
this.subscriptionType = subscriptionType;
/**
* Unique subscription object identifier.
*
Expand All @@ -150,20 +152,6 @@ class SubscriptionBase {
this.eventDispatcher = new event_dispatcher_1.EventDispatcher();
this._state = state;
}
/**
* Retrieve subscription type.
*
* There is two types:
* - Subscription
* - SubscriptionSet
*
* @returns One of subscription types.
*
* @internal
*/
get subscriptionType() {
return 'Subscription';
}
/**
* Subscription state.
*
Expand Down
38 changes: 19 additions & 19 deletions lib/entities/subscription-set.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,6 @@ class SubscriptionSetState extends subscription_base_1.SubscriptionBaseState {
super(parameters.client, subscriptionInput, parameters.options, parameters.client.subscriptionTimetoken);
this.subscriptions = parameters.subscriptions;
}
/**
* Retrieve subscription type.
*
* There is two types:
* - Subscription
* - SubscriptionSet
*
* @returns One of subscription types.
*
* @internal
*/
get subscriptionType() {
return 'SubscriptionSet';
}
/**
* Add a single subscription object to the set.
*
Expand Down Expand Up @@ -151,7 +137,7 @@ class SubscriptionSet extends subscription_base_1.SubscriptionBase {
state = parameters.state;
state.client.logger.debug('SubscriptionSet', 'Create subscription set clone');
}
super(state);
super(state, 'SubscriptionSet');
this.state.storeClone(this.id, this);
// Update a parent sets list for original set subscriptions.
state.subscriptions.forEach((subscription) => subscription.addParentSet(this));
Expand Down Expand Up @@ -428,10 +414,24 @@ class SubscriptionSet extends subscription_base_1.SubscriptionBase {
unregister(subscriptions) {
const activeSubscriptions = (subscriptions !== null && subscriptions !== void 0 ? subscriptions : this.state.subscriptions);
activeSubscriptions.forEach(({ state }) => state.entity.decreaseSubscriptionCount(this.state.id));
this.state.client.logger.trace(this.subscriptionType, () => ({
messageType: 'text',
message: `Unregister subscription from real-time events: ${this}`,
}));
this.state.client.logger.trace(this.subscriptionType, () => {
if (!subscriptions) {
return {
messageType: 'text',
message: `Unregister subscription from real-time events: ${this}`,
};
}
else {
return {
messageType: 'object',
message: {
subscription: this,
subscriptions,
},
details: 'Unregister subscriptions of subscription set from real-time events:',
};
}
});
this.state.client.unregisterEventHandleCapable(this, activeSubscriptions);
}
/**
Expand Down
4 changes: 4 additions & 0 deletions lib/errors/pubnub-api-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ class PubNubAPIError extends Error {
category = categories_1.default.PNAccessDeniedCategory;
message = 'Access denied';
}
else if (status >= 500) {
category = categories_1.default.PNServerErrorCategory;
message = 'Internal server error';
}
if (typeof response === 'object' && Object.keys(response).length === 0) {
category = categories_1.default.PNMalformedResponseCategory;
message = 'Malformed response (network issues)';
Expand Down
11 changes: 10 additions & 1 deletion lib/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -817,7 +817,7 @@ declare class PubNubCore<
* configured PubNub client `uuid` if not set.
* @param callback - Request completion handler callback.
*
* @deprecated Use {@link PubNubCore#objects.getUUIDMetadata getUUIDMetadata} method instead.
* @deprecated Use {@link PubNubCore#objects.getUUIDMetadata|getUUIDMetadata} method instead.
*/
fetchUser<Custom extends PubNub.AppContext.CustomData = PubNub.AppContext.CustomData>(
parameters: PubNub.AppContext.GetUUIDMetadataParameters,
Expand Down Expand Up @@ -2143,6 +2143,14 @@ declare namespace PubNub {
* - Wi-Fi hotspot authorization page.
*/
PNMalformedResponseCategory = 'PNMalformedResponseCategory',
/**
* Server can't process request.
*
* There can be few sources of unexpected return with success code:
* - potentially an ongoing incident;
* - proxy server / VPN.
*/
PNServerErrorCategory = 'PNServerErrorCategory',
/**
* Something strange happened; please check the logs.
*/
Expand Down Expand Up @@ -4577,6 +4585,7 @@ declare namespace PubNub {
* Implementation of base functionality used by {@link SubscriptionObject Subscription} and {@link SubscriptionSet}.
*/
export abstract class SubscriptionBase implements EventEmitCapable, EventHandleCapable {
protected readonly subscriptionType: 'Subscription' | 'SubscriptionSet';
/**
* Get a list of channels which is used for subscription.
*
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/core/constants/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ enum StatusCategory {
*/
PNMalformedResponseCategory = 'PNMalformedResponseCategory',

/**
* Server can't process request.
*
* There can be few sources of unexpected return with success code:
* - potentially an ongoing incident;
* - proxy server / VPN.
*/
PNServerErrorCategory = 'PNServerErrorCategory',

/**
* Something strange happened; please check the logs.
*/
Expand Down
55 changes: 40 additions & 15 deletions src/core/pubnub-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,27 @@ export class PubNubCore<
*/
protected readonly transport: Transport;

/**
* `userId` change handler.
*
* @internal
*/
protected onUserIdChange?: (userId: string) => void;

/**
* Heartbeat interval change handler.
*
* @internal
*/
protected onHeartbeatIntervalChange?: (interval: number) => void;

/**
* `authKey` or `token` change handler.
*
* @internal
*/
protected onAuthenticationChange?: (auth?: string) => void;

/**
* REST API endpoints access tokens manager.
*
Expand Down Expand Up @@ -676,6 +697,8 @@ export class PubNubCore<
setAuthKey(authKey: string): void {
this.logger.debug('PubNub', `Set auth key: ${authKey}`);
this._configuration.setAuthKey(authKey);

if (this.onAuthenticationChange) this.onAuthenticationChange(authKey);
}

/**
Expand Down Expand Up @@ -706,6 +729,8 @@ export class PubNubCore<

this.logger.debug('PubNub', `Set user ID: ${value}`);
this._configuration.userId = value;

if (this.onUserIdChange) this.onUserIdChange(this._configuration.userId);
}

/**
Expand All @@ -727,15 +752,7 @@ export class PubNubCore<
* @throws Error empty user identifier has been provided.
*/
setUserId(value: string): void {
if (!value || typeof value !== 'string' || value.trim().length === 0) {
const error = new Error('Missing or invalid userId parameter. Provide a valid string userId');
this.logger.error('PubNub', () => ({ messageType: 'error', message: error }));

throw error;
}

this.logger.debug('PubNub', `Set user ID: ${value}`);
this._configuration.userId = value;
this.userId = value;
}

/**
Expand Down Expand Up @@ -812,6 +829,8 @@ export class PubNubCore<
set heartbeatInterval(interval: number) {
this.logger.debug('PubNub', `Set heartbeat interval: ${interval}`);
this._configuration.setHeartbeatInterval(interval);

if (this.onHeartbeatIntervalChange) this.onHeartbeatIntervalChange(this._configuration.getHeartbeatInterval() ?? 0);
}

/**
Expand All @@ -820,7 +839,6 @@ export class PubNubCore<
* @param interval - New presence request heartbeat intervals.
*/
setHeartbeatInterval(interval: number): void {
this.logger.debug('PubNub', `Set heartbeat interval: ${interval}`);
this.heartbeatInterval = interval;
}

Expand Down Expand Up @@ -1493,12 +1511,18 @@ export class PubNubCore<
details: `Unregister event handle capable:`,
}));

// Check whether only subscription object has been passed to be unregistered.
let shouldDeleteEventHandler = !subscriptions || subscriptions.length === 0;

// Check whether subscription set is unregistering with all managed Subscription objects,
if (
!subscriptions ||
subscriptions.length === 0 ||
(subscriptions && subscription instanceof SubscriptionSet && subscriptions === subscriptions)
!shouldDeleteEventHandler &&
subscription instanceof SubscriptionSet &&
subscription.subscriptions.length === subscriptions?.length
)
delete this.eventHandleCapable[subscription.state.id];
shouldDeleteEventHandler = subscription.subscriptions.every((sub) => subscriptions.includes(sub));

if (shouldDeleteEventHandler) delete this.eventHandleCapable[subscription.state.id];

let subscriptionInput: SubscriptionInput;
if (!subscriptions || subscriptions.length === 0) {
Expand Down Expand Up @@ -3016,6 +3040,7 @@ export class PubNubCore<
*/
public set token(token: string | undefined) {
if (this.tokenManager) this.tokenManager.setToken(token);
if (this.onAuthenticationChange) this.onAuthenticationChange(token);
}

/**
Expand Down Expand Up @@ -3269,7 +3294,7 @@ export class PubNubCore<
* configured PubNub client `uuid` if not set.
* @param callback - Request completion handler callback.
*
* @deprecated Use {@link PubNubCore#objects.getUUIDMetadata getUUIDMetadata} method instead.
* @deprecated Use {@link PubNubCore#objects.getUUIDMetadata|getUUIDMetadata} method instead.
*/
public fetchUser<Custom extends AppContext.CustomData = AppContext.CustomData>(
parameters: AppContext.GetUUIDMetadataParameters,
Expand Down
Loading