|
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