|
404 | 404 | const heartbeatRequestKey = `${client.userId}_${(_a = clientAggregateAuthKey(client)) !== null && _a !== void 0 ? _a : ''}`;
|
405 | 405 | const hbRequestsBySubscriptionKey = serviceHeartbeatRequests[client.subscriptionKey];
|
406 | 406 | const hbRequests = (hbRequestsBySubscriptionKey !== null && hbRequestsBySubscriptionKey !== void 0 ? hbRequestsBySubscriptionKey : {})[heartbeatRequestKey];
|
407 |
| - notifyRequestProcessing('start', [client], new Date().toISOString(), request); |
| 407 | + notifyRequestProcessing('start', [client], new Date().toISOString(), event.request); |
408 | 408 | if (!request) {
|
409 | 409 | consoleLog(`Previous heartbeat request has been sent less than ${client.heartbeatInterval} seconds ago. Skipping...`, client);
|
410 | 410 | let response;
|
|
446 | 446 | * @param [client] - Specific client to handle leave request.
|
447 | 447 | */
|
448 | 448 | const handleSendLeaveRequestEvent = (data, client) => {
|
| 449 | + var _a, _b; |
| 450 | + var _c; |
449 | 451 | client = client !== null && client !== void 0 ? client : pubNubClients[data.clientIdentifier];
|
450 | 452 | const request = leaveTransportRequestFromEvent(data);
|
451 | 453 | if (!client)
|
452 | 454 | return;
|
453 | 455 | // Clean up client subscription information if there is no more channels / groups to use.
|
454 |
| - const { subscription } = client; |
| 456 | + const { subscription, heartbeat } = client; |
455 | 457 | const serviceRequestId = subscription === null || subscription === void 0 ? void 0 : subscription.serviceRequestId;
|
456 |
| - if (subscription) { |
457 |
| - if (subscription.channels.length === 0 && subscription.channelGroups.length === 0) { |
458 |
| - subscription.channelGroupQuery = ''; |
459 |
| - subscription.path = ''; |
460 |
| - subscription.previousTimetoken = '0'; |
461 |
| - subscription.timetoken = '0'; |
462 |
| - delete subscription.region; |
463 |
| - delete subscription.serviceRequestId; |
464 |
| - delete subscription.request; |
| 458 | + if (subscription && subscription.channels.length === 0 && subscription.channelGroups.length === 0) { |
| 459 | + subscription.channelGroupQuery = ''; |
| 460 | + subscription.path = ''; |
| 461 | + subscription.previousTimetoken = '0'; |
| 462 | + subscription.timetoken = '0'; |
| 463 | + delete subscription.region; |
| 464 | + delete subscription.serviceRequestId; |
| 465 | + delete subscription.request; |
| 466 | + } |
| 467 | + if (serviceHeartbeatRequests[client.subscriptionKey]) { |
| 468 | + if (heartbeat && heartbeat.channels.length === 0 && heartbeat.channelGroups.length === 0) { |
| 469 | + const hbRequestsBySubscriptionKey = ((_a = serviceHeartbeatRequests[_c = client.subscriptionKey]) !== null && _a !== void 0 ? _a : (serviceHeartbeatRequests[_c] = {})); |
| 470 | + const heartbeatRequestKey = `${client.userId}_${(_b = clientAggregateAuthKey(client)) !== null && _b !== void 0 ? _b : ''}`; |
| 471 | + if (hbRequestsBySubscriptionKey[heartbeatRequestKey] && |
| 472 | + hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier === client.clientIdentifier) |
| 473 | + delete hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier; |
465 | 474 | }
|
466 | 475 | }
|
467 | 476 | if (!request) {
|
|
837 | 846 | return undefined;
|
838 | 847 | const hbRequestsBySubscriptionKey = ((_a = serviceHeartbeatRequests[_e = client.subscriptionKey]) !== null && _a !== void 0 ? _a : (serviceHeartbeatRequests[_e] = {}));
|
839 | 848 | const heartbeatRequestKey = `${client.userId}_${(_b = clientAggregateAuthKey(client)) !== null && _b !== void 0 ? _b : ''}`;
|
840 |
| - const channelGroupsForAnnouncement = client.heartbeat.channelGroups; |
841 |
| - const channelsForAnnouncement = client.heartbeat.channels; |
| 849 | + const channelGroupsForAnnouncement = [...client.heartbeat.channelGroups]; |
| 850 | + const channelsForAnnouncement = [...client.heartbeat.channels]; |
842 | 851 | let aggregatedState;
|
843 | 852 | let failedPreviousRequest = false;
|
844 | 853 | let aggregated;
|
845 | 854 | if (!hbRequestsBySubscriptionKey[heartbeatRequestKey]) {
|
846 | 855 | hbRequestsBySubscriptionKey[heartbeatRequestKey] = {
|
847 | 856 | channels: channelsForAnnouncement,
|
848 | 857 | channelGroups: channelGroupsForAnnouncement,
|
| 858 | + clientIdentifier: client.clientIdentifier, |
849 | 859 | timestamp: Date.now(),
|
850 | 860 | };
|
851 | 861 | aggregatedState = (_c = client.heartbeat.presenceState) !== null && _c !== void 0 ? _c : {};
|
|
866 | 876 | if (client.heartbeatInterval)
|
867 | 877 | minimumHeartbeatInterval = Math.min(minimumHeartbeatInterval, client.heartbeatInterval);
|
868 | 878 | }
|
869 |
| - if (aggregated) { |
| 879 | + // Check whether multiple instance aggregate heartbeat and there is previous sender known. |
| 880 | + // `clientIdentifier` maybe empty in case if client which triggered heartbeats before has been invalidated and new |
| 881 | + // should handle heartbeat unconditionally. |
| 882 | + if (aggregated && hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier) { |
870 | 883 | const expectedTimestamp = hbRequestsBySubscriptionKey[heartbeatRequestKey].timestamp + minimumHeartbeatInterval * 1000;
|
871 | 884 | const currentTimestamp = Date.now();
|
872 | 885 | // Check whether it is too soon to send request or not (5 is leeway which let send request a bit earlier).
|
|
875 | 888 | return undefined;
|
876 | 889 | }
|
877 | 890 | delete hbRequestsBySubscriptionKey[heartbeatRequestKey].response;
|
| 891 | + hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier = client.clientIdentifier; |
878 | 892 | // Aggregate channels for similar clients which is pending for heartbeat.
|
879 |
| - for (const client of clients) { |
880 |
| - const { heartbeat } = client; |
881 |
| - if (heartbeat === undefined || client.clientIdentifier === event.clientIdentifier) |
| 893 | + for (const _client of clients) { |
| 894 | + const { heartbeat } = _client; |
| 895 | + if (heartbeat === undefined || _client.clientIdentifier === event.clientIdentifier) |
882 | 896 | continue;
|
883 | 897 | // Append presence state from the client (will override previously set value if already set).
|
884 | 898 | if (heartbeat.presenceState)
|
|
894 | 908 | if (!channelsForAnnouncement.includes(objectName) && !channelGroupsForAnnouncement.includes(objectName))
|
895 | 909 | delete aggregatedState[objectName];
|
896 | 910 | }
|
| 911 | + // No need to try send request with empty list of channels and groups. |
| 912 | + if (channelsForAnnouncement.length === 0 && channelGroupsForAnnouncement.length === 0) |
| 913 | + return undefined; |
897 | 914 | // Update request channels list (if required).
|
898 |
| - if (channelsForAnnouncement.length) { |
| 915 | + if (channelsForAnnouncement.length || channelGroupsForAnnouncement.length) { |
899 | 916 | const pathComponents = request.path.split('/');
|
900 |
| - pathComponents[6] = channelsForAnnouncement.join(','); |
| 917 | + pathComponents[6] = channelsForAnnouncement.length ? channelsForAnnouncement.join(',') : ','; |
901 | 918 | request.path = pathComponents.join('/');
|
902 | 919 | }
|
903 | 920 | // Update request channel groups list (if required).
|
|
927 | 944 | * done.
|
928 | 945 | */
|
929 | 946 | const leaveTransportRequestFromEvent = (event) => {
|
| 947 | + var _a; |
930 | 948 | const client = pubNubClients[event.clientIdentifier];
|
931 | 949 | const clients = clientsForSendLeaveRequestEvent(event);
|
932 | 950 | let channelGroups = channelGroupsFromRequest(event.request);
|
|
977 | 995 | }
|
978 | 996 | return undefined;
|
979 | 997 | }
|
| 998 | + // Update aggregated heartbeat state object. |
| 999 | + if (client && serviceHeartbeatRequests[client.subscriptionKey] && (channels.length || channelGroups.length)) { |
| 1000 | + const hbRequestsBySubscriptionKey = serviceHeartbeatRequests[client.subscriptionKey]; |
| 1001 | + const heartbeatRequestKey = `${client.userId}_${(_a = clientAggregateAuthKey(client)) !== null && _a !== void 0 ? _a : ''}`; |
| 1002 | + if (hbRequestsBySubscriptionKey[heartbeatRequestKey]) { |
| 1003 | + let { channels: hbChannels, channelGroups: hbChannelGroups } = hbRequestsBySubscriptionKey[heartbeatRequestKey]; |
| 1004 | + if (channelGroups.length) |
| 1005 | + hbChannelGroups = hbChannelGroups.filter((group) => !channels.includes(group)); |
| 1006 | + if (channels.length) |
| 1007 | + hbChannels = hbChannels.filter((channel) => !channels.includes(channel)); |
| 1008 | + hbRequestsBySubscriptionKey[heartbeatRequestKey].channelGroups = hbChannelGroups; |
| 1009 | + hbRequestsBySubscriptionKey[heartbeatRequestKey].channels = hbChannels; |
| 1010 | + } |
| 1011 | + } |
980 | 1012 | // Update request channels list (if required).
|
981 | 1013 | if (channels.length) {
|
982 | 1014 | const pathComponents = request.path.split('/');
|
|
1419 | 1451 | * @param clientId - Unique PubNub client identifier.
|
1420 | 1452 | */
|
1421 | 1453 | const invalidateClient = (subscriptionKey, clientId) => {
|
1422 |
| - var _a; |
| 1454 | + var _a, _b, _c; |
1423 | 1455 | const invalidatedClient = pubNubClients[clientId];
|
1424 | 1456 | delete pubNubClients[clientId];
|
1425 | 1457 | let clients = pubNubClientsBySubscriptionKey[subscriptionKey];
|
|
1432 | 1464 | if (serviceRequestId)
|
1433 | 1465 | cancelRequest(serviceRequestId);
|
1434 | 1466 | }
|
| 1467 | + if (serviceHeartbeatRequests[subscriptionKey]) { |
| 1468 | + const hbRequestsBySubscriptionKey = ((_a = serviceHeartbeatRequests[subscriptionKey]) !== null && _a !== void 0 ? _a : (serviceHeartbeatRequests[subscriptionKey] = {})); |
| 1469 | + const heartbeatRequestKey = `${invalidatedClient.userId}_${(_b = clientAggregateAuthKey(invalidatedClient)) !== null && _b !== void 0 ? _b : ''}`; |
| 1470 | + if (hbRequestsBySubscriptionKey[heartbeatRequestKey] && |
| 1471 | + hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier === invalidatedClient.clientIdentifier) |
| 1472 | + delete hbRequestsBySubscriptionKey[heartbeatRequestKey].clientIdentifier; |
| 1473 | + } |
1435 | 1474 | // Leave subscribed channels / groups properly.
|
1436 | 1475 | if (invalidatedClient.unsubscribeOfflineClients)
|
1437 | 1476 | unsubscribeClient(invalidatedClient);
|
|
1460 | 1499 | else
|
1461 | 1500 | delete sharedWorkerClients[subscriptionKey];
|
1462 | 1501 | }
|
1463 |
| - const message = `Invalidate '${clientId}' client. '${((_a = pubNubClientsBySubscriptionKey[subscriptionKey]) !== null && _a !== void 0 ? _a : []).length}' clients currently active.`; |
| 1502 | + const message = `Invalidate '${clientId}' client. '${((_c = pubNubClientsBySubscriptionKey[subscriptionKey]) !== null && _c !== void 0 ? _c : []).length}' clients currently active.`; |
1464 | 1503 | if (!clients)
|
1465 | 1504 | consoleLog(message);
|
1466 | 1505 | else
|
|
0 commit comments