@splitsoftware/splitio-commons 2.1.0-rc.2 → 2.1.1-rc.0
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 +2 -7
- package/README.md +1 -0
- package/cjs/evaluator/combiners/and.js +2 -6
- package/cjs/evaluator/combiners/ifelseif.js +6 -6
- package/cjs/evaluator/condition/index.js +6 -5
- package/cjs/evaluator/index.js +7 -7
- package/cjs/evaluator/matchers/index.js +3 -1
- package/cjs/evaluator/matchers/matcherTypes.js +1 -0
- package/cjs/evaluator/matchers/rbsegment.js +43 -0
- package/cjs/evaluator/matchersTransform/index.js +4 -0
- package/cjs/evaluator/parser/index.js +2 -2
- package/cjs/evaluator/value/sanitize.js +1 -0
- package/cjs/logger/constants.js +5 -6
- package/cjs/logger/messages/debug.js +3 -4
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +0 -6
- package/cjs/services/splitApi.js +2 -2
- package/cjs/storages/AbstractSplitsCacheAsync.js +19 -1
- package/cjs/storages/AbstractSplitsCacheSync.js +17 -9
- package/cjs/storages/KeyBuilder.js +8 -15
- package/cjs/storages/KeyBuilderCS.js +11 -5
- package/cjs/storages/KeyBuilderSS.js +3 -0
- package/cjs/storages/dataLoader.js +3 -5
- package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +117 -0
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
- package/cjs/storages/inLocalStorage/index.js +7 -5
- package/cjs/storages/inMemory/InMemoryStorage.js +3 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +61 -0
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +64 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/cjs/storages/inRedis/constants.js +1 -1
- package/cjs/storages/inRedis/index.js +2 -0
- package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +64 -0
- package/cjs/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/cjs/storages/pluggable/index.js +3 -2
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
- package/cjs/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/cjs/sync/polling/pollingManagerCS.js +7 -7
- package/cjs/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/cjs/sync/polling/updaters/splitChangesUpdater.js +62 -51
- package/cjs/sync/streaming/SSEHandler/index.js +1 -0
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +106 -77
- package/cjs/sync/streaming/constants.js +2 -1
- package/cjs/sync/streaming/pushManager.js +3 -16
- package/cjs/sync/syncManagerOnline.js +5 -10
- package/cjs/trackers/uniqueKeysTracker.js +1 -1
- package/cjs/utils/constants/browser.js +5 -0
- package/cjs/utils/constants/index.js +3 -2
- package/cjs/utils/settingsValidation/storage/storageCS.js +1 -1
- package/esm/evaluator/combiners/and.js +2 -6
- package/esm/evaluator/combiners/ifelseif.js +7 -7
- package/esm/evaluator/condition/index.js +6 -5
- package/esm/evaluator/index.js +7 -7
- package/esm/evaluator/matchers/index.js +3 -1
- package/esm/evaluator/matchers/matcherTypes.js +1 -0
- package/esm/evaluator/matchers/rbsegment.js +39 -0
- package/esm/evaluator/matchersTransform/index.js +4 -0
- package/esm/evaluator/parser/index.js +2 -2
- package/esm/evaluator/value/sanitize.js +1 -0
- package/esm/logger/constants.js +2 -3
- package/esm/logger/messages/debug.js +3 -4
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +0 -6
- package/esm/services/splitApi.js +2 -2
- package/esm/storages/AbstractSplitsCacheAsync.js +19 -1
- package/esm/storages/AbstractSplitsCacheSync.js +17 -9
- package/esm/storages/KeyBuilder.js +8 -15
- package/esm/storages/KeyBuilderCS.js +11 -5
- package/esm/storages/KeyBuilderSS.js +3 -0
- package/esm/storages/dataLoader.js +2 -4
- package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +114 -0
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +69 -15
- package/esm/storages/inLocalStorage/index.js +7 -5
- package/esm/storages/inMemory/InMemoryStorage.js +3 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +4 -0
- package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +58 -0
- package/esm/storages/inMemory/SplitsCacheInMemory.js +24 -31
- package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +61 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +4 -21
- package/esm/storages/inRedis/constants.js +1 -1
- package/esm/storages/inRedis/index.js +2 -0
- package/esm/storages/pluggable/RBSegmentsCachePluggable.js +61 -0
- package/esm/storages/pluggable/SplitsCachePluggable.js +2 -19
- package/esm/storages/pluggable/index.js +3 -2
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +14 -16
- package/esm/sync/polling/fetchers/splitChangesFetcher.js +2 -2
- package/esm/sync/polling/pollingManagerCS.js +7 -7
- package/esm/sync/polling/syncTasks/splitsSyncTask.js +1 -1
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +2 -2
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
- package/esm/sync/polling/updaters/splitChangesUpdater.js +63 -52
- package/esm/sync/streaming/SSEHandler/index.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +102 -73
- package/esm/sync/streaming/constants.js +1 -0
- package/esm/sync/streaming/pushManager.js +6 -19
- package/esm/sync/syncManagerOnline.js +5 -10
- package/esm/trackers/uniqueKeysTracker.js +1 -1
- package/esm/utils/constants/browser.js +2 -0
- package/esm/utils/constants/index.js +2 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +1 -1
- package/package.json +1 -1
- package/src/dtos/types.ts +32 -8
- package/src/evaluator/Engine.ts +1 -1
- package/src/evaluator/combiners/and.ts +5 -4
- package/src/evaluator/combiners/ifelseif.ts +7 -9
- package/src/evaluator/condition/engineUtils.ts +1 -1
- package/src/evaluator/condition/index.ts +12 -12
- package/src/evaluator/index.ts +7 -7
- package/src/evaluator/matchers/index.ts +3 -1
- package/src/evaluator/matchers/matcherTypes.ts +1 -0
- package/src/evaluator/matchers/rbsegment.ts +61 -0
- package/src/evaluator/matchersTransform/index.ts +3 -0
- package/src/evaluator/parser/index.ts +3 -3
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +5 -4
- package/src/logger/constants.ts +2 -3
- package/src/logger/messages/debug.ts +3 -4
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +0 -5
- package/src/sdkManager/index.ts +1 -1
- package/src/services/splitApi.ts +2 -2
- package/src/services/types.ts +1 -1
- package/src/storages/AbstractSplitsCacheAsync.ts +23 -5
- package/src/storages/AbstractSplitsCacheSync.ts +22 -15
- package/src/storages/KeyBuilder.ts +9 -17
- package/src/storages/KeyBuilderCS.ts +13 -6
- package/src/storages/KeyBuilderSS.ts +4 -0
- package/src/storages/dataLoader.ts +2 -5
- package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +136 -0
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +80 -16
- package/src/storages/inLocalStorage/index.ts +12 -8
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +4 -0
- package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +68 -0
- package/src/storages/inMemory/SplitsCacheInMemory.ts +22 -27
- package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +79 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +4 -21
- package/src/storages/inRedis/constants.ts +1 -1
- package/src/storages/inRedis/index.ts +2 -0
- package/src/storages/pluggable/RBSegmentsCachePluggable.ts +76 -0
- package/src/storages/pluggable/SplitsCachePluggable.ts +2 -19
- package/src/storages/pluggable/index.ts +3 -2
- package/src/storages/types.ts +47 -18
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +19 -21
- package/src/sync/polling/fetchers/splitChangesFetcher.ts +2 -1
- package/src/sync/polling/fetchers/types.ts +1 -0
- package/src/sync/polling/pollingManagerCS.ts +7 -7
- package/src/sync/polling/syncTasks/splitsSyncTask.ts +1 -2
- package/src/sync/polling/types.ts +2 -2
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +2 -2
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
- package/src/sync/polling/updaters/splitChangesUpdater.ts +74 -63
- package/src/sync/streaming/SSEHandler/index.ts +2 -1
- package/src/sync/streaming/SSEHandler/types.ts +2 -2
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +98 -68
- package/src/sync/streaming/constants.ts +1 -0
- package/src/sync/streaming/parseUtils.ts +2 -2
- package/src/sync/streaming/pushManager.ts +6 -18
- package/src/sync/streaming/types.ts +3 -2
- package/src/sync/syncManagerOnline.ts +5 -11
- package/src/trackers/uniqueKeysTracker.ts +1 -1
- package/src/utils/constants/browser.ts +2 -0
- package/src/utils/constants/index.ts +2 -1
- package/src/utils/lang/index.ts +2 -2
- package/src/utils/settingsValidation/storage/storageCS.ts +1 -1
- package/types/splitio.d.ts +1 -25
- package/cjs/storages/inLocalStorage/validateCache.js +0 -79
- package/esm/storages/inLocalStorage/validateCache.js +0 -75
- package/src/storages/inLocalStorage/validateCache.ts +0 -91
|
@@ -11,11 +11,12 @@ export function splitChangesFetcherFactory(fetchSplitChanges: IFetchSplitChanges
|
|
|
11
11
|
since: number,
|
|
12
12
|
noCache?: boolean,
|
|
13
13
|
till?: number,
|
|
14
|
+
rbSince?: number,
|
|
14
15
|
// Optional decorator for `fetchSplitChanges` promise, such as timeout or time tracker
|
|
15
16
|
decorator?: (promise: Promise<IResponse>) => Promise<IResponse>
|
|
16
17
|
) {
|
|
17
18
|
|
|
18
|
-
let splitsPromise = fetchSplitChanges(since, noCache, till);
|
|
19
|
+
let splitsPromise = fetchSplitChanges(since, noCache, till, rbSince);
|
|
19
20
|
if (decorator) splitsPromise = decorator(splitsPromise);
|
|
20
21
|
|
|
21
22
|
return splitsPromise.then(resp => resp.json());
|
|
@@ -43,10 +43,10 @@ export function pollingManagerCSFactory(
|
|
|
43
43
|
// smart pausing
|
|
44
44
|
readiness.splits.on(SDK_SPLITS_ARRIVED, () => {
|
|
45
45
|
if (!splitsSyncTask.isRunning()) return; // noop if not doing polling
|
|
46
|
-
const
|
|
47
|
-
if (
|
|
48
|
-
log.info(POLLING_SMART_PAUSING, [
|
|
49
|
-
if (
|
|
46
|
+
const usingSegments = storage.splits.usesSegments() || storage.rbSegments.usesSegments();
|
|
47
|
+
if (usingSegments !== mySegmentsSyncTask.isRunning()) {
|
|
48
|
+
log.info(POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
|
|
49
|
+
if (usingSegments) {
|
|
50
50
|
startMySegmentsSyncTasks();
|
|
51
51
|
} else {
|
|
52
52
|
stopMySegmentsSyncTasks();
|
|
@@ -59,9 +59,9 @@ export function pollingManagerCSFactory(
|
|
|
59
59
|
|
|
60
60
|
// smart ready
|
|
61
61
|
function smartReady() {
|
|
62
|
-
if (!readiness.isReady() && !storage.splits.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
62
|
+
if (!readiness.isReady() && !storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
63
63
|
}
|
|
64
|
-
if (!storage.splits.usesSegments()) setTimeout(smartReady, 0);
|
|
64
|
+
if (!storage.splits.usesSegments() && !storage.rbSegments.usesSegments()) setTimeout(smartReady, 0);
|
|
65
65
|
else readiness.splits.once(SDK_SPLITS_ARRIVED, smartReady);
|
|
66
66
|
|
|
67
67
|
mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
|
|
@@ -77,7 +77,7 @@ export function pollingManagerCSFactory(
|
|
|
77
77
|
log.info(POLLING_START);
|
|
78
78
|
|
|
79
79
|
splitsSyncTask.start();
|
|
80
|
-
if (storage.splits.usesSegments()) startMySegmentsSyncTasks();
|
|
80
|
+
if (storage.splits.usesSegments() || storage.rbSegments.usesSegments()) startMySegmentsSyncTasks();
|
|
81
81
|
},
|
|
82
82
|
|
|
83
83
|
// Stop periodic fetching (polling)
|
|
@@ -22,8 +22,7 @@ export function splitsSyncTaskFactory(
|
|
|
22
22
|
splitChangesUpdaterFactory(
|
|
23
23
|
settings.log,
|
|
24
24
|
splitChangesFetcherFactory(fetchSplitChanges),
|
|
25
|
-
storage
|
|
26
|
-
storage.segments,
|
|
25
|
+
storage,
|
|
27
26
|
settings.sync.__splitFiltersValidation,
|
|
28
27
|
readiness.splits,
|
|
29
28
|
settings.startup.requestTimeoutBeforeReady,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { ISplit } from '../../dtos/types';
|
|
1
|
+
import { IRBSegment, ISplit } from '../../dtos/types';
|
|
2
2
|
import { IReadinessManager } from '../../readiness/types';
|
|
3
3
|
import { IStorageSync } from '../../storages/types';
|
|
4
4
|
import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../streaming/types';
|
|
5
5
|
import { ITask, ISyncTask } from '../types';
|
|
6
6
|
|
|
7
|
-
export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit, changeNumber: number }], boolean> { }
|
|
7
|
+
export interface ISplitsSyncTask extends ISyncTask<[noCache?: boolean, till?: number, splitUpdateNotification?: { payload: ISplit | IRBSegment, changeNumber: number }], boolean> { }
|
|
8
8
|
|
|
9
9
|
export interface ISegmentsSyncTask extends ISyncTask<[fetchOnlyNew?: boolean, segmentName?: string, noCache?: boolean, till?: number], boolean> { }
|
|
10
10
|
|
|
@@ -27,7 +27,7 @@ export function mySegmentsUpdaterFactory(
|
|
|
27
27
|
matchingKey: string
|
|
28
28
|
): IMySegmentsUpdater {
|
|
29
29
|
|
|
30
|
-
const { splits, segments, largeSegments } = storage;
|
|
30
|
+
const { splits, rbSegments, segments, largeSegments } = storage;
|
|
31
31
|
let readyOnAlreadyExistentState = true;
|
|
32
32
|
let startingUp = true;
|
|
33
33
|
|
|
@@ -51,7 +51,7 @@ export function mySegmentsUpdaterFactory(
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// Notify update if required
|
|
54
|
-
if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
54
|
+
if ((splits.usesSegments() || rbSegments.usesSegments()) && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
55
55
|
readyOnAlreadyExistentState = false;
|
|
56
56
|
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
|
|
57
57
|
}
|
|
@@ -51,7 +51,7 @@ export function segmentChangesUpdaterFactory(
|
|
|
51
51
|
* Returned promise will not be rejected.
|
|
52
52
|
*
|
|
53
53
|
* @param fetchOnlyNew - if true, only fetch the segments that not exists, i.e., which `changeNumber` is equal to -1.
|
|
54
|
-
* This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE notifications.
|
|
54
|
+
* This param is used by SplitUpdateWorker on server-side SDK, to fetch new registered segments on SPLIT_UPDATE or RB_SEGMENT_UPDATE notifications.
|
|
55
55
|
* @param segmentName - segment name to fetch. By passing `undefined` it fetches the list of segments registered at the storage
|
|
56
56
|
* @param noCache - true to revalidate data to fetch on a SEGMENT_UPDATE notifications.
|
|
57
57
|
* @param till - till target for the provided segmentName, for CDN bypass.
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import { ISegmentsCacheBase,
|
|
1
|
+
import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
|
|
2
2
|
import { ISplitChangesFetcher } from '../fetchers/types';
|
|
3
|
-
import { ISplit, ISplitChangesResponse, ISplitFiltersValidation } from '../../../dtos/types';
|
|
3
|
+
import { IRBSegment, ISplit, ISplitChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
|
|
4
4
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
5
5
|
import { timeout } from '../../../utils/promise/timeout';
|
|
6
|
-
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
6
|
+
import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
|
-
import { SYNC_SPLITS_FETCH,
|
|
8
|
+
import { SYNC_SPLITS_FETCH, SYNC_SPLITS_UPDATE, SYNC_RBS_UPDATE, SYNC_SPLITS_FETCH_FAILS, SYNC_SPLITS_FETCH_RETRY } from '../../../logger/constants';
|
|
9
9
|
import { startsWith } from '../../../utils/lang';
|
|
10
|
-
import { IN_SEGMENT } from '../../../utils/constants';
|
|
10
|
+
import { IN_RULE_BASED_SEGMENT, IN_SEGMENT } from '../../../utils/constants';
|
|
11
11
|
import { setToArray } from '../../../utils/lang/sets';
|
|
12
|
+
import { SPLIT_UPDATE } from '../../streaming/constants';
|
|
12
13
|
|
|
13
|
-
type
|
|
14
|
+
export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
|
|
15
|
+
type SplitChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
|
|
14
16
|
|
|
15
17
|
// Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
|
|
16
18
|
// Returns a promise that could be rejected.
|
|
@@ -27,24 +29,24 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
|
|
|
27
29
|
* Collect segments from a raw split definition.
|
|
28
30
|
* Exported for testing purposes.
|
|
29
31
|
*/
|
|
30
|
-
export function parseSegments(
|
|
31
|
-
|
|
32
|
+
export function parseSegments(ruleEntity: ISplit | IRBSegment, matcherType: typeof IN_SEGMENT | typeof IN_RULE_BASED_SEGMENT = IN_SEGMENT): Set<string> {
|
|
33
|
+
const { conditions, excluded } = ruleEntity as IRBSegment;
|
|
34
|
+
const segments = new Set<string>(excluded && excluded.segments);
|
|
32
35
|
|
|
33
36
|
for (let i = 0; i < conditions.length; i++) {
|
|
34
37
|
const matchers = conditions[i].matcherGroup.matchers;
|
|
35
38
|
|
|
36
39
|
matchers.forEach(matcher => {
|
|
37
|
-
if (matcher.matcherType ===
|
|
40
|
+
if (matcher.matcherType === matcherType) segments.add(matcher.userDefinedSegmentMatcherData.segmentName);
|
|
38
41
|
});
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
return segments;
|
|
42
45
|
}
|
|
43
46
|
|
|
44
|
-
interface ISplitMutations {
|
|
45
|
-
added: [
|
|
46
|
-
removed:
|
|
47
|
-
segments: string[]
|
|
47
|
+
interface ISplitMutations<T extends ISplit | IRBSegment> {
|
|
48
|
+
added: T[],
|
|
49
|
+
removed: T[]
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
/**
|
|
@@ -73,25 +75,21 @@ function matchFilters(featureFlag: ISplit, filters: ISplitFiltersValidation) {
|
|
|
73
75
|
* i.e., an object with added splits, removed splits and used segments.
|
|
74
76
|
* Exported for testing purposes.
|
|
75
77
|
*/
|
|
76
|
-
export function
|
|
77
|
-
const segments = new Set<string>();
|
|
78
|
-
const computed = entries.reduce((accum, split) => {
|
|
79
|
-
if (split.status === 'ACTIVE' && matchFilters(split, filters)) {
|
|
80
|
-
accum.added.push([split.name, split]);
|
|
78
|
+
export function computeMutation<T extends ISplit | IRBSegment>(rules: Array<T>, segments: Set<string>, filters?: ISplitFiltersValidation): ISplitMutations<T> {
|
|
81
79
|
|
|
82
|
-
|
|
80
|
+
return rules.reduce((accum, ruleEntity) => {
|
|
81
|
+
if (ruleEntity.status === 'ACTIVE' && (!filters || matchFilters(ruleEntity as ISplit, filters))) {
|
|
82
|
+
accum.added.push(ruleEntity);
|
|
83
|
+
|
|
84
|
+
parseSegments(ruleEntity).forEach((segmentName: string) => {
|
|
83
85
|
segments.add(segmentName);
|
|
84
86
|
});
|
|
85
87
|
} else {
|
|
86
|
-
accum.removed.push(
|
|
88
|
+
accum.removed.push(ruleEntity);
|
|
87
89
|
}
|
|
88
90
|
|
|
89
91
|
return accum;
|
|
90
|
-
}, { added: [], removed: []
|
|
91
|
-
|
|
92
|
-
computed.segments = setToArray(segments);
|
|
93
|
-
|
|
94
|
-
return computed;
|
|
92
|
+
}, { added: [], removed: [] } as ISplitMutations<T>);
|
|
95
93
|
}
|
|
96
94
|
|
|
97
95
|
/**
|
|
@@ -111,14 +109,14 @@ export function computeSplitsMutation(entries: ISplit[], filters: ISplitFiltersV
|
|
|
111
109
|
export function splitChangesUpdaterFactory(
|
|
112
110
|
log: ILogger,
|
|
113
111
|
splitChangesFetcher: ISplitChangesFetcher,
|
|
114
|
-
|
|
115
|
-
segments: ISegmentsCacheBase,
|
|
112
|
+
storage: Pick<IStorageBase, 'splits' | 'rbSegments' | 'segments'>,
|
|
116
113
|
splitFiltersValidation: ISplitFiltersValidation,
|
|
117
114
|
splitsEventEmitter?: ISplitsEventEmitter,
|
|
118
115
|
requestTimeoutBeforeReady: number = 0,
|
|
119
116
|
retriesOnFailureBeforeReady: number = 0,
|
|
120
117
|
isClientSide?: boolean
|
|
121
|
-
):
|
|
118
|
+
): SplitChangesUpdater {
|
|
119
|
+
const { splits, rbSegments, segments } = storage;
|
|
122
120
|
|
|
123
121
|
let startingUp = true;
|
|
124
122
|
|
|
@@ -128,16 +126,6 @@ export function splitChangesUpdaterFactory(
|
|
|
128
126
|
return promise;
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
/** Returns true if at least one split was updated */
|
|
132
|
-
function isThereUpdate(flagsChange: [boolean | void, void | boolean[], void | boolean[], boolean | void] | [any, any, any]) {
|
|
133
|
-
const [, added, removed] = flagsChange;
|
|
134
|
-
// There is at least one added or modified feature flag
|
|
135
|
-
if (added && added.some((update: boolean) => update)) return true;
|
|
136
|
-
// There is at least one removed feature flag
|
|
137
|
-
if (removed && removed.some((update: boolean) => update)) return true;
|
|
138
|
-
return false;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
129
|
/**
|
|
142
130
|
* SplitChanges updater returns a promise that resolves with a `false` boolean value if it fails to fetch splits or synchronize them with the storage.
|
|
143
131
|
* Returned promise will not be rejected.
|
|
@@ -145,39 +133,53 @@ export function splitChangesUpdaterFactory(
|
|
|
145
133
|
* @param noCache - true to revalidate data to fetch
|
|
146
134
|
* @param till - query param to bypass CDN requests
|
|
147
135
|
*/
|
|
148
|
-
return function splitChangesUpdater(noCache?: boolean, till?: number,
|
|
136
|
+
return function splitChangesUpdater(noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) {
|
|
149
137
|
|
|
150
138
|
/**
|
|
151
139
|
* @param since - current changeNumber at splitsCache
|
|
152
140
|
* @param retry - current number of retry attempts
|
|
153
141
|
*/
|
|
154
|
-
function _splitChangesUpdater(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
142
|
+
function _splitChangesUpdater(sinces: [number, number], retry = 0): Promise<boolean> {
|
|
143
|
+
const [since, rbSince] = sinces;
|
|
144
|
+
log.debug(SYNC_SPLITS_FETCH, sinces);
|
|
145
|
+
const fetcherPromise = Promise.resolve(
|
|
146
|
+
instantUpdate ?
|
|
147
|
+
instantUpdate.type === SPLIT_UPDATE ?
|
|
148
|
+
// IFFU edge case: a change to a flag that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
|
|
149
|
+
Promise.resolve(rbSegments.contains(parseSegments(instantUpdate.payload, IN_RULE_BASED_SEGMENT))).then((contains) => {
|
|
150
|
+
return contains ?
|
|
151
|
+
{ ff: { d: [instantUpdate.payload as ISplit], t: instantUpdate.changeNumber } } :
|
|
152
|
+
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
|
|
153
|
+
}) :
|
|
154
|
+
{ rbs: { d: [instantUpdate.payload as IRBSegment], t: instantUpdate.changeNumber } } :
|
|
155
|
+
splitChangesFetcher(since, noCache, till, rbSince, _promiseDecorator)
|
|
159
156
|
)
|
|
160
157
|
.then((splitChanges: ISplitChangesResponse) => {
|
|
161
158
|
startingUp = false;
|
|
162
159
|
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
160
|
+
const usedSegments = new Set<string>();
|
|
161
|
+
|
|
162
|
+
let ffUpdate: MaybeThenable<boolean> = false;
|
|
163
|
+
if (splitChanges.ff) {
|
|
164
|
+
const { added, removed } = computeMutation(splitChanges.ff.d, usedSegments, splitFiltersValidation);
|
|
165
|
+
log.debug(SYNC_SPLITS_UPDATE, [added.length, removed.length]);
|
|
166
|
+
ffUpdate = splits.update(added, removed, splitChanges.ff.t);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let rbsUpdate: MaybeThenable<boolean> = false;
|
|
170
|
+
if (splitChanges.rbs) {
|
|
171
|
+
const { added, removed } = computeMutation(splitChanges.rbs.d, usedSegments);
|
|
172
|
+
log.debug(SYNC_RBS_UPDATE, [added.length, removed.length]);
|
|
173
|
+
rbsUpdate = rbSegments.update(added, removed, splitChanges.rbs.t);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return Promise.all([ffUpdate, rbsUpdate,
|
|
177
|
+
// @TODO if at least 1 segment fetch fails due to 404 and other segments are updated in the storage, SDK_UPDATE is not emitted
|
|
178
|
+
segments.registerSegments(setToArray(usedSegments))
|
|
179
|
+
]).then(([ffChanged, rbsChanged]) => {
|
|
178
180
|
if (splitsEventEmitter) {
|
|
179
181
|
// To emit SDK_SPLITS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
|
|
180
|
-
return Promise.resolve(!splitsEventEmitter.splitsArrived || (
|
|
182
|
+
return Promise.resolve(!splitsEventEmitter.splitsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
|
|
181
183
|
.catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
|
|
182
184
|
.then(emitSplitsArrivedEvent => {
|
|
183
185
|
// emit SDK events
|
|
@@ -194,15 +196,24 @@ export function splitChangesUpdaterFactory(
|
|
|
194
196
|
if (startingUp && retriesOnFailureBeforeReady > retry) {
|
|
195
197
|
retry += 1;
|
|
196
198
|
log.info(SYNC_SPLITS_FETCH_RETRY, [retry, error]);
|
|
197
|
-
return _splitChangesUpdater(
|
|
199
|
+
return _splitChangesUpdater(sinces, retry);
|
|
198
200
|
} else {
|
|
199
201
|
startingUp = false;
|
|
200
202
|
}
|
|
201
203
|
return false;
|
|
202
204
|
});
|
|
205
|
+
|
|
206
|
+
// After triggering the requests, if we have cached splits information let's notify that to emit SDK_READY_FROM_CACHE.
|
|
207
|
+
// Wrapping in a promise since checkCache can be async.
|
|
208
|
+
if (splitsEventEmitter && startingUp) {
|
|
209
|
+
Promise.resolve(splits.checkCache()).then(isCacheReady => {
|
|
210
|
+
if (isCacheReady) splitsEventEmitter.emit(SDK_SPLITS_CACHE_LOADED);
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
return fetcherPromise;
|
|
203
214
|
}
|
|
204
215
|
|
|
205
|
-
|
|
206
|
-
return
|
|
216
|
+
// `getChangeNumber` never rejects or throws error
|
|
217
|
+
return Promise.all([splits.getChangeNumber(), rbSegments.getChangeNumber()]).then(_splitChangesUpdater);
|
|
207
218
|
};
|
|
208
219
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { errorParser, messageParser } from './NotificationParser';
|
|
2
2
|
import { notificationKeeperFactory } from './NotificationKeeper';
|
|
3
|
-
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE } from '../constants';
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, RB_SEGMENT_UPDATE } from '../constants';
|
|
4
4
|
import { IPushEventEmitter } from '../types';
|
|
5
5
|
import { ISseEventHandler } from '../SSEClient/types';
|
|
6
6
|
import { INotificationError, INotificationMessage } from './types';
|
|
@@ -84,6 +84,7 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
|
|
|
84
84
|
case MEMBERSHIPS_MS_UPDATE:
|
|
85
85
|
case MEMBERSHIPS_LS_UPDATE:
|
|
86
86
|
case SPLIT_KILL:
|
|
87
|
+
case RB_SEGMENT_UPDATE:
|
|
87
88
|
pushEmitter.emit(parsedData.type, parsedData);
|
|
88
89
|
break;
|
|
89
90
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ControlType } from '../constants';
|
|
2
|
-
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../types';
|
|
2
|
+
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE, RB_SEGMENT_UPDATE } from '../types';
|
|
3
3
|
|
|
4
4
|
export enum Compression {
|
|
5
5
|
None = 0,
|
|
@@ -42,7 +42,7 @@ export interface ISegmentUpdateData {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export interface ISplitUpdateData {
|
|
45
|
-
type: SPLIT_UPDATE,
|
|
45
|
+
type: SPLIT_UPDATE | RB_SEGMENT_UPDATE,
|
|
46
46
|
changeNumber: number,
|
|
47
47
|
pcn?: number,
|
|
48
48
|
d?: string,
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { ISplit } from '../../../dtos/types';
|
|
1
|
+
import { IRBSegment, ISplit } from '../../../dtos/types';
|
|
2
|
+
import { STREAMING_PARSING_SPLIT_UPDATE } from '../../../logger/constants';
|
|
2
3
|
import { ILogger } from '../../../logger/types';
|
|
3
4
|
import { SDK_SPLITS_ARRIVED } from '../../../readiness/constants';
|
|
4
5
|
import { ISplitsEventEmitter } from '../../../readiness/types';
|
|
5
|
-
import { ISplitsCacheSync } from '../../../storages/types';
|
|
6
|
+
import { IRBSegmentsCacheSync, ISplitsCacheSync, IStorageSync } from '../../../storages/types';
|
|
6
7
|
import { ITelemetryTracker } from '../../../trackers/types';
|
|
7
8
|
import { Backoff } from '../../../utils/Backoff';
|
|
8
9
|
import { SPLITS } from '../../../utils/constants';
|
|
9
10
|
import { ISegmentsSyncTask, ISplitsSyncTask } from '../../polling/types';
|
|
11
|
+
import { InstantUpdate } from '../../polling/updaters/splitChangesUpdater';
|
|
12
|
+
import { RB_SEGMENT_UPDATE } from '../constants';
|
|
13
|
+
import { parseFFUpdatePayload } from '../parseUtils';
|
|
10
14
|
import { ISplitKillData, ISplitUpdateData } from '../SSEHandler/types';
|
|
11
15
|
import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants';
|
|
12
16
|
import { IUpdateWorker } from './types';
|
|
@@ -14,102 +18,128 @@ import { IUpdateWorker } from './types';
|
|
|
14
18
|
/**
|
|
15
19
|
* SplitsUpdateWorker factory
|
|
16
20
|
*/
|
|
17
|
-
export function SplitsUpdateWorker(log: ILogger,
|
|
21
|
+
export function SplitsUpdateWorker(log: ILogger, storage: IStorageSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData]> & { killSplit(event: ISplitKillData): void } {
|
|
18
22
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let isHandlingEvent: boolean;
|
|
22
|
-
let cdnBypass: boolean;
|
|
23
|
-
let payload: ISplit | undefined;
|
|
24
|
-
const backoff = new Backoff(__handleSplitUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
|
|
23
|
+
const ff = SplitsUpdateWorker(storage.splits);
|
|
24
|
+
const rbs = SplitsUpdateWorker(storage.rbSegments);
|
|
25
25
|
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
34
|
-
if (handleNewEvent) {
|
|
35
|
-
__handleSplitUpdateCall();
|
|
36
|
-
} else {
|
|
37
|
-
if (splitUpdateNotification) telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
38
|
-
// fetch new registered segments for server-side API. Not retrying on error
|
|
39
|
-
if (segmentsSyncTask) segmentsSyncTask.execute(true);
|
|
26
|
+
function SplitsUpdateWorker(cache: ISplitsCacheSync | IRBSegmentsCacheSync) {
|
|
27
|
+
let maxChangeNumber = -1;
|
|
28
|
+
let handleNewEvent = false;
|
|
29
|
+
let isHandlingEvent: boolean;
|
|
30
|
+
let cdnBypass: boolean;
|
|
31
|
+
let instantUpdate: InstantUpdate | undefined;
|
|
32
|
+
const backoff = new Backoff(__handleSplitUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
function __handleSplitUpdateCall() {
|
|
35
|
+
isHandlingEvent = true;
|
|
36
|
+
if (maxChangeNumber > cache.getChangeNumber()) {
|
|
37
|
+
handleNewEvent = false;
|
|
38
|
+
// fetch splits revalidating data if cached
|
|
39
|
+
splitsSyncTask.execute(true, cdnBypass ? maxChangeNumber : undefined, instantUpdate).then(() => {
|
|
40
|
+
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
41
|
+
if (handleNewEvent) {
|
|
42
|
+
__handleSplitUpdateCall();
|
|
43
|
+
} else {
|
|
44
|
+
if (instantUpdate) telemetryTracker.trackUpdatesFromSSE(SPLITS);
|
|
45
|
+
// fetch new registered segments for server-side API. Not retrying on error
|
|
46
|
+
if (segmentsSyncTask) segmentsSyncTask.execute(true);
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
|
|
45
|
-
isHandlingEvent = false;
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
+
const attempts = backoff.attempts + 1;
|
|
48
49
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
if (ff.isSync() && rbs.isSync()) {
|
|
51
|
+
log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
|
|
52
|
+
isHandlingEvent = false;
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
53
55
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
cdnBypass
|
|
60
|
-
|
|
56
|
+
if (attempts < FETCH_BACKOFF_MAX_RETRIES) {
|
|
57
|
+
backoff.scheduleCall();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (cdnBypass) {
|
|
62
|
+
log.debug(`No changes fetched after ${attempts} attempts with CDN bypassed.`);
|
|
63
|
+
isHandlingEvent = false;
|
|
64
|
+
} else {
|
|
65
|
+
backoff.reset();
|
|
66
|
+
cdnBypass = true;
|
|
67
|
+
__handleSplitUpdateCall();
|
|
68
|
+
}
|
|
61
69
|
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
isHandlingEvent = false;
|
|
73
|
+
}
|
|
66
74
|
}
|
|
67
|
-
}
|
|
68
75
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
return {
|
|
77
|
+
/**
|
|
78
|
+
* Invoked by NotificationProcessor on SPLIT_UPDATE or RB_SEGMENT_UPDATE event
|
|
79
|
+
*
|
|
80
|
+
* @param changeNumber - change number of the notification
|
|
81
|
+
*/
|
|
82
|
+
put({ changeNumber, pcn, type }: ISplitUpdateData, payload?: ISplit | IRBSegment) {
|
|
83
|
+
const currentChangeNumber = cache.getChangeNumber();
|
|
76
84
|
|
|
77
|
-
|
|
85
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
|
|
78
86
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
maxChangeNumber = changeNumber;
|
|
88
|
+
handleNewEvent = true;
|
|
89
|
+
cdnBypass = false;
|
|
90
|
+
instantUpdate = undefined;
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
if (payload && currentChangeNumber === pcn) {
|
|
93
|
+
instantUpdate = { payload, changeNumber, type };
|
|
94
|
+
}
|
|
87
95
|
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
if (backoff.timeoutID || !isHandlingEvent) __handleSplitUpdateCall();
|
|
97
|
+
backoff.reset();
|
|
98
|
+
},
|
|
99
|
+
stop() {
|
|
100
|
+
isHandlingEvent = false;
|
|
101
|
+
backoff.reset();
|
|
102
|
+
},
|
|
103
|
+
isSync() {
|
|
104
|
+
return maxChangeNumber <= cache.getChangeNumber();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
90
107
|
}
|
|
91
108
|
|
|
92
109
|
return {
|
|
93
|
-
put
|
|
110
|
+
put(parsedData) {
|
|
111
|
+
if (parsedData.d && parsedData.c !== undefined) {
|
|
112
|
+
try {
|
|
113
|
+
const payload = parseFFUpdatePayload(parsedData.c, parsedData.d);
|
|
114
|
+
if (payload) {
|
|
115
|
+
(parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
} catch (e) {
|
|
119
|
+
log.warn(STREAMING_PARSING_SPLIT_UPDATE, [parsedData.type, e]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
(parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData);
|
|
123
|
+
},
|
|
94
124
|
/**
|
|
95
125
|
* Invoked by NotificationProcessor on SPLIT_KILL event
|
|
96
126
|
*
|
|
97
|
-
* @param changeNumber - change number of the
|
|
127
|
+
* @param changeNumber - change number of the notification
|
|
98
128
|
* @param splitName - name of split to kill
|
|
99
129
|
* @param defaultTreatment - default treatment value
|
|
100
130
|
*/
|
|
101
131
|
killSplit({ changeNumber, splitName, defaultTreatment }: ISplitKillData) {
|
|
102
|
-
if (
|
|
132
|
+
if (storage.splits.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
103
133
|
// trigger an SDK_UPDATE if Split was killed locally
|
|
104
134
|
splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true);
|
|
105
135
|
}
|
|
106
136
|
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
107
|
-
put({ changeNumber } as ISplitUpdateData);
|
|
137
|
+
ff.put({ changeNumber } as ISplitUpdateData);
|
|
108
138
|
},
|
|
109
139
|
|
|
110
140
|
stop() {
|
|
111
|
-
|
|
112
|
-
|
|
141
|
+
ff.stop();
|
|
142
|
+
rbs.stop();
|
|
113
143
|
}
|
|
114
144
|
};
|
|
115
145
|
}
|
|
@@ -30,6 +30,7 @@ export const MEMBERSHIPS_LS_UPDATE = 'MEMBERSHIPS_LS_UPDATE';
|
|
|
30
30
|
export const SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
31
31
|
export const SPLIT_KILL = 'SPLIT_KILL';
|
|
32
32
|
export const SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
33
|
+
export const RB_SEGMENT_UPDATE = 'RB_SEGMENT_UPDATE';
|
|
33
34
|
|
|
34
35
|
// Control-type push notifications, handled by NotificationKeeper
|
|
35
36
|
export const CONTROL = 'CONTROL';
|
|
@@ -2,7 +2,7 @@ import { algorithms } from '../../utils/decompress';
|
|
|
2
2
|
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
3
|
import { hash } from '../../utils/murmur3/murmur3';
|
|
4
4
|
import { Compression, IMembershipMSUpdateData, KeyList } from './SSEHandler/types';
|
|
5
|
-
import { ISplit } from '../../dtos/types';
|
|
5
|
+
import { IRBSegment, ISplit } from '../../dtos/types';
|
|
6
6
|
|
|
7
7
|
const GZIP = 1;
|
|
8
8
|
const ZLIB = 2;
|
|
@@ -82,7 +82,7 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
|
|
|
82
82
|
/**
|
|
83
83
|
* Parse feature flags notifications for instant feature flag updates
|
|
84
84
|
*/
|
|
85
|
-
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | undefined {
|
|
85
|
+
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | IRBSegment | undefined {
|
|
86
86
|
return compression > 0 ?
|
|
87
87
|
parseKeyList(data, compression, false) :
|
|
88
88
|
JSON.parse(decodeFromBase64(data));
|