@splitsoftware/splitio-commons 1.17.1-rc.4 → 1.17.1
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/CHANGES.txt +28 -29
- package/LICENSE +1 -1
- package/README.md +4 -3
- package/cjs/consent/sdkUserConsent.js +4 -2
- package/cjs/evaluator/matchers/index.js +1 -3
- package/cjs/evaluator/matchers/matcherTypes.js +0 -1
- package/cjs/evaluator/matchers/segment.js +0 -6
- package/cjs/evaluator/matchersTransform/index.js +1 -4
- package/cjs/evaluator/matchersTransform/segment.js +1 -3
- package/cjs/logger/constants.js +2 -2
- package/cjs/logger/messages/info.js +1 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +8 -18
- package/cjs/readiness/sdkReadinessManager.js +6 -5
- package/cjs/sdkClient/sdkClient.js +5 -5
- package/cjs/sdkClient/sdkClientMethod.js +1 -3
- package/cjs/sdkClient/sdkClientMethodCS.js +15 -9
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +15 -9
- package/cjs/sdkFactory/index.js +10 -32
- package/cjs/services/decorateHeaders.js +6 -1
- package/cjs/services/splitApi.js +5 -5
- package/cjs/services/splitHttpClient.js +5 -2
- package/cjs/storages/AbstractSegmentsCacheSync.js +33 -0
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -2
- package/cjs/storages/KeyBuilderCS.js +5 -23
- package/cjs/storages/dataLoader.js +1 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
- package/cjs/storages/inLocalStorage/index.js +2 -6
- package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -6
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
- package/cjs/storages/inMemory/SegmentsCacheInMemory.js +28 -14
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +9 -8
- package/cjs/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/cjs/storages/inRedis/SegmentsCacheInRedis.js +21 -15
- package/cjs/storages/inRedis/index.js +11 -5
- package/cjs/storages/pluggable/SegmentsCachePluggable.js +34 -13
- package/cjs/storages/pluggable/inMemoryWrapper.js +1 -1
- package/cjs/sync/offline/syncManagerOffline.js +11 -18
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +1 -1
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +28 -12
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/cjs/sync/streaming/AuthClient/index.js +1 -1
- package/cjs/sync/streaming/SSEHandler/index.js +5 -3
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +48 -107
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/cjs/sync/streaming/constants.js +3 -3
- package/cjs/sync/streaming/parseUtils.js +9 -14
- package/cjs/sync/streaming/pushManager.js +67 -69
- package/cjs/sync/syncManagerOnline.js +21 -20
- package/cjs/sync/syncTask.js +2 -2
- package/cjs/trackers/eventTracker.js +10 -12
- package/cjs/trackers/impressionsTracker.js +14 -16
- package/cjs/trackers/uniqueKeysTracker.js +3 -5
- package/cjs/utils/constants/index.js +4 -5
- package/cjs/utils/settingsValidation/index.js +1 -2
- package/esm/consent/sdkUserConsent.js +4 -2
- package/esm/evaluator/matchers/index.js +1 -3
- package/esm/evaluator/matchers/matcherTypes.js +0 -1
- package/esm/evaluator/matchers/segment.js +0 -6
- package/esm/evaluator/matchersTransform/index.js +1 -4
- package/esm/evaluator/matchersTransform/segment.js +1 -3
- package/esm/logger/constants.js +1 -1
- package/esm/logger/messages/info.js +1 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +8 -18
- package/esm/readiness/sdkReadinessManager.js +6 -5
- package/esm/sdkClient/sdkClient.js +5 -5
- package/esm/sdkClient/sdkClientMethod.js +1 -3
- package/esm/sdkClient/sdkClientMethodCS.js +13 -7
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +13 -7
- package/esm/sdkFactory/index.js +10 -32
- package/esm/services/decorateHeaders.js +4 -0
- package/esm/services/splitApi.js +6 -6
- package/esm/services/splitHttpClient.js +6 -3
- package/esm/storages/AbstractSegmentsCacheSync.js +30 -0
- package/esm/storages/AbstractSplitsCacheSync.js +2 -3
- package/esm/storages/KeyBuilderCS.js +4 -21
- package/esm/storages/dataLoader.js +1 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +56 -33
- package/esm/storages/inLocalStorage/index.js +3 -7
- package/esm/storages/inMemory/InMemoryStorageCS.js +1 -6
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +44 -13
- package/esm/storages/inMemory/SegmentsCacheInMemory.js +28 -14
- package/esm/storages/inMemory/SplitsCacheInMemory.js +9 -8
- package/esm/storages/inMemory/TelemetryCacheInMemory.js +10 -7
- package/esm/storages/inRedis/SegmentsCacheInRedis.js +21 -15
- package/esm/storages/inRedis/index.js +11 -5
- package/esm/storages/pluggable/SegmentsCachePluggable.js +34 -13
- package/esm/storages/pluggable/inMemoryWrapper.js +1 -1
- package/esm/sync/offline/syncManagerOffline.js +11 -18
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +8 -5
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +1 -1
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -15
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +28 -12
- package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
- package/esm/sync/streaming/AuthClient/index.js +1 -1
- package/esm/sync/streaming/SSEHandler/index.js +6 -4
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +49 -108
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
- package/esm/sync/streaming/constants.js +2 -2
- package/esm/sync/streaming/parseUtils.js +8 -12
- package/esm/sync/streaming/pushManager.js +70 -72
- package/esm/sync/syncManagerOnline.js +21 -20
- package/esm/sync/syncTask.js +2 -2
- package/esm/trackers/eventTracker.js +10 -12
- package/esm/trackers/impressionsTracker.js +14 -16
- package/esm/trackers/uniqueKeysTracker.js +3 -5
- package/esm/utils/constants/index.js +2 -3
- package/esm/utils/settingsValidation/index.js +1 -2
- package/package.json +2 -2
- package/src/consent/sdkUserConsent.ts +3 -2
- package/src/dtos/types.ts +7 -21
- package/src/evaluator/matchers/index.ts +0 -2
- package/src/evaluator/matchers/matcherTypes.ts +0 -1
- package/src/evaluator/matchers/segment.ts +0 -7
- package/src/evaluator/matchersTransform/index.ts +1 -4
- package/src/evaluator/matchersTransform/segment.ts +3 -5
- package/src/logger/constants.ts +1 -1
- package/src/logger/messages/info.ts +1 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +8 -19
- package/src/readiness/sdkReadinessManager.ts +7 -7
- package/src/readiness/types.ts +2 -5
- package/src/sdkClient/sdkClient.ts +5 -5
- package/src/sdkClient/sdkClientMethod.ts +1 -4
- package/src/sdkClient/sdkClientMethodCS.ts +15 -7
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +15 -7
- package/src/sdkFactory/index.ts +12 -35
- package/src/sdkFactory/types.ts +1 -4
- package/src/services/decorateHeaders.ts +5 -0
- package/src/services/splitApi.ts +7 -7
- package/src/services/splitHttpClient.ts +7 -4
- package/src/services/types.ts +2 -2
- package/src/storages/AbstractSegmentsCacheSync.ts +68 -0
- package/src/storages/AbstractSplitsCacheSync.ts +3 -4
- package/src/storages/KeyBuilderCS.ts +5 -34
- package/src/storages/dataLoader.ts +1 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +63 -33
- package/src/storages/inLocalStorage/index.ts +4 -8
- package/src/storages/inMemory/InMemoryStorageCS.ts +1 -6
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +47 -13
- package/src/storages/inMemory/SegmentsCacheInMemory.ts +27 -13
- package/src/storages/inMemory/SplitsCacheInMemory.ts +9 -7
- package/src/storages/inMemory/TelemetryCacheInMemory.ts +11 -7
- package/src/storages/inRedis/SegmentsCacheInRedis.ts +24 -15
- package/src/storages/inRedis/index.ts +12 -6
- package/src/storages/pluggable/SegmentsCachePluggable.ts +37 -13
- package/src/storages/pluggable/inMemoryWrapper.ts +1 -1
- package/src/storages/types.ts +17 -15
- package/src/sync/offline/syncManagerOffline.ts +13 -21
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +10 -8
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +2 -3
- package/src/sync/polling/pollingManagerCS.ts +4 -4
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +5 -4
- package/src/sync/polling/types.ts +6 -7
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +22 -19
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +29 -13
- package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
- package/src/sync/streaming/AuthClient/index.ts +1 -1
- package/src/sync/streaming/SSEClient/index.ts +6 -4
- package/src/sync/streaming/SSEHandler/index.ts +8 -5
- package/src/sync/streaming/SSEHandler/types.ts +15 -15
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +49 -116
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +4 -4
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
- package/src/sync/streaming/constants.ts +2 -2
- package/src/sync/streaming/parseUtils.ts +11 -19
- package/src/sync/streaming/pushManager.ts +72 -73
- package/src/sync/streaming/types.ts +10 -10
- package/src/sync/submitters/types.ts +5 -8
- package/src/sync/syncManagerOnline.ts +17 -17
- package/src/sync/syncTask.ts +2 -2
- package/src/sync/types.ts +1 -1
- package/src/trackers/eventTracker.ts +8 -11
- package/src/trackers/impressionsTracker.ts +10 -13
- package/src/trackers/types.ts +0 -1
- package/src/trackers/uniqueKeysTracker.ts +4 -6
- package/src/types.ts +1 -7
- package/src/utils/constants/index.ts +2 -3
- package/src/utils/settingsValidation/index.ts +2 -3
- package/src/utils/settingsValidation/types.ts +1 -1
- package/types/dtos/types.d.ts +7 -18
- package/types/evaluator/matchersTransform/segment.d.ts +2 -2
- package/types/logger/constants.d.ts +1 -1
- package/types/readiness/readinessManager.d.ts +2 -2
- package/types/readiness/sdkReadinessManager.d.ts +3 -2
- package/types/readiness/types.d.ts +2 -5
- package/types/sdkClient/sdkClientMethod.d.ts +1 -1
- package/types/sdkFactory/types.d.ts +1 -3
- package/types/services/decorateHeaders.d.ts +1 -0
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -2
- package/types/storages/AbstractSegmentsCacheSync.d.ts +11 -9
- package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
- package/types/storages/KeyBuilderCS.d.ts +2 -9
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +18 -8
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +13 -7
- package/types/storages/inMemory/SegmentsCacheInMemory.d.ts +8 -6
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +2 -1
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +6 -4
- package/types/storages/inRedis/SegmentsCacheInRedis.d.ts +4 -7
- package/types/storages/inRedis/index.d.ts +1 -1
- package/types/storages/pluggable/SegmentsCachePluggable.d.ts +17 -5
- package/types/storages/pluggable/inMemoryWrapper.d.ts +1 -1
- package/types/storages/types.d.ts +15 -11
- package/types/sync/polling/fetchers/mySegmentsFetcher.d.ts +2 -2
- package/types/sync/polling/fetchers/types.d.ts +2 -2
- package/types/sync/polling/syncTasks/mySegmentsSyncTask.d.ts +2 -2
- package/types/sync/polling/types.d.ts +4 -7
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -4
- package/types/sync/streaming/SSEHandler/types.d.ts +14 -16
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -4
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +1 -2
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +2 -3
- package/types/sync/streaming/UpdateWorkers/types.d.ts +2 -2
- package/types/sync/streaming/constants.d.ts +2 -2
- package/types/sync/streaming/parseUtils.d.ts +5 -4
- package/types/sync/streaming/types.d.ts +8 -8
- package/types/sync/submitters/types.d.ts +4 -7
- package/types/sync/types.d.ts +1 -1
- package/types/trackers/eventTracker.d.ts +1 -1
- package/types/trackers/impressionsTracker.d.ts +1 -1
- package/types/trackers/types.d.ts +0 -1
- package/types/types.d.ts +1 -7
- package/types/utils/constants/index.d.ts +2 -3
- package/types/utils/settingsValidation/types.d.ts +1 -1
- package/cjs/evaluator/matchers/large_segment.js +0 -16
- package/cjs/sdkClient/identity.js +0 -7
- package/cjs/storages/AbstractMySegmentsCacheSync.js +0 -60
- package/esm/evaluator/matchers/large_segment.js +0 -12
- package/esm/sdkClient/identity.js +0 -3
- package/esm/storages/AbstractMySegmentsCacheSync.js +0 -57
- package/src/evaluator/matchers/large_segment.ts +0 -18
- package/src/sdkClient/identity.ts +0 -5
- package/src/storages/AbstractMySegmentsCacheSync.ts +0 -94
- package/types/evaluator/matchers/large_segment.d.ts +0 -5
- package/types/evaluator/matchers/sember_inlist.d.ts +0 -3
- package/types/evaluator/matchersTransform/set.d.ts +0 -5
- package/types/evaluator/matchersTransform/string.d.ts +0 -7
- package/types/sdkClient/identity.d.ts +0 -2
- package/types/storages/AbstractMySegmentsCacheSync.d.ts +0 -39
- package/types/storages/AbstractSplitsCache.d.ts +0 -46
- package/types/sync/streaming/mySegmentsV2utils.d.ts +0 -27
- package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +0 -9
- package/types/sync/streaming/pushManager_Spec1_3.d.ts +0 -9
- package/types/trackers/impressionObserver/utils.d.ts +0 -5
- package/types/utils/inputValidation/sdkKey.d.ts +0 -7
- package/types/utils/inputValidation/splitExistance.d.ts +0 -7
- package/types/utils/inputValidation/trafficTypeExistance.d.ts +0 -9
- package/types/utils/redis/RedisMock.d.ts +0 -4
- package/types/utils/settingsValidation/logger/globalLogLevel.d.ts +0 -8
- /package/types/utils/{semVer.d.ts → Semver.d.ts} +0 -0
|
@@ -17,19 +17,25 @@ export interface InRedisStorageOptions {
|
|
|
17
17
|
options?: Record<string, any>
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
let RD: typeof RedisAdapter | undefined;
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
// Using `require` to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
|
|
24
|
+
// Redis storage is not supported with .mjs files.
|
|
25
|
+
RD = require('./RedisAdapter').RedisAdapter;
|
|
26
|
+
} catch (error) { /* empty */ }
|
|
27
|
+
|
|
20
28
|
/**
|
|
21
|
-
* InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
|
|
29
|
+
* InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
|
|
22
30
|
* @see {@link https://www.npmjs.com/package/ioredis}
|
|
23
31
|
*/
|
|
24
32
|
export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
|
|
25
33
|
|
|
26
|
-
// Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
|
|
27
|
-
// Redis storage is not supported with .mjs files.
|
|
28
|
-
const RD = require('./RedisAdapter').RedisAdapter;
|
|
29
|
-
|
|
30
34
|
const prefix = validatePrefix(options.prefix);
|
|
31
35
|
|
|
32
36
|
function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync {
|
|
37
|
+
if (!RD) throw new Error('The SDK Redis storage is unavailable. Make sure your runtime environment supports CommonJS (`require`) so the `ioredis` dependency can be imported.');
|
|
38
|
+
|
|
33
39
|
const { onReadyCb, settings, settings: { log, sync: { impressionsMode } } } = params;
|
|
34
40
|
const metadata = metadataBuilder(settings);
|
|
35
41
|
const keys = new KeyBuilderSS(prefix, metadata);
|
|
@@ -38,7 +44,7 @@ export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsy
|
|
|
38
44
|
const impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
|
|
39
45
|
const uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
|
|
40
46
|
|
|
41
|
-
//
|
|
47
|
+
// Subscription to Redis connect event in order to emit SDK_READY event on consumer mode
|
|
42
48
|
redisClient.on('connect', () => {
|
|
43
49
|
onReadyCb();
|
|
44
50
|
if (impressionCountsCache) impressionCountsCache.start();
|
|
@@ -23,20 +23,33 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
* The returned promise is resolved
|
|
28
|
-
* or rejected if
|
|
26
|
+
* Add a list of `segmentKeys` to the given segment `name`.
|
|
27
|
+
* The returned promise is resolved when the operation success
|
|
28
|
+
* or rejected if wrapper operation fails.
|
|
29
29
|
*/
|
|
30
|
-
|
|
30
|
+
addToSegment(name: string, segmentKeys: string[]) {
|
|
31
31
|
const segmentKey = this.keys.buildSegmentNameKey(name);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
if (segmentKeys.length) {
|
|
34
|
+
return this.wrapper.addItems(segmentKey, segmentKeys);
|
|
35
|
+
} else {
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Remove a list of `segmentKeys` from the given segment `name`.
|
|
42
|
+
* The returned promise is resolved when the operation success
|
|
43
|
+
* or rejected if wrapper operation fails.
|
|
44
|
+
*/
|
|
45
|
+
removeFromSegment(name: string, segmentKeys: string[]) {
|
|
46
|
+
const segmentKey = this.keys.buildSegmentNameKey(name);
|
|
47
|
+
|
|
48
|
+
if (segmentKeys.length) {
|
|
49
|
+
return this.wrapper.removeItems(segmentKey, segmentKeys);
|
|
50
|
+
} else {
|
|
51
|
+
return Promise.resolve();
|
|
52
|
+
}
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
/**
|
|
@@ -47,6 +60,17 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
|
|
|
47
60
|
return this.wrapper.itemContains(this.keys.buildSegmentNameKey(name), key);
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Set till number for the given segment `name`.
|
|
65
|
+
* The returned promise is resolved when the operation success,
|
|
66
|
+
* or rejected if it fails (e.g., wrapper operation fails).
|
|
67
|
+
*/
|
|
68
|
+
setChangeNumber(name: string, changeNumber: number) {
|
|
69
|
+
return this.wrapper.set(
|
|
70
|
+
this.keys.buildSegmentTillKey(name), changeNumber + ''
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
50
74
|
/**
|
|
51
75
|
* Get till number or -1 if it's not defined.
|
|
52
76
|
* The returned promise is resolved with the changeNumber or -1 if it doesn't exist or a wrapper operation fails.
|
|
@@ -56,10 +80,10 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
|
|
|
56
80
|
return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
|
|
57
81
|
const i = parseInt(value as string, 10);
|
|
58
82
|
|
|
59
|
-
return isNaNNumber(i) ?
|
|
83
|
+
return isNaNNumber(i) ? undefined : i;
|
|
60
84
|
}).catch((e) => {
|
|
61
85
|
this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
|
|
62
|
-
return
|
|
86
|
+
return undefined;
|
|
63
87
|
});
|
|
64
88
|
}
|
|
65
89
|
|
|
@@ -7,7 +7,7 @@ import { ISet, setToArray, _Set } from '../../utils/lang/sets';
|
|
|
7
7
|
* The `_cache` property is the object were items are stored.
|
|
8
8
|
* Intended for testing purposes.
|
|
9
9
|
*
|
|
10
|
-
* @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves
|
|
10
|
+
* @param connDelay delay in millis for `connect` resolve. If not provided, `connect` resolves inmediatelly.
|
|
11
11
|
*/
|
|
12
12
|
export function inMemoryWrapperFactory(connDelay?: number): IPluggableStorageWrapper & { _cache: Record<string, string | string[] | ISet<string>>, _setConnDelay(connDelay: number): void } {
|
|
13
13
|
|
package/src/storages/types.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { MaybeThenable, ISplit
|
|
2
|
-
import { MySegmentsData } from '../sync/polling/types';
|
|
1
|
+
import { MaybeThenable, ISplit } from '../dtos/types';
|
|
3
2
|
import { EventDataType, HttpErrors, HttpLatencies, ImpressionDataType, LastSync, Method, MethodExceptions, MethodLatencies, MultiMethodExceptions, MultiMethodLatencies, MultiConfigs, OperationType, StoredEventWithMetadata, StoredImpressionWithMetadata, StreamingEvent, UniqueKeysPayloadCs, UniqueKeysPayloadSs, TelemetryUsageStatsPayload, UpdatesFromSSEEnum } from '../sync/submitters/types';
|
|
4
3
|
import { SplitIO, ImpressionDTO, ISettings } from '../types';
|
|
5
4
|
import { ISet } from '../utils/lang/sets';
|
|
@@ -205,7 +204,7 @@ export interface ISplitsCacheBase {
|
|
|
205
204
|
getSplitNames(): MaybeThenable<string[]>,
|
|
206
205
|
// should never reject or throw an exception. Instead return true by default, asssuming the TT might exist.
|
|
207
206
|
trafficTypeExists(trafficType: string): MaybeThenable<boolean>,
|
|
208
|
-
// only for Client-Side
|
|
207
|
+
// only for Client-Side
|
|
209
208
|
usesSegments(): MaybeThenable<boolean>,
|
|
210
209
|
clear(): MaybeThenable<boolean | void>,
|
|
211
210
|
// should never reject or throw an exception. Instead return false by default, to avoid emitting SDK_READY_FROM_CACHE.
|
|
@@ -219,7 +218,7 @@ export interface ISplitsCacheSync extends ISplitsCacheBase {
|
|
|
219
218
|
removeSplits(names: string[]): boolean[],
|
|
220
219
|
getSplit(name: string): ISplit | null,
|
|
221
220
|
getSplits(names: string[]): Record<string, ISplit | null>,
|
|
222
|
-
setChangeNumber(changeNumber: number): boolean
|
|
221
|
+
setChangeNumber(changeNumber: number): boolean,
|
|
223
222
|
getChangeNumber(): number,
|
|
224
223
|
getAll(): ISplit[],
|
|
225
224
|
getSplitNames(): string[],
|
|
@@ -251,32 +250,38 @@ export interface ISplitsCacheAsync extends ISplitsCacheBase {
|
|
|
251
250
|
/** Segments cache */
|
|
252
251
|
|
|
253
252
|
export interface ISegmentsCacheBase {
|
|
253
|
+
addToSegment(name: string, segmentKeys: string[]): MaybeThenable<boolean | void> // different signature on Server and Client-Side
|
|
254
|
+
removeFromSegment(name: string, segmentKeys: string[]): MaybeThenable<boolean | void> // different signature on Server and Client-Side
|
|
254
255
|
isInSegment(name: string, key?: string): MaybeThenable<boolean> // different signature on Server and Client-Side
|
|
255
256
|
registerSegments(names: string[]): MaybeThenable<boolean | void> // only for Server-Side
|
|
256
257
|
getRegisteredSegments(): MaybeThenable<string[]> // only for Server-Side
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
setChangeNumber(name: string, changeNumber: number): MaybeThenable<boolean | void> // only for Server-Side
|
|
259
|
+
getChangeNumber(name: string): MaybeThenable<number | undefined> // only for Server-Side
|
|
259
260
|
clear(): MaybeThenable<boolean | void>
|
|
260
261
|
}
|
|
261
262
|
|
|
262
263
|
// Same API for both variants: SegmentsCache and MySegmentsCache (client-side API)
|
|
263
264
|
export interface ISegmentsCacheSync extends ISegmentsCacheBase {
|
|
265
|
+
addToSegment(name: string, segmentKeys?: string[]): boolean
|
|
266
|
+
removeFromSegment(name: string, segmentKeys?: string[]): boolean
|
|
264
267
|
isInSegment(name: string, key?: string): boolean
|
|
265
268
|
registerSegments(names: string[]): boolean
|
|
266
269
|
getRegisteredSegments(): string[]
|
|
267
270
|
getKeysCount(): number // only used for telemetry
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
resetSegments(
|
|
271
|
+
setChangeNumber(name: string, changeNumber: number): boolean
|
|
272
|
+
getChangeNumber(name: string): number | undefined
|
|
273
|
+
resetSegments(names: string[]): boolean // only for Sync Client-Side
|
|
271
274
|
clear(): void
|
|
272
275
|
}
|
|
273
276
|
|
|
274
277
|
export interface ISegmentsCacheAsync extends ISegmentsCacheBase {
|
|
278
|
+
addToSegment(name: string, segmentKeys: string[]): Promise<boolean | void>
|
|
279
|
+
removeFromSegment(name: string, segmentKeys: string[]): Promise<boolean | void>
|
|
275
280
|
isInSegment(name: string, key: string): Promise<boolean>
|
|
276
281
|
registerSegments(names: string[]): Promise<boolean | void>
|
|
277
282
|
getRegisteredSegments(): Promise<string[]>
|
|
278
|
-
|
|
279
|
-
|
|
283
|
+
setChangeNumber(name: string, changeNumber: number): Promise<boolean | void>
|
|
284
|
+
getChangeNumber(name: string): Promise<number | undefined>
|
|
280
285
|
clear(): Promise<boolean | void>
|
|
281
286
|
}
|
|
282
287
|
|
|
@@ -472,10 +477,7 @@ export interface IStorageSync extends IStorageBase<
|
|
|
472
477
|
IEventsCacheSync,
|
|
473
478
|
ITelemetryCacheSync,
|
|
474
479
|
IUniqueKeysCacheSync
|
|
475
|
-
> {
|
|
476
|
-
// Defined in client-side
|
|
477
|
-
largeSegments?: ISegmentsCacheSync,
|
|
478
|
-
}
|
|
480
|
+
> { }
|
|
479
481
|
|
|
480
482
|
export interface IStorageAsync extends IStorageBase<
|
|
481
483
|
ISplitsCacheAsync,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISyncManagerCS } from '../types';
|
|
1
|
+
import { ISyncManager, ISyncManagerCS } from '../types';
|
|
2
2
|
import { fromObjectSyncTaskFactory } from './syncTasks/fromObjectSyncTask';
|
|
3
3
|
import { objectAssign } from '../../utils/lang/objectAssign';
|
|
4
4
|
import { ISplitsParser } from './splitsParser/types';
|
|
@@ -29,34 +29,26 @@ export function syncManagerOfflineFactory(
|
|
|
29
29
|
storage,
|
|
30
30
|
}: ISdkFactoryContextSync): ISyncManagerCS {
|
|
31
31
|
|
|
32
|
-
const mainSyncManager = fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings);
|
|
33
|
-
const mainStart = mainSyncManager.start;
|
|
34
|
-
const sharedStarts: Array<() => void> = [];
|
|
35
|
-
|
|
36
32
|
return objectAssign(
|
|
37
|
-
|
|
33
|
+
fromObjectSyncTaskFactory(splitsParserFactory(), storage, readiness, settings),
|
|
38
34
|
{
|
|
39
|
-
start() {
|
|
40
|
-
mainStart();
|
|
41
|
-
sharedStarts.forEach(cb => cb());
|
|
42
|
-
sharedStarts.length = 0;
|
|
43
|
-
},
|
|
44
35
|
// fake flush, that resolves immediately
|
|
45
36
|
flush,
|
|
46
37
|
|
|
47
38
|
// [Only used for client-side]
|
|
48
|
-
shared(matchingKey: string, readinessManager: IReadinessManager) {
|
|
49
|
-
// In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
|
|
50
|
-
// SDK_READY cannot be emitted directly because this will not update the readiness status
|
|
51
|
-
function emitSdkReady() {
|
|
52
|
-
readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (mainSyncManager.isRunning()) setTimeout(emitSdkReady);
|
|
56
|
-
else sharedStarts.push(emitSdkReady);
|
|
57
|
-
|
|
39
|
+
shared(matchingKey: string, readinessManager: IReadinessManager): ISyncManager {
|
|
58
40
|
return {
|
|
41
|
+
start() {
|
|
42
|
+
// In LOCALHOST mode, shared clients are ready in the next event-loop cycle than created
|
|
43
|
+
// SDK_READY cannot be emitted directly because this will not update the readiness status
|
|
44
|
+
setTimeout(() => {
|
|
45
|
+
readinessManager.segments.emit(SDK_SEGMENTS_ARRIVED); // SDK_SPLITS_ARRIVED emitted by main SyncManager
|
|
46
|
+
}, 0);
|
|
47
|
+
},
|
|
59
48
|
stop() { },
|
|
49
|
+
isRunning() {
|
|
50
|
+
return true;
|
|
51
|
+
},
|
|
60
52
|
flush,
|
|
61
53
|
};
|
|
62
54
|
}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IFetchMySegments, IResponse } from '../../../services/types';
|
|
2
|
+
import { IMySegmentsResponseItem } from '../../../dtos/types';
|
|
3
3
|
import { IMySegmentsFetcher } from './types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Factory of MySegments fetcher.
|
|
7
7
|
* MySegments fetcher is a wrapper around `mySegments` API service that parses the response and handle errors.
|
|
8
8
|
*/
|
|
9
|
-
export function mySegmentsFetcherFactory(
|
|
9
|
+
export function mySegmentsFetcherFactory(fetchMySegments: IFetchMySegments): IMySegmentsFetcher {
|
|
10
10
|
|
|
11
11
|
return function mySegmentsFetcher(
|
|
12
12
|
userMatchingKey: string,
|
|
13
13
|
noCache?: boolean,
|
|
14
|
-
|
|
15
|
-
// Optional decorator for `fetchMemberships` promise, such as timeout or time tracker
|
|
14
|
+
// Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
|
|
16
15
|
decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
|
|
17
|
-
): Promise<
|
|
16
|
+
): Promise<string[]> {
|
|
18
17
|
|
|
19
|
-
let mySegmentsPromise =
|
|
18
|
+
let mySegmentsPromise = fetchMySegments(userMatchingKey, noCache);
|
|
20
19
|
if (decorator) mySegmentsPromise = decorator(mySegmentsPromise);
|
|
21
20
|
|
|
22
|
-
|
|
21
|
+
// Extract segment names
|
|
22
|
+
return mySegmentsPromise
|
|
23
|
+
.then(resp => resp.json())
|
|
24
|
+
.then(json => json.mySegments.map((segment: IMySegmentsResponseItem) => segment.name));
|
|
23
25
|
};
|
|
24
26
|
|
|
25
27
|
}
|
|
@@ -28,7 +28,7 @@ export function segmentChangesFetcherFactory(fetchSegmentChanges: IFetchSegmentC
|
|
|
28
28
|
segmentName: string,
|
|
29
29
|
noCache?: boolean,
|
|
30
30
|
till?: number,
|
|
31
|
-
// Optional decorator for `
|
|
31
|
+
// Optional decorator for `fetchMySegments` promise, such as timeout or time tracker
|
|
32
32
|
decorator?: (promise: Promise<ISegmentChangesResponse[]>) => Promise<ISegmentChangesResponse[]>
|
|
33
33
|
): Promise<ISegmentChangesResponse[]> {
|
|
34
34
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ISplitChangesResponse, ISegmentChangesResponse
|
|
1
|
+
import { ISplitChangesResponse, ISegmentChangesResponse } from '../../../dtos/types';
|
|
2
2
|
import { IResponse } from '../../../services/types';
|
|
3
3
|
|
|
4
4
|
export type ISplitChangesFetcher = (
|
|
@@ -19,6 +19,5 @@ export type ISegmentChangesFetcher = (
|
|
|
19
19
|
export type IMySegmentsFetcher = (
|
|
20
20
|
userMatchingKey: string,
|
|
21
21
|
noCache?: boolean,
|
|
22
|
-
till?: number,
|
|
23
22
|
decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
|
|
24
|
-
) => Promise<
|
|
23
|
+
) => Promise<string[]>
|
|
@@ -29,13 +29,13 @@ export function pollingManagerCSFactory(
|
|
|
29
29
|
const mySegmentsSyncTask = add(matchingKey, readiness, storage);
|
|
30
30
|
|
|
31
31
|
function startMySegmentsSyncTasks() {
|
|
32
|
-
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask)
|
|
32
|
+
forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
|
|
33
33
|
mySegmentsSyncTask.start();
|
|
34
34
|
});
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function stopMySegmentsSyncTasks() {
|
|
38
|
-
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask)
|
|
38
|
+
forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
|
|
39
39
|
if (mySegmentsSyncTask.isRunning()) mySegmentsSyncTask.stop();
|
|
40
40
|
});
|
|
41
41
|
}
|
|
@@ -55,7 +55,7 @@ export function pollingManagerCSFactory(
|
|
|
55
55
|
});
|
|
56
56
|
|
|
57
57
|
function add(matchingKey: string, readiness: IReadinessManager, storage: IStorageSync) {
|
|
58
|
-
const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.
|
|
58
|
+
const mySegmentsSyncTask = mySegmentsSyncTaskFactory(splitApi.fetchMySegments, storage, readiness, settings, matchingKey);
|
|
59
59
|
|
|
60
60
|
// smart ready
|
|
61
61
|
function smartReady() {
|
|
@@ -94,7 +94,7 @@ export function pollingManagerCSFactory(
|
|
|
94
94
|
// fetch splits and segments
|
|
95
95
|
syncAll() {
|
|
96
96
|
const promises = [splitsSyncTask.execute()];
|
|
97
|
-
forOwn(mySegmentsSyncTasks, (mySegmentsSyncTask)
|
|
97
|
+
forOwn(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
|
|
98
98
|
promises.push(mySegmentsSyncTask.execute());
|
|
99
99
|
});
|
|
100
100
|
return Promise.all(promises);
|
|
@@ -2,7 +2,7 @@ import { IStorageSync } from '../../../storages/types';
|
|
|
2
2
|
import { IReadinessManager } from '../../../readiness/types';
|
|
3
3
|
import { syncTaskFactory } from '../../syncTask';
|
|
4
4
|
import { IMySegmentsSyncTask } from '../types';
|
|
5
|
-
import {
|
|
5
|
+
import { IFetchMySegments } from '../../../services/types';
|
|
6
6
|
import { mySegmentsFetcherFactory } from '../fetchers/mySegmentsFetcher';
|
|
7
7
|
import { ISettings } from '../../../types';
|
|
8
8
|
import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
|
|
@@ -11,7 +11,7 @@ import { mySegmentsUpdaterFactory } from '../updaters/mySegmentsUpdater';
|
|
|
11
11
|
* Creates a sync task that periodically executes a `mySegmentsUpdater` task
|
|
12
12
|
*/
|
|
13
13
|
export function mySegmentsSyncTaskFactory(
|
|
14
|
-
|
|
14
|
+
fetchMySegments: IFetchMySegments,
|
|
15
15
|
storage: IStorageSync,
|
|
16
16
|
readiness: IReadinessManager,
|
|
17
17
|
settings: ISettings,
|
|
@@ -21,8 +21,9 @@ export function mySegmentsSyncTaskFactory(
|
|
|
21
21
|
settings.log,
|
|
22
22
|
mySegmentsUpdaterFactory(
|
|
23
23
|
settings.log,
|
|
24
|
-
mySegmentsFetcherFactory(
|
|
25
|
-
storage,
|
|
24
|
+
mySegmentsFetcherFactory(fetchMySegments),
|
|
25
|
+
storage.splits,
|
|
26
|
+
storage.segments,
|
|
26
27
|
readiness.segments,
|
|
27
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
28
29
|
settings.startup.retriesOnFailureBeforeReady,
|
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import { ISplit } from '../../dtos/types';
|
|
2
2
|
import { IReadinessManager } from '../../readiness/types';
|
|
3
3
|
import { IStorageSync } from '../../storages/types';
|
|
4
|
-
import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../streaming/types';
|
|
5
4
|
import { ITask, ISyncTask } from '../types';
|
|
6
5
|
|
|
7
6
|
export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
|
|
8
7
|
|
|
9
8
|
export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
|
|
10
9
|
|
|
11
|
-
export type MySegmentsData = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export type MySegmentsData = string[] | {
|
|
11
|
+
/* segment name */
|
|
12
|
+
name: string,
|
|
13
|
+
/* action: `true` for add, and `false` for delete */
|
|
14
|
+
add: boolean
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean
|
|
17
|
+
export interface IMySegmentsSyncTask extends ISyncTask<[segmentsData?: MySegmentsData, noCache?: boolean], boolean> { }
|
|
19
18
|
|
|
20
19
|
export interface IPollingManager extends ITask {
|
|
21
20
|
syncAll(): Promise<any>
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { IMySegmentsFetcher } from '../fetchers/types';
|
|
2
|
-
import {
|
|
2
|
+
import { ISegmentsCacheSync, ISplitsCacheSync } from '../../../storages/types';
|
|
3
3
|
import { ISegmentsEventEmitter } from '../../../readiness/types';
|
|
4
4
|
import { timeout } from '../../../utils/promise/timeout';
|
|
5
5
|
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
6
6
|
import { ILogger } from '../../../logger/types';
|
|
7
7
|
import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
|
|
8
8
|
import { MySegmentsData } from '../types';
|
|
9
|
-
import { IMembershipsResponse } from '../../../dtos/types';
|
|
10
|
-
import { MEMBERSHIPS_LS_UPDATE } from '../../streaming/constants';
|
|
11
9
|
|
|
12
|
-
type IMySegmentsUpdater = (
|
|
10
|
+
type IMySegmentsUpdater = (segmentList?: string[], noCache?: boolean) => Promise<boolean>
|
|
13
11
|
|
|
14
12
|
/**
|
|
15
13
|
* factory of MySegments updater, a task that:
|
|
@@ -20,14 +18,14 @@ type IMySegmentsUpdater = (segmentsData?: MySegmentsData, noCache?: boolean, til
|
|
|
20
18
|
export function mySegmentsUpdaterFactory(
|
|
21
19
|
log: ILogger,
|
|
22
20
|
mySegmentsFetcher: IMySegmentsFetcher,
|
|
23
|
-
|
|
21
|
+
splitsCache: ISplitsCacheSync,
|
|
22
|
+
mySegmentsCache: ISegmentsCacheSync,
|
|
24
23
|
segmentsEventEmitter: ISegmentsEventEmitter,
|
|
25
24
|
requestTimeoutBeforeReady: number,
|
|
26
25
|
retriesOnFailureBeforeReady: number,
|
|
27
26
|
matchingKey: string
|
|
28
27
|
): IMySegmentsUpdater {
|
|
29
28
|
|
|
30
|
-
const { splits, segments, largeSegments } = storage;
|
|
31
29
|
let readyOnAlreadyExistentState = true;
|
|
32
30
|
let startingUp = true;
|
|
33
31
|
|
|
@@ -38,31 +36,37 @@ export function mySegmentsUpdaterFactory(
|
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
// @TODO if allowing pluggable storages, handle async execution
|
|
41
|
-
function updateSegments(segmentsData:
|
|
39
|
+
function updateSegments(segmentsData: MySegmentsData) {
|
|
42
40
|
|
|
43
41
|
let shouldNotifyUpdate;
|
|
44
|
-
if ((segmentsData
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
segments.resetSegments(segmentsData as MySegmentsData);
|
|
42
|
+
if (Array.isArray(segmentsData)) {
|
|
43
|
+
// Update the list of segment names available
|
|
44
|
+
shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData);
|
|
48
45
|
} else {
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
// Add/Delete the segment
|
|
47
|
+
const { name, add } = segmentsData;
|
|
48
|
+
if (mySegmentsCache.isInSegment(name) !== add) {
|
|
49
|
+
shouldNotifyUpdate = true;
|
|
50
|
+
if (add) mySegmentsCache.addToSegment(name);
|
|
51
|
+
else mySegmentsCache.removeFromSegment(name);
|
|
52
|
+
} else {
|
|
53
|
+
shouldNotifyUpdate = false;
|
|
54
|
+
}
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
// Notify update if required
|
|
54
|
-
if (
|
|
58
|
+
if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
55
59
|
readyOnAlreadyExistentState = false;
|
|
56
60
|
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
60
|
-
function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean
|
|
64
|
+
function _mySegmentsUpdater(retry: number, segmentsData?: MySegmentsData, noCache?: boolean): Promise<boolean> {
|
|
61
65
|
const updaterPromise: Promise<boolean> = segmentsData ?
|
|
62
66
|
// If segmentsData is provided, there is no need to fetch mySegments
|
|
63
67
|
new Promise((res) => { updateSegments(segmentsData); res(true); }) :
|
|
64
68
|
// If not provided, fetch mySegments
|
|
65
|
-
mySegmentsFetcher(matchingKey, noCache,
|
|
69
|
+
mySegmentsFetcher(matchingKey, noCache, _promiseDecorator).then(segments => {
|
|
66
70
|
// Only when we have downloaded segments completely, we should not keep retrying anymore
|
|
67
71
|
startingUp = false;
|
|
68
72
|
|
|
@@ -92,10 +96,9 @@ export function mySegmentsUpdaterFactory(
|
|
|
92
96
|
* (2) an object with a segment name and action (true: add, or false: delete) to update the storage,
|
|
93
97
|
* (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
|
|
94
98
|
* @param {boolean | undefined} noCache true to revalidate data to fetch
|
|
95
|
-
* @param {boolean | undefined} till query param to bypass CDN requests
|
|
96
99
|
*/
|
|
97
|
-
return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean
|
|
98
|
-
return _mySegmentsUpdater(0, segmentsData, noCache
|
|
100
|
+
return function mySegmentsUpdater(segmentsData?: MySegmentsData, noCache?: boolean) {
|
|
101
|
+
return _mySegmentsUpdater(0, segmentsData, noCache);
|
|
99
102
|
};
|
|
100
103
|
|
|
101
104
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ISegmentChangesFetcher } from '../fetchers/types';
|
|
2
2
|
import { ISegmentsCacheBase } from '../../../storages/types';
|
|
3
3
|
import { IReadinessManager } from '../../../readiness/types';
|
|
4
|
+
import { MaybeThenable } from '../../../dtos/types';
|
|
5
|
+
import { findIndex } from '../../../utils/lang';
|
|
4
6
|
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
5
7
|
import { ILogger } from '../../../logger/types';
|
|
6
8
|
import { LOG_PREFIX_INSTANTIATION, LOG_PREFIX_SYNC_SEGMENTS } from '../../../logger/constants';
|
|
9
|
+
import { thenable } from '../../../utils/promise/thenable';
|
|
7
10
|
|
|
8
11
|
type ISegmentChangesUpdater = (fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number) => Promise<boolean>
|
|
9
12
|
|
|
@@ -27,22 +30,31 @@ export function segmentChangesUpdaterFactory(
|
|
|
27
30
|
|
|
28
31
|
let readyOnAlreadyExistentState = true;
|
|
29
32
|
|
|
30
|
-
function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean)
|
|
33
|
+
function updateSegment(segmentName: string, noCache?: boolean, till?: number, fetchOnlyNew?: boolean) {
|
|
31
34
|
log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing segment ${segmentName}`);
|
|
32
35
|
let sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
|
|
33
36
|
|
|
34
37
|
return sincePromise.then(since => {
|
|
35
38
|
// if fetchOnlyNew flag, avoid processing already fetched segments
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
if (fetchOnlyNew && since !== undefined) return -1;
|
|
40
|
+
|
|
41
|
+
return segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
|
|
42
|
+
let changeNumber = -1;
|
|
43
|
+
const results: MaybeThenable<boolean | void>[] = [];
|
|
44
|
+
changes.forEach(x => {
|
|
45
|
+
if (x.added.length > 0) results.push(segments.addToSegment(segmentName, x.added));
|
|
46
|
+
if (x.removed.length > 0) results.push(segments.removeFromSegment(segmentName, x.removed));
|
|
47
|
+
if (x.added.length > 0 || x.removed.length > 0) {
|
|
48
|
+
results.push(segments.setChangeNumber(segmentName, x.till));
|
|
49
|
+
changeNumber = x.till;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processed ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
|
|
45
53
|
});
|
|
54
|
+
// If at least one storage operation result is a promise, join all in a single promise.
|
|
55
|
+
if (results.some(result => thenable(result))) return Promise.all(results).then(() => changeNumber);
|
|
56
|
+
return changeNumber;
|
|
57
|
+
});
|
|
46
58
|
});
|
|
47
59
|
}
|
|
48
60
|
/**
|
|
@@ -63,12 +75,16 @@ export function segmentChangesUpdaterFactory(
|
|
|
63
75
|
let segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
|
|
64
76
|
|
|
65
77
|
return segmentsPromise.then(segmentNames => {
|
|
66
|
-
// Async fetchers
|
|
67
|
-
const updaters =
|
|
78
|
+
// Async fetchers are collected here.
|
|
79
|
+
const updaters: Promise<number>[] = [];
|
|
80
|
+
|
|
81
|
+
for (let index = 0; index < segmentNames.length; index++) {
|
|
82
|
+
updaters.push(updateSegment(segmentNames[index], noCache, till, fetchOnlyNew));
|
|
83
|
+
}
|
|
68
84
|
|
|
69
85
|
return Promise.all(updaters).then(shouldUpdateFlags => {
|
|
70
86
|
// if at least one segment fetch succeeded, mark segments ready
|
|
71
|
-
if (shouldUpdateFlags
|
|
87
|
+
if (findIndex(shouldUpdateFlags, v => v !== -1) !== -1 || readyOnAlreadyExistentState) {
|
|
72
88
|
readyOnAlreadyExistentState = false;
|
|
73
89
|
if (readiness) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
74
90
|
}
|
|
@@ -19,7 +19,7 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
|
19
19
|
let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
|
|
20
20
|
return registeredSegments.then(segmentNames => {
|
|
21
21
|
return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
|
|
22
|
-
.then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !==
|
|
22
|
+
.then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -14,7 +14,7 @@ export function authenticateFactory(fetchAuth: IFetchAuth): IAuthenticate {
|
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Run authentication requests to Auth Server, and returns a promise that resolves with the decoded JTW token.
|
|
17
|
-
* @param {string[] | undefined} userKeys set of user Keys to track
|
|
17
|
+
* @param {string[] | undefined} userKeys set of user Keys to track MY_SEGMENTS_CHANGES. It is undefined for server-side API.
|
|
18
18
|
*/
|
|
19
19
|
return function authenticate(userKeys?: string[]): Promise<IAuthToken> {
|
|
20
20
|
return fetchAuth(userKeys)
|
|
@@ -71,10 +71,12 @@ export class SSEClient implements ISSEClient {
|
|
|
71
71
|
open(authToken: IAuthTokenPushEnabled) {
|
|
72
72
|
this.close(); // it closes connection if previously opened
|
|
73
73
|
|
|
74
|
-
const channelsQueryParam = Object.keys(authToken.channels).map(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
const channelsQueryParam = Object.keys(authToken.channels).map(
|
|
75
|
+
function (channel) {
|
|
76
|
+
const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
|
|
77
|
+
return encodeURIComponent(params + channel);
|
|
78
|
+
}
|
|
79
|
+
).join(',');
|
|
78
80
|
const url = `${this.settings.urls.streaming}/sse?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
|
|
79
81
|
const isServerSide = !this.settings.core.key;
|
|
80
82
|
|