@splitsoftware/splitio-commons 0.1.1-canary.9 → 0.1.1-rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/evaluator/matchers/matcherTypes.js +4 -4
- package/cjs/evaluator/matchersTransform/index.js +11 -11
- package/cjs/evaluator/value/sanitize.js +6 -6
- package/cjs/listeners/browser.js +1 -2
- package/cjs/listeners/node.js +0 -3
- package/cjs/logger/constants.js +3 -1
- package/cjs/logger/messages/error.js +3 -2
- package/cjs/logger/messages/info.js +2 -2
- package/cjs/logger/messages/warn.js +2 -1
- package/cjs/readiness/readinessManager.js +10 -7
- package/cjs/sdkFactory/index.js +1 -4
- package/cjs/services/splitApi.js +1 -1
- package/cjs/services/splitHttpClient.js +5 -4
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/inLocalStorage/index.js +5 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/cjs/storages/inRedis/index.js +5 -2
- package/cjs/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +6 -7
- package/cjs/storages/pluggable/index.js +5 -2
- package/cjs/storages/pluggable/wrapperAdapter.js +0 -1
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +92 -89
- package/cjs/sync/offline/splitsParser/splitsParserFromSettings.js +45 -42
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -4
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/cjs/sync/streaming/SSEClient/index.js +0 -11
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/cjs/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/cjs/sync/streaming/SSEHandler/index.js +8 -9
- package/cjs/sync/streaming/SSEHandler/types.js +14 -0
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/cjs/sync/streaming/constants.js +3 -1
- package/cjs/sync/streaming/mySegmentsV2utils.js +75 -0
- package/cjs/sync/streaming/pushManager.js +141 -40
- package/cjs/sync/submitters/metricsSyncTask.js +1 -1
- package/cjs/sync/submitters/submitterSyncTask.js +2 -2
- package/cjs/sync/syncManagerFromFile.js +15 -0
- package/cjs/sync/syncManagerFromObject.js +14 -0
- package/cjs/sync/syncManagerOffline.js +3 -3
- package/cjs/sync/syncManagerOnline.js +5 -3
- package/cjs/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/cjs/trackers/impressionObserver/buildKey.js +3 -9
- package/cjs/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/cjs/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/cjs/utils/constants/index.js +4 -1
- package/cjs/utils/decompress/index.js +427 -0
- package/cjs/utils/murmur3/{commons.js → common.js} +2 -6
- package/cjs/utils/murmur3/murmur3.js +11 -12
- package/cjs/utils/murmur3/murmur3_128.js +7 -142
- package/cjs/utils/murmur3/murmur3_128_x86.js +154 -0
- package/cjs/utils/murmur3/murmur3_64.js +36 -0
- package/cjs/utils/murmur3/utfx.js +100 -106
- package/cjs/utils/promise/wrapper.js +14 -11
- package/cjs/utils/settingsValidation/index.js +5 -2
- package/cjs/utils/settingsValidation/localhost/index.js +20 -0
- package/cjs/utils/settingsValidation/splitFilters.js +0 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +18 -8
- package/cjs/utils/settingsValidation/url.js +1 -1
- package/esm/evaluator/matchers/matcherTypes.js +2 -2
- package/esm/evaluator/matchersTransform/index.js +12 -12
- package/esm/evaluator/value/sanitize.js +7 -7
- package/esm/listeners/browser.js +1 -2
- package/esm/listeners/node.js +0 -3
- package/esm/logger/constants.js +2 -0
- package/esm/logger/messages/error.js +3 -2
- package/esm/logger/messages/info.js +2 -2
- package/esm/logger/messages/warn.js +2 -1
- package/esm/readiness/readinessManager.js +10 -7
- package/esm/sdkFactory/index.js +1 -4
- package/esm/services/splitApi.js +1 -1
- package/esm/services/splitHttpClient.js +5 -4
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/inLocalStorage/index.js +5 -2
- package/esm/storages/inMemory/InMemoryStorage.js +2 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/esm/storages/inRedis/index.js +5 -2
- package/esm/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +6 -7
- package/esm/storages/pluggable/index.js +5 -2
- package/esm/storages/pluggable/wrapperAdapter.js +0 -1
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +90 -88
- package/esm/sync/offline/splitsParser/splitsParserFromSettings.js +43 -41
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +15 -5
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/esm/sync/streaming/SSEClient/index.js +0 -11
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/esm/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/esm/sync/streaming/SSEHandler/index.js +9 -10
- package/esm/sync/streaming/SSEHandler/types.js +13 -1
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/esm/sync/streaming/constants.js +2 -0
- package/esm/sync/streaming/mySegmentsV2utils.js +69 -0
- package/esm/sync/streaming/pushManager.js +143 -42
- package/esm/sync/submitters/metricsSyncTask.js +1 -1
- package/esm/sync/submitters/submitterSyncTask.js +2 -2
- package/esm/sync/syncManagerFromFile.js +11 -0
- package/esm/sync/syncManagerFromObject.js +10 -0
- package/esm/sync/syncManagerOffline.js +3 -3
- package/esm/sync/syncManagerOnline.js +5 -3
- package/esm/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/esm/trackers/impressionObserver/buildKey.js +2 -9
- package/esm/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/esm/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/esm/utils/constants/index.js +3 -0
- package/esm/utils/decompress/index.js +424 -0
- package/esm/utils/murmur3/{commons.js → common.js} +1 -4
- package/esm/utils/murmur3/murmur3.js +1 -2
- package/esm/utils/murmur3/murmur3_128.js +7 -142
- package/esm/utils/murmur3/murmur3_128_x86.js +150 -0
- package/esm/utils/murmur3/murmur3_64.js +32 -0
- package/esm/utils/murmur3/utfx.js +96 -106
- package/esm/utils/promise/wrapper.js +14 -11
- package/esm/utils/settingsValidation/index.js +5 -2
- package/esm/utils/settingsValidation/localhost/index.js +16 -0
- package/esm/utils/settingsValidation/splitFilters.js +0 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +16 -7
- package/esm/utils/settingsValidation/url.js +1 -1
- package/package.json +5 -5
- package/src/evaluator/matchers/matcherTypes.ts +2 -2
- package/src/evaluator/matchersTransform/index.ts +12 -12
- package/src/evaluator/value/sanitize.ts +7 -7
- package/src/listeners/browser.ts +1 -1
- package/src/listeners/node.ts +1 -2
- package/src/logger/constants.ts +2 -0
- package/src/logger/messages/error.ts +3 -2
- package/src/logger/messages/info.ts +2 -2
- package/src/logger/messages/warn.ts +3 -1
- package/src/readiness/readinessManager.ts +9 -7
- package/src/sdkFactory/index.ts +1 -3
- package/src/sdkFactory/types.ts +3 -3
- package/src/services/splitApi.ts +2 -3
- package/src/services/splitHttpClient.ts +6 -5
- package/src/services/types.ts +5 -5
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/inLocalStorage/index.ts +8 -4
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +3 -1
- package/src/storages/inRedis/index.ts +8 -4
- package/src/storages/pluggable/SplitsCachePluggable.ts +3 -1
- package/src/storages/pluggable/inMemoryWrapper.ts +6 -7
- package/src/storages/pluggable/index.ts +8 -4
- package/src/storages/pluggable/wrapperAdapter.ts +0 -1
- package/src/storages/types.ts +18 -15
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +110 -105
- package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +45 -41
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +15 -5
- package/src/sync/polling/types.ts +2 -1
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +28 -10
- package/src/sync/streaming/AuthClient/types.ts +3 -0
- package/src/sync/streaming/SSEClient/index.ts +1 -15
- package/src/sync/streaming/SSEClient/types.ts +0 -1
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +8 -0
- package/src/sync/streaming/SSEHandler/NotificationParser.ts +4 -2
- package/src/sync/streaming/SSEHandler/index.ts +11 -20
- package/src/sync/streaming/SSEHandler/types.ts +37 -3
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +7 -6
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +2 -1
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +4 -3
- package/src/sync/streaming/UpdateWorkers/types.ts +1 -1
- package/src/sync/streaming/constants.ts +2 -0
- package/src/sync/streaming/mySegmentsV2utils.ts +77 -0
- package/src/sync/streaming/pushManager.ts +139 -42
- package/src/sync/streaming/types.ts +14 -22
- package/src/sync/submitters/metricsSyncTask.ts +1 -1
- package/src/sync/submitters/submitterSyncTask.ts +2 -1
- package/src/sync/syncManagerFromFile.ts +13 -0
- package/src/sync/syncManagerFromObject.ts +12 -0
- package/src/sync/syncManagerOffline.ts +3 -3
- package/src/sync/syncManagerOnline.ts +6 -3
- package/src/trackers/impressionObserver/ImpressionObserver.ts +4 -6
- package/src/trackers/impressionObserver/buildKey.ts +2 -16
- package/src/trackers/impressionObserver/impressionObserverCS.ts +2 -2
- package/src/trackers/impressionObserver/impressionObserverSS.ts +3 -3
- package/src/types.ts +16 -2
- package/src/utils/constants/index.ts +6 -1
- package/src/utils/decompress/index.ts +429 -0
- package/src/utils/murmur3/{commons.ts → common.ts} +1 -5
- package/src/utils/murmur3/murmur3.ts +5 -5
- package/src/utils/murmur3/murmur3_128.ts +7 -180
- package/src/utils/murmur3/murmur3_128_x86.ts +188 -0
- package/src/utils/murmur3/murmur3_64.ts +36 -0
- package/src/utils/murmur3/utfx.ts +92 -110
- package/src/utils/promise/wrapper.ts +12 -9
- package/src/utils/settingsValidation/index.ts +8 -4
- package/src/utils/settingsValidation/localhost/index.ts +19 -0
- package/src/utils/settingsValidation/splitFilters.ts +0 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +21 -8
- package/src/utils/settingsValidation/types.ts +2 -11
- package/src/utils/settingsValidation/url.ts +1 -1
- package/types/evaluator/matchers/matcherTypes.d.ts +2 -2
- package/types/listeners/browser.d.ts +1 -0
- package/types/listeners/node.d.ts +0 -1
- package/types/logger/constants.d.ts +2 -0
- package/types/sdkFactory/types.d.ts +3 -3
- package/types/services/types.d.ts +1 -0
- package/types/storages/inLocalStorage/index.d.ts +2 -2
- package/types/storages/inMemory/InMemoryStorage.d.ts +3 -0
- package/types/storages/inMemory/InMemoryStorageCS.d.ts +3 -0
- package/types/storages/inRedis/index.d.ts +2 -2
- package/types/storages/pluggable/index.d.ts +2 -2
- package/types/storages/types.d.ts +15 -15
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -7
- package/types/sync/offline/splitsParser/splitsParserFromSettings.d.ts +1 -5
- package/types/sync/polling/types.d.ts +2 -1
- package/types/sync/streaming/AuthClient/indexV1.d.ts +12 -0
- package/types/sync/streaming/AuthClient/indexV2.d.ts +8 -0
- package/types/sync/streaming/AuthClient/types.d.ts +2 -0
- package/types/sync/streaming/SSEClient/index.d.ts +1 -9
- package/types/sync/streaming/SSEClient/types.d.ts +0 -1
- package/types/sync/streaming/SSEHandler/NotificationParser.d.ts +3 -2
- package/types/sync/streaming/SSEHandler/types.d.ts +30 -2
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +4 -3
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +2 -1
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +3 -2
- package/types/sync/streaming/UpdateWorkers/types.d.ts +1 -1
- package/types/sync/streaming/constants.d.ts +3 -1
- package/types/sync/streaming/mySegmentsV2utils.d.ts +27 -0
- package/types/sync/streaming/pushManagerNoUsers.d.ts +13 -0
- package/types/sync/streaming/types.d.ts +9 -5
- package/types/sync/submitters/submitterSyncTask.d.ts +1 -1
- package/types/sync/syncManagerFromFile.d.ts +2 -0
- package/types/sync/syncManagerFromObject.d.ts +2 -0
- package/types/sync/syncManagerOffline.d.ts +1 -1
- package/types/trackers/impressionObserver/ImpressionObserver.d.ts +2 -2
- package/types/trackers/impressionObserver/buildKey.d.ts +1 -1
- package/types/trackers/impressionObserver/impressionObserverCS.d.ts +2 -2
- package/types/trackers/impressionObserver/impressionObserverSS.d.ts +2 -2
- package/types/types.d.ts +16 -2
- package/types/utils/constants/index.d.ts +5 -1
- package/types/utils/decompress/index.d.ts +16 -0
- package/types/utils/murmur3/common.d.ts +12 -0
- package/types/utils/murmur3/murmur3.d.ts +2 -2
- package/types/utils/murmur3/murmur3_128.d.ts +5 -0
- package/types/utils/murmur3/murmur3_128_x86.d.ts +7 -0
- package/types/utils/murmur3/murmur3_64.d.ts +10 -0
- package/types/utils/murmur3/utfx.d.ts +24 -6
- package/types/utils/settingsValidation/index.d.ts +3 -2
- package/types/utils/settingsValidation/localhost/index.d.ts +9 -0
- package/types/utils/settingsValidation/storage/storageCS.d.ts +7 -1
- package/types/utils/settingsValidation/types.d.ts +2 -10
- package/cjs/sync/streaming/pushManagerCS.js +0 -179
- package/cjs/sync/streaming/pushManagerSS.js +0 -128
- package/esm/sync/streaming/pushManagerCS.js +0 -175
- package/esm/sync/streaming/pushManagerSS.js +0 -124
- package/src/sync/streaming/pushManagerCS.ts +0 -238
- package/src/sync/streaming/pushManagerSS.ts +0 -177
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import objectAssign from 'object-assign';
|
|
2
|
-
import { MY_SEGMENTS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants';
|
|
3
|
-
import Backoff from '../../utils/Backoff';
|
|
4
|
-
import SSEHandlerFactory from './SSEHandler';
|
|
5
|
-
import MySegmentsUpdateWorker from './UpdateWorkers/MySegmentsUpdateWorker';
|
|
6
|
-
import SplitsUpdateWorker from './UpdateWorkers/SplitsUpdateWorker';
|
|
7
|
-
import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
8
|
-
import { forOwn } from '../../utils/lang';
|
|
9
|
-
import SSEClient from './SSEClient';
|
|
10
|
-
import { getMatching } from '../../utils/key';
|
|
11
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants';
|
|
12
|
-
/**
|
|
13
|
-
* PushManager factory for client-side, with support for multiple clients.
|
|
14
|
-
* It assumes settings contains a key.
|
|
15
|
-
*/
|
|
16
|
-
export default function pushManagerCSFactory(pollingManager, storage, readiness, fetchAuth, platform, settings) {
|
|
17
|
-
var log = settings.log;
|
|
18
|
-
var sseClient;
|
|
19
|
-
try {
|
|
20
|
-
// `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native).
|
|
21
|
-
sseClient = new SSEClient(settings, false, platform.getEventSource);
|
|
22
|
-
}
|
|
23
|
-
catch (e) {
|
|
24
|
-
log.warn(STREAMING_FALLBACK, [e]);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
var authenticate = authenticateFactory(fetchAuth);
|
|
28
|
-
// init feedback loop
|
|
29
|
-
var pushEmitter = new platform.EventEmitter();
|
|
30
|
-
var sseHandler = SSEHandlerFactory(log, pushEmitter);
|
|
31
|
-
sseClient.setEventHandler(sseHandler);
|
|
32
|
-
// [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
|
|
33
|
-
var userKeyHashes = {};
|
|
34
|
-
var userKey = getMatching(settings.core.key); // matching key of main client
|
|
35
|
-
var hash = hashUserKey(userKey);
|
|
36
|
-
userKeyHashes[hash] = userKey;
|
|
37
|
-
// [Only for client-side] map of user keys to their corresponding MySegmentsUpdateWorkers. It has a two-fold intention:
|
|
38
|
-
// - stop workers all together when push is disconnected
|
|
39
|
-
// - keep the current list of user keys to authenticate
|
|
40
|
-
var workers = {};
|
|
41
|
-
// init workers
|
|
42
|
-
var mySegmentsUpdateWorker = new MySegmentsUpdateWorker(pollingManager.segmentsSyncTask);
|
|
43
|
-
workers[userKey] = mySegmentsUpdateWorker;
|
|
44
|
-
var splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits);
|
|
45
|
-
// [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
|
|
46
|
-
var connectForNewClient = false;
|
|
47
|
-
// flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error.
|
|
48
|
-
// It is used to halt the `connectPush` process if it was in progress.
|
|
49
|
-
var disconnected;
|
|
50
|
-
/** PushManager functions related to initialization */
|
|
51
|
-
var connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase);
|
|
52
|
-
var timeoutId;
|
|
53
|
-
function scheduleTokenRefresh(issuedAt, expirationTime) {
|
|
54
|
-
// clear scheduled token refresh if exists (needed when resuming PUSH)
|
|
55
|
-
if (timeoutId)
|
|
56
|
-
clearTimeout(timeoutId);
|
|
57
|
-
// Set token refresh 10 minutes before expirationTime
|
|
58
|
-
var delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION;
|
|
59
|
-
log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]);
|
|
60
|
-
timeoutId = setTimeout(connectPush, delayInSeconds * 1000);
|
|
61
|
-
}
|
|
62
|
-
function connectPush() {
|
|
63
|
-
disconnected = false;
|
|
64
|
-
log.info(STREAMING_CONNECTING);
|
|
65
|
-
var userKeys = Object.keys(workers); // [Only for client-side]
|
|
66
|
-
authenticate(userKeys).then(function (authData) {
|
|
67
|
-
if (disconnected)
|
|
68
|
-
return;
|
|
69
|
-
// 'pushEnabled: false' is handled as a PUSH_NONRETRYABLE_ERROR instead of PUSH_SUBSYSTEM_DOWN, in order to
|
|
70
|
-
// close the sseClient in case the org has been bloqued while the instance was connected to streaming
|
|
71
|
-
if (!authData.pushEnabled) {
|
|
72
|
-
log.info(STREAMING_DISABLED);
|
|
73
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
// [Only for client-side] don't open SSE connection if a new shared client was added, since it means that a new authentication is taking place
|
|
77
|
-
if (userKeys && userKeys.length < Object.keys(workers).length)
|
|
78
|
-
return;
|
|
79
|
-
// Connect to SSE and schedule refresh token
|
|
80
|
-
var decodedToken = authData.decodedToken;
|
|
81
|
-
sseClient.open(authData);
|
|
82
|
-
scheduleTokenRefresh(decodedToken.iat, decodedToken.exp);
|
|
83
|
-
}).catch(function (error) {
|
|
84
|
-
if (disconnected)
|
|
85
|
-
return;
|
|
86
|
-
log.error(ERROR_STREAMING_AUTH, [error.message]);
|
|
87
|
-
// Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side)
|
|
88
|
-
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
89
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
// Handle other HTTP and network errors as recoverable errors
|
|
93
|
-
pushEmitter.emit(PUSH_RETRYABLE_ERROR);
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
// close SSE connection and cancel scheduled tasks
|
|
97
|
-
function disconnectPush() {
|
|
98
|
-
sseClient.close();
|
|
99
|
-
disconnected = true;
|
|
100
|
-
log.info(STREAMING_DISCONNECTING);
|
|
101
|
-
if (timeoutId)
|
|
102
|
-
clearTimeout(timeoutId);
|
|
103
|
-
connectPushRetryBackoff.reset();
|
|
104
|
-
stopWorkers();
|
|
105
|
-
}
|
|
106
|
-
// cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
|
|
107
|
-
function stopWorkers() {
|
|
108
|
-
splitsUpdateWorker.backoff.reset();
|
|
109
|
-
forOwn(workers, function (worker) { return worker.backoff.reset(); });
|
|
110
|
-
}
|
|
111
|
-
pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers);
|
|
112
|
-
// restart backoff retry counter once push is connected
|
|
113
|
-
pushEmitter.on(PUSH_SUBSYSTEM_UP, function () { connectPushRetryBackoff.reset(); });
|
|
114
|
-
/** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
|
|
115
|
-
pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
|
|
116
|
-
// Note: `stopWorkers` is been called twice, but it is not harmful
|
|
117
|
-
disconnectPush();
|
|
118
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
119
|
-
});
|
|
120
|
-
/** Fallbacking with retry due to recoverable SSE and Authentication errors */
|
|
121
|
-
pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() {
|
|
122
|
-
// SSE connection is closed to avoid repeated errors due to retries
|
|
123
|
-
sseClient.close();
|
|
124
|
-
// retry streaming reconnect with backoff algorithm
|
|
125
|
-
var delayInMillis = connectPushRetryBackoff.scheduleCall();
|
|
126
|
-
log.info(STREAMING_RECONNECT, [delayInMillis / 1000]);
|
|
127
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
128
|
-
});
|
|
129
|
-
/** Functions related to synchronization (Queues and Workers in the spec) */
|
|
130
|
-
pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit);
|
|
131
|
-
pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put);
|
|
132
|
-
// [Only for client-side]
|
|
133
|
-
pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) {
|
|
134
|
-
var userKeyHash = channel.split('_')[2];
|
|
135
|
-
var userKey = userKeyHashes[userKeyHash];
|
|
136
|
-
if (userKey && workers[userKey]) { // check context since it can be undefined if client has been destroyed
|
|
137
|
-
var mySegmentsUpdateWorker_1 = workers[userKey];
|
|
138
|
-
mySegmentsUpdateWorker_1.put(parsedData.changeNumber, parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
return objectAssign(
|
|
142
|
-
// Expose Event Emitter functionality and Event constants
|
|
143
|
-
Object.create(pushEmitter), {
|
|
144
|
-
// Expose functionality for starting and stoping push mode:
|
|
145
|
-
stop: disconnectPush,
|
|
146
|
-
start: function () {
|
|
147
|
-
// Run in next event-loop cycle for optimization: if multiple clients are created in the same cycle than the factory, only one authentication is performed.
|
|
148
|
-
setTimeout(connectPush);
|
|
149
|
-
},
|
|
150
|
-
// [Only for client-side]
|
|
151
|
-
add: function (userKey, mySegmentsSyncTask) {
|
|
152
|
-
var mySegmentsUpdateWorker = new MySegmentsUpdateWorker(mySegmentsSyncTask);
|
|
153
|
-
workers[userKey] = mySegmentsUpdateWorker;
|
|
154
|
-
var hash = hashUserKey(userKey);
|
|
155
|
-
if (!userKeyHashes[hash]) {
|
|
156
|
-
userKeyHashes[hash] = userKey;
|
|
157
|
-
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
158
|
-
}
|
|
159
|
-
// Reconnects in case of a new client.
|
|
160
|
-
// Run in next event-loop cycle to save authentication calls
|
|
161
|
-
// in case the user is creating several clients in the current cycle.
|
|
162
|
-
setTimeout(function checkForReconnect() {
|
|
163
|
-
if (connectForNewClient) {
|
|
164
|
-
connectForNewClient = false;
|
|
165
|
-
connectPush();
|
|
166
|
-
}
|
|
167
|
-
}, 0);
|
|
168
|
-
},
|
|
169
|
-
// [Only for client-side]
|
|
170
|
-
remove: function (userKey) {
|
|
171
|
-
var hash = hashUserKey(userKey);
|
|
172
|
-
delete userKeyHashes[hash];
|
|
173
|
-
}
|
|
174
|
-
});
|
|
175
|
-
}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import objectAssign from 'object-assign';
|
|
2
|
-
import { PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants';
|
|
3
|
-
import Backoff from '../../utils/Backoff';
|
|
4
|
-
import SSEHandlerFactory from './SSEHandler';
|
|
5
|
-
import SegmentsUpdateWorker from './UpdateWorkers/SegmentsUpdateWorker';
|
|
6
|
-
import SplitsUpdateWorker from './UpdateWorkers/SplitsUpdateWorker';
|
|
7
|
-
import { authenticateFactory } from './AuthClient';
|
|
8
|
-
import SSEClient from './SSEClient';
|
|
9
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants';
|
|
10
|
-
/**
|
|
11
|
-
* PushManager factory for server-side
|
|
12
|
-
*/
|
|
13
|
-
export default function pushManagerSSFactory(pollingManager, storage, readiness, fetchAuth, platform, settings) {
|
|
14
|
-
var log = settings.log;
|
|
15
|
-
var sseClient;
|
|
16
|
-
try {
|
|
17
|
-
sseClient = new SSEClient(settings, true, platform.getEventSource);
|
|
18
|
-
}
|
|
19
|
-
catch (e) {
|
|
20
|
-
log.warn(STREAMING_FALLBACK, [e]);
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
var authenticate = authenticateFactory(fetchAuth);
|
|
24
|
-
// init feedback loop (pushEmitter)
|
|
25
|
-
var pushEmitter = new platform.EventEmitter();
|
|
26
|
-
var sseHandler = SSEHandlerFactory(log, pushEmitter);
|
|
27
|
-
sseClient.setEventHandler(sseHandler);
|
|
28
|
-
// init workers
|
|
29
|
-
var splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits, pollingManager.segmentsSyncTask);
|
|
30
|
-
var segmentsUpdateWorker = new SegmentsUpdateWorker(storage.segments, pollingManager.segmentsSyncTask);
|
|
31
|
-
// flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error.
|
|
32
|
-
// It is used to halt the `connectPush` process if it was in progress.
|
|
33
|
-
var disconnected;
|
|
34
|
-
/** PushManager functions related to initialization */
|
|
35
|
-
var connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase);
|
|
36
|
-
var timeoutId;
|
|
37
|
-
function scheduleTokenRefresh(issuedAt, expirationTime) {
|
|
38
|
-
// clear scheduled token refresh if exists (needed when resuming PUSH)
|
|
39
|
-
if (timeoutId)
|
|
40
|
-
clearTimeout(timeoutId);
|
|
41
|
-
// Set token refresh 10 minutes before expirationTime
|
|
42
|
-
var delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION;
|
|
43
|
-
log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]);
|
|
44
|
-
timeoutId = setTimeout(connectPush, delayInSeconds * 1000);
|
|
45
|
-
}
|
|
46
|
-
function connectPush() {
|
|
47
|
-
disconnected = false;
|
|
48
|
-
log.info(STREAMING_CONNECTING);
|
|
49
|
-
authenticate().then(function (authData) {
|
|
50
|
-
if (disconnected)
|
|
51
|
-
return;
|
|
52
|
-
// 'pushEnabled: false' is handled as a PUSH_NONRETRYABLE_ERROR instead of PUSH_SUBSYSTEM_DOWN, in order to
|
|
53
|
-
// close the sseClient in case the org has been bloqued while the instance was connected to streaming
|
|
54
|
-
if (!authData.pushEnabled) {
|
|
55
|
-
log.info(STREAMING_DISABLED);
|
|
56
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
// Connect to SSE and schedule refresh token
|
|
60
|
-
var decodedToken = authData.decodedToken;
|
|
61
|
-
sseClient.open(authData);
|
|
62
|
-
scheduleTokenRefresh(decodedToken.iat, decodedToken.exp);
|
|
63
|
-
}).catch(function (error) {
|
|
64
|
-
if (disconnected)
|
|
65
|
-
return;
|
|
66
|
-
log.error(ERROR_STREAMING_AUTH, [error.message]);
|
|
67
|
-
// Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side)
|
|
68
|
-
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
69
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
// Handle other HTTP and network errors as recoverable errors
|
|
73
|
-
pushEmitter.emit(PUSH_RETRYABLE_ERROR);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
// close SSE connection and cancel scheduled tasks
|
|
77
|
-
function disconnectPush() {
|
|
78
|
-
sseClient.close();
|
|
79
|
-
disconnected = true;
|
|
80
|
-
log.info(STREAMING_DISCONNECTING);
|
|
81
|
-
if (timeoutId)
|
|
82
|
-
clearTimeout(timeoutId);
|
|
83
|
-
connectPushRetryBackoff.reset();
|
|
84
|
-
stopWorkers();
|
|
85
|
-
}
|
|
86
|
-
// cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
|
|
87
|
-
function stopWorkers() {
|
|
88
|
-
splitsUpdateWorker.backoff.reset();
|
|
89
|
-
segmentsUpdateWorker.backoff.reset();
|
|
90
|
-
}
|
|
91
|
-
pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers);
|
|
92
|
-
// restart backoff retry counter once push is connected
|
|
93
|
-
pushEmitter.on(PUSH_SUBSYSTEM_UP, function () { connectPushRetryBackoff.reset(); });
|
|
94
|
-
/** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
|
|
95
|
-
pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
|
|
96
|
-
// Note: `stopWorkers` is been called twice, but it is not harmful
|
|
97
|
-
disconnectPush();
|
|
98
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
99
|
-
});
|
|
100
|
-
/** Fallbacking with retry due to recoverable SSE and Authentication errors */
|
|
101
|
-
pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() {
|
|
102
|
-
// SSE connection is closed to avoid repeated errors due to retries
|
|
103
|
-
sseClient.close();
|
|
104
|
-
// retry streaming reconnect with backoff algorithm
|
|
105
|
-
var delayInMillis = connectPushRetryBackoff.scheduleCall();
|
|
106
|
-
log.info(STREAMING_RECONNECT, [delayInMillis / 1000]);
|
|
107
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
108
|
-
});
|
|
109
|
-
/** Functions related to synchronization (Queues and Workers in the spec) */
|
|
110
|
-
pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit);
|
|
111
|
-
pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put);
|
|
112
|
-
// [Only for server-side]
|
|
113
|
-
pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker.put);
|
|
114
|
-
return objectAssign(
|
|
115
|
-
// Expose Event Emitter functionality and Event constants
|
|
116
|
-
Object.create(pushEmitter), {
|
|
117
|
-
// Expose functionality for starting and stoping push mode:
|
|
118
|
-
stop: disconnectPush,
|
|
119
|
-
start: function () {
|
|
120
|
-
// Run in next event-loop cycle as in browser
|
|
121
|
-
setTimeout(connectPush);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
}
|
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { IPushEventEmitter, IPushManagerCS } from './types';
|
|
2
|
-
import { ISSEClient } from './SSEClient/types';
|
|
3
|
-
import { IStorageSync } from '../../storages/types';
|
|
4
|
-
import { IReadinessManager } from '../../readiness/types';
|
|
5
|
-
import { ISegmentsSyncTask, IPollingManager } from '../polling/types';
|
|
6
|
-
import { IUpdateWorker } from './UpdateWorkers/types';
|
|
7
|
-
import objectAssign from 'object-assign';
|
|
8
|
-
import { MY_SEGMENTS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP } from './constants';
|
|
9
|
-
import Backoff from '../../utils/Backoff';
|
|
10
|
-
import SSEHandlerFactory from './SSEHandler';
|
|
11
|
-
import MySegmentsUpdateWorker from './UpdateWorkers/MySegmentsUpdateWorker';
|
|
12
|
-
import SplitsUpdateWorker from './UpdateWorkers/SplitsUpdateWorker';
|
|
13
|
-
import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
14
|
-
import { forOwn } from '../../utils/lang';
|
|
15
|
-
import SSEClient from './SSEClient';
|
|
16
|
-
import { IFetchAuth } from '../../services/types';
|
|
17
|
-
import { ISettings } from '../../types';
|
|
18
|
-
import { getMatching } from '../../utils/key';
|
|
19
|
-
import { IPlatform } from '../../sdkFactory/types';
|
|
20
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT } from '../../logger/constants';
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* PushManager factory for client-side, with support for multiple clients.
|
|
24
|
-
* It assumes settings contains a key.
|
|
25
|
-
*/
|
|
26
|
-
export default function pushManagerCSFactory(
|
|
27
|
-
pollingManager: IPollingManager,
|
|
28
|
-
storage: IStorageSync,
|
|
29
|
-
readiness: IReadinessManager,
|
|
30
|
-
fetchAuth: IFetchAuth,
|
|
31
|
-
platform: IPlatform,
|
|
32
|
-
settings: ISettings
|
|
33
|
-
): IPushManagerCS | undefined {
|
|
34
|
-
|
|
35
|
-
const log = settings.log;
|
|
36
|
-
|
|
37
|
-
let sseClient: ISSEClient;
|
|
38
|
-
try {
|
|
39
|
-
// `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native).
|
|
40
|
-
sseClient = new SSEClient(settings, false, platform.getEventSource);
|
|
41
|
-
} catch (e) {
|
|
42
|
-
log.warn(STREAMING_FALLBACK, [e]);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const authenticate = authenticateFactory(fetchAuth);
|
|
46
|
-
|
|
47
|
-
// init feedback loop
|
|
48
|
-
const pushEmitter = new platform.EventEmitter() as IPushEventEmitter;
|
|
49
|
-
const sseHandler = SSEHandlerFactory(log, pushEmitter);
|
|
50
|
-
sseClient.setEventHandler(sseHandler);
|
|
51
|
-
|
|
52
|
-
// [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
|
|
53
|
-
const userKeyHashes: Record<string, string> = {};
|
|
54
|
-
const userKey = getMatching(settings.core.key); // matching key of main client
|
|
55
|
-
const hash = hashUserKey(userKey);
|
|
56
|
-
userKeyHashes[hash] = userKey;
|
|
57
|
-
|
|
58
|
-
// [Only for client-side] map of user keys to their corresponding MySegmentsUpdateWorkers. It has a two-fold intention:
|
|
59
|
-
// - stop workers all together when push is disconnected
|
|
60
|
-
// - keep the current list of user keys to authenticate
|
|
61
|
-
const workers: Record<string, IUpdateWorker> = {};
|
|
62
|
-
|
|
63
|
-
// init workers
|
|
64
|
-
const mySegmentsUpdateWorker = new MySegmentsUpdateWorker(pollingManager.segmentsSyncTask);
|
|
65
|
-
workers[userKey] = mySegmentsUpdateWorker;
|
|
66
|
-
const splitsUpdateWorker = new SplitsUpdateWorker(storage.splits, pollingManager.splitsSyncTask, readiness.splits);
|
|
67
|
-
|
|
68
|
-
// [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
|
|
69
|
-
let connectForNewClient = false;
|
|
70
|
-
|
|
71
|
-
// flag that indicates if `disconnectPush` was called, either by the SyncManager (when the client is destroyed) or by a PUSH_NONRETRYABLE_ERROR error.
|
|
72
|
-
// It is used to halt the `connectPush` process if it was in progress.
|
|
73
|
-
let disconnected: boolean | undefined;
|
|
74
|
-
|
|
75
|
-
/** PushManager functions related to initialization */
|
|
76
|
-
|
|
77
|
-
const connectPushRetryBackoff = new Backoff(connectPush, settings.scheduler.pushRetryBackoffBase);
|
|
78
|
-
|
|
79
|
-
let timeoutId: ReturnType<typeof setTimeout>;
|
|
80
|
-
|
|
81
|
-
function scheduleTokenRefresh(issuedAt: number, expirationTime: number) {
|
|
82
|
-
// clear scheduled token refresh if exists (needed when resuming PUSH)
|
|
83
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
84
|
-
|
|
85
|
-
// Set token refresh 10 minutes before expirationTime
|
|
86
|
-
const delayInSeconds = expirationTime - issuedAt - SECONDS_BEFORE_EXPIRATION;
|
|
87
|
-
|
|
88
|
-
log.info(STREAMING_REFRESH_TOKEN, [delayInSeconds]);
|
|
89
|
-
|
|
90
|
-
timeoutId = setTimeout(connectPush, delayInSeconds * 1000);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function connectPush() {
|
|
94
|
-
disconnected = false;
|
|
95
|
-
log.info(STREAMING_CONNECTING);
|
|
96
|
-
|
|
97
|
-
const userKeys = Object.keys(workers); // [Only for client-side]
|
|
98
|
-
authenticate(userKeys).then(
|
|
99
|
-
function (authData) {
|
|
100
|
-
if (disconnected) return;
|
|
101
|
-
|
|
102
|
-
// 'pushEnabled: false' is handled as a PUSH_NONRETRYABLE_ERROR instead of PUSH_SUBSYSTEM_DOWN, in order to
|
|
103
|
-
// close the sseClient in case the org has been bloqued while the instance was connected to streaming
|
|
104
|
-
if (!authData.pushEnabled) {
|
|
105
|
-
log.info(STREAMING_DISABLED);
|
|
106
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// [Only for client-side] don't open SSE connection if a new shared client was added, since it means that a new authentication is taking place
|
|
111
|
-
if (userKeys && userKeys.length < Object.keys(workers).length) return;
|
|
112
|
-
|
|
113
|
-
// Connect to SSE and schedule refresh token
|
|
114
|
-
const decodedToken = authData.decodedToken;
|
|
115
|
-
sseClient.open(authData);
|
|
116
|
-
scheduleTokenRefresh(decodedToken.iat, decodedToken.exp);
|
|
117
|
-
}
|
|
118
|
-
).catch(
|
|
119
|
-
function (error) {
|
|
120
|
-
if (disconnected) return;
|
|
121
|
-
|
|
122
|
-
log.error(ERROR_STREAMING_AUTH, [error.message]);
|
|
123
|
-
|
|
124
|
-
// Handle 4XX HTTP errors: 401 (invalid API Key) or 400 (using incorrect API Key, i.e., client-side API Key on server-side)
|
|
125
|
-
if (error.statusCode >= 400 && error.statusCode < 500) {
|
|
126
|
-
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Handle other HTTP and network errors as recoverable errors
|
|
131
|
-
pushEmitter.emit(PUSH_RETRYABLE_ERROR);
|
|
132
|
-
}
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// close SSE connection and cancel scheduled tasks
|
|
137
|
-
function disconnectPush() {
|
|
138
|
-
sseClient.close();
|
|
139
|
-
disconnected = true;
|
|
140
|
-
log.info(STREAMING_DISCONNECTING);
|
|
141
|
-
|
|
142
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
143
|
-
connectPushRetryBackoff.reset();
|
|
144
|
-
|
|
145
|
-
stopWorkers();
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// cancel scheduled fetch retries of Splits, Segments, and MySegments Update Workers
|
|
149
|
-
function stopWorkers() {
|
|
150
|
-
splitsUpdateWorker.backoff.reset();
|
|
151
|
-
forOwn(workers, worker => worker.backoff.reset());
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
pushEmitter.on(PUSH_SUBSYSTEM_DOWN, stopWorkers);
|
|
155
|
-
|
|
156
|
-
// restart backoff retry counter once push is connected
|
|
157
|
-
pushEmitter.on(PUSH_SUBSYSTEM_UP, () => { connectPushRetryBackoff.reset(); });
|
|
158
|
-
|
|
159
|
-
/** Fallbacking without retry due to: STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE and Authentication errors */
|
|
160
|
-
|
|
161
|
-
pushEmitter.on(PUSH_NONRETRYABLE_ERROR, function handleNonRetryableError() {
|
|
162
|
-
// Note: `stopWorkers` is been called twice, but it is not harmful
|
|
163
|
-
disconnectPush();
|
|
164
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
/** Fallbacking with retry due to recoverable SSE and Authentication errors */
|
|
168
|
-
|
|
169
|
-
pushEmitter.on(PUSH_RETRYABLE_ERROR, function handleRetryableError() { // HTTP or network error in SSE connection
|
|
170
|
-
// SSE connection is closed to avoid repeated errors due to retries
|
|
171
|
-
sseClient.close();
|
|
172
|
-
|
|
173
|
-
// retry streaming reconnect with backoff algorithm
|
|
174
|
-
let delayInMillis = connectPushRetryBackoff.scheduleCall();
|
|
175
|
-
|
|
176
|
-
log.info(STREAMING_RECONNECT, [delayInMillis / 1000]);
|
|
177
|
-
|
|
178
|
-
pushEmitter.emit(PUSH_SUBSYSTEM_DOWN); // no harm if polling already
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
/** Functions related to synchronization (Queues and Workers in the spec) */
|
|
182
|
-
|
|
183
|
-
pushEmitter.on(SPLIT_KILL, splitsUpdateWorker.killSplit);
|
|
184
|
-
pushEmitter.on(SPLIT_UPDATE, splitsUpdateWorker.put);
|
|
185
|
-
// [Only for client-side]
|
|
186
|
-
pushEmitter.on(MY_SEGMENTS_UPDATE, function handleMySegmentsUpdate(parsedData, channel) {
|
|
187
|
-
const userKeyHash = channel.split('_')[2];
|
|
188
|
-
const userKey = userKeyHashes[userKeyHash];
|
|
189
|
-
if (userKey && workers[userKey]) { // check context since it can be undefined if client has been destroyed
|
|
190
|
-
const mySegmentsUpdateWorker = workers[userKey];
|
|
191
|
-
mySegmentsUpdateWorker.put(
|
|
192
|
-
parsedData.changeNumber,
|
|
193
|
-
parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
return objectAssign(
|
|
198
|
-
// Expose Event Emitter functionality and Event constants
|
|
199
|
-
Object.create(pushEmitter),
|
|
200
|
-
{
|
|
201
|
-
// Expose functionality for starting and stoping push mode:
|
|
202
|
-
stop: disconnectPush, // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which start polling.
|
|
203
|
-
|
|
204
|
-
start() {
|
|
205
|
-
// Run in next event-loop cycle for optimization: if multiple clients are created in the same cycle than the factory, only one authentication is performed.
|
|
206
|
-
setTimeout(connectPush);
|
|
207
|
-
},
|
|
208
|
-
|
|
209
|
-
// [Only for client-side]
|
|
210
|
-
add(userKey: string, mySegmentsSyncTask: ISegmentsSyncTask) {
|
|
211
|
-
const mySegmentsUpdateWorker = new MySegmentsUpdateWorker(mySegmentsSyncTask);
|
|
212
|
-
workers[userKey] = mySegmentsUpdateWorker;
|
|
213
|
-
|
|
214
|
-
const hash = hashUserKey(userKey);
|
|
215
|
-
|
|
216
|
-
if (!userKeyHashes[hash]) {
|
|
217
|
-
userKeyHashes[hash] = userKey;
|
|
218
|
-
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Reconnects in case of a new client.
|
|
222
|
-
// Run in next event-loop cycle to save authentication calls
|
|
223
|
-
// in case the user is creating several clients in the current cycle.
|
|
224
|
-
setTimeout(function checkForReconnect() {
|
|
225
|
-
if (connectForNewClient) {
|
|
226
|
-
connectForNewClient = false;
|
|
227
|
-
connectPush();
|
|
228
|
-
}
|
|
229
|
-
}, 0);
|
|
230
|
-
},
|
|
231
|
-
// [Only for client-side]
|
|
232
|
-
remove(userKey: string) {
|
|
233
|
-
const hash = hashUserKey(userKey);
|
|
234
|
-
delete userKeyHashes[hash];
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
);
|
|
238
|
-
}
|