@splitsoftware/splitio-commons 1.16.1-rc.1 → 1.16.1-rc.10
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 +4 -0
- package/cjs/logger/constants.js +5 -4
- package/cjs/logger/messages/info.js +2 -1
- package/cjs/logger/messages/warn.js +1 -1
- package/cjs/readiness/readinessManager.js +7 -12
- package/cjs/services/splitApi.js +4 -8
- package/cjs/storages/AbstractSegmentsCacheSync.js +1 -6
- package/cjs/storages/AbstractSplitsCacheAsync.js +2 -2
- package/cjs/storages/AbstractSplitsCacheSync.js +7 -5
- package/cjs/storages/KeyBuilder.js +0 -3
- package/cjs/storages/KeyBuilderCS.js +6 -0
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +23 -2
- package/cjs/storages/inLocalStorage/SplitsCacheInLocal.js +4 -16
- package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +5 -1
- package/cjs/storages/inMemory/SplitsCacheInMemory.js +6 -15
- package/cjs/sync/polling/fetchers/mySegmentsFetcher.js +4 -11
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/cjs/sync/polling/pollingManagerCS.js +33 -51
- package/cjs/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +23 -19
- package/cjs/sync/streaming/SSEHandler/index.js +7 -8
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +8 -4
- package/cjs/sync/streaming/constants.js +2 -3
- package/cjs/sync/streaming/parseUtils.js +14 -9
- package/cjs/sync/streaming/pushManager.js +29 -52
- package/cjs/sync/submitters/telemetrySubmitter.js +0 -2
- package/cjs/sync/syncManagerOnline.js +14 -24
- package/cjs/utils/constants/index.js +1 -1
- package/cjs/utils/settingsValidation/index.js +1 -5
- package/esm/logger/constants.js +2 -1
- package/esm/logger/messages/info.js +2 -1
- package/esm/logger/messages/warn.js +1 -1
- package/esm/readiness/readinessManager.js +7 -12
- package/esm/services/splitApi.js +5 -9
- package/esm/storages/AbstractSegmentsCacheSync.js +1 -6
- package/esm/storages/AbstractSplitsCacheAsync.js +2 -2
- package/esm/storages/AbstractSplitsCacheSync.js +5 -3
- package/esm/storages/KeyBuilder.js +0 -3
- package/esm/storages/KeyBuilderCS.js +6 -0
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +23 -2
- package/esm/storages/inLocalStorage/SplitsCacheInLocal.js +5 -17
- package/esm/storages/inMemory/MySegmentsCacheInMemory.js +5 -1
- package/esm/storages/inMemory/SplitsCacheInMemory.js +7 -16
- package/esm/sync/polling/fetchers/mySegmentsFetcher.js +4 -11
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +1 -1
- package/esm/sync/polling/pollingManagerCS.js +34 -52
- package/esm/sync/polling/syncTasks/mySegmentsSyncTask.js +2 -2
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +21 -17
- package/esm/sync/streaming/SSEHandler/index.js +8 -9
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +8 -4
- package/esm/sync/streaming/constants.js +1 -2
- package/esm/sync/streaming/parseUtils.js +12 -8
- package/esm/sync/streaming/pushManager.js +31 -53
- package/esm/sync/submitters/telemetrySubmitter.js +0 -2
- package/esm/sync/syncManagerOnline.js +15 -25
- package/esm/utils/constants/index.js +1 -1
- package/esm/utils/settingsValidation/index.js +1 -5
- package/package.json +1 -1
- package/src/dtos/types.ts +14 -12
- package/src/logger/constants.ts +2 -1
- package/src/logger/messages/info.ts +2 -1
- package/src/logger/messages/warn.ts +1 -1
- package/src/readiness/readinessManager.ts +7 -9
- package/src/readiness/types.ts +0 -1
- package/src/services/splitApi.ts +6 -11
- package/src/services/splitHttpClient.ts +1 -1
- package/src/services/types.ts +2 -3
- package/src/storages/AbstractSegmentsCacheSync.ts +2 -6
- package/src/storages/AbstractSplitsCacheAsync.ts +2 -2
- package/src/storages/AbstractSplitsCacheSync.ts +6 -4
- package/src/storages/KeyBuilder.ts +0 -3
- package/src/storages/KeyBuilderCS.ts +9 -0
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +26 -2
- package/src/storages/inLocalStorage/SplitsCacheInLocal.ts +5 -20
- package/src/storages/inMemory/MySegmentsCacheInMemory.ts +7 -1
- package/src/storages/inMemory/SplitsCacheInMemory.ts +7 -13
- package/src/storages/types.ts +6 -5
- package/src/sync/polling/fetchers/mySegmentsFetcher.ts +7 -14
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +1 -1
- package/src/sync/polling/fetchers/types.ts +2 -2
- package/src/sync/polling/pollingManagerCS.ts +29 -61
- package/src/sync/polling/syncTasks/mySegmentsSyncTask.ts +12 -13
- package/src/sync/polling/types.ts +8 -7
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +20 -16
- package/src/sync/streaming/SSEClient/index.ts +4 -6
- package/src/sync/streaming/SSEHandler/index.ts +11 -13
- package/src/sync/streaming/SSEHandler/types.ts +13 -25
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +11 -7
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +1 -1
- package/src/sync/streaming/UpdateWorkers/types.ts +2 -2
- package/src/sync/streaming/constants.ts +1 -2
- package/src/sync/streaming/parseUtils.ts +19 -11
- package/src/sync/streaming/pushManager.ts +37 -64
- package/src/sync/streaming/types.ts +9 -11
- package/src/sync/submitters/telemetrySubmitter.ts +0 -2
- package/src/sync/submitters/types.ts +1 -3
- package/src/sync/syncManagerOnline.ts +11 -19
- package/src/types.ts +1 -26
- package/src/utils/constants/index.ts +1 -1
- package/src/utils/settingsValidation/index.ts +1 -5
- package/types/dtos/types.d.ts +14 -11
- package/types/logger/constants.d.ts +2 -1
- package/types/readiness/types.d.ts +0 -1
- package/types/services/decorateHeaders.d.ts +2 -0
- package/types/services/splitApi.d.ts +1 -1
- package/types/services/splitHttpClient.d.ts +1 -1
- package/types/services/types.d.ts +2 -3
- package/types/storages/AbstractSegmentsCacheSync.d.ts +2 -6
- package/types/storages/AbstractSplitsCacheAsync.d.ts +1 -1
- package/types/storages/AbstractSplitsCacheSync.d.ts +3 -3
- package/types/storages/KeyBuilder.d.ts +0 -1
- package/types/storages/KeyBuilderCS.d.ts +2 -0
- package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +3 -2
- package/types/storages/inLocalStorage/SplitsCacheInLocal.d.ts +1 -1
- package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +3 -1
- package/types/storages/inMemory/SplitsCacheInMemory.d.ts +1 -2
- package/types/storages/types.d.ts +4 -4
- 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 +4 -3
- package/types/sync/polling/types.d.ts +6 -12
- package/types/sync/polling/updaters/mySegmentsUpdater.d.ts +3 -2
- package/types/sync/streaming/SSEHandler/types.d.ts +13 -22
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +2 -2
- 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 +2 -2
- package/types/sync/streaming/constants.d.ts +1 -2
- package/types/sync/streaming/parseUtils.d.ts +4 -5
- package/types/sync/streaming/pushManager.d.ts +0 -2
- package/types/sync/streaming/pushManagerCS_Spec1_3.d.ts +9 -0
- package/types/sync/streaming/pushManager_Spec1_3.d.ts +9 -0
- package/types/sync/streaming/types.d.ts +8 -9
- package/types/sync/submitters/types.d.ts +1 -3
- package/types/types.d.ts +0 -25
- package/types/utils/constants/index.d.ts +1 -1
- package/types/utils/settingsValidation/index.d.ts +0 -2
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { IMySegmentsFetcher } from '../fetchers/types';
|
|
2
|
-
import {
|
|
2
|
+
import { IStorageSync } from '../../../storages/types';
|
|
3
|
+
import { ISegmentsEventEmitter } from '../../../readiness/types';
|
|
3
4
|
import { timeout } from '../../../utils/promise/timeout';
|
|
5
|
+
import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
4
6
|
import { ILogger } from '../../../logger/types';
|
|
5
7
|
import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
|
|
6
8
|
import { MySegmentsData } from '../types';
|
|
@@ -16,13 +18,14 @@ type IMySegmentsUpdater = (segmentList?: MySegmentsData, noCache?: boolean) => P
|
|
|
16
18
|
export function mySegmentsUpdaterFactory(
|
|
17
19
|
log: ILogger,
|
|
18
20
|
mySegmentsFetcher: IMySegmentsFetcher,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
storage: IStorageSync,
|
|
22
|
+
segmentsEventEmitter: ISegmentsEventEmitter,
|
|
21
23
|
requestTimeoutBeforeReady: number,
|
|
22
24
|
retriesOnFailureBeforeReady: number,
|
|
23
25
|
matchingKey: string
|
|
24
26
|
): IMySegmentsUpdater {
|
|
25
27
|
|
|
28
|
+
const { splits, segments, largeSegments } = storage;
|
|
26
29
|
let readyOnAlreadyExistentState = true;
|
|
27
30
|
let startingUp = true;
|
|
28
31
|
|
|
@@ -37,24 +40,25 @@ export function mySegmentsUpdaterFactory(
|
|
|
37
40
|
|
|
38
41
|
let shouldNotifyUpdate;
|
|
39
42
|
if (Array.isArray(segmentsData)) {
|
|
40
|
-
//
|
|
41
|
-
|
|
43
|
+
// Add/Delete the segment names
|
|
44
|
+
segmentsData.forEach(({ isLS, name, add }) => {
|
|
45
|
+
const cache = isLS ? largeSegments : segments;
|
|
46
|
+
if (cache!.isInSegment(name) !== add) {
|
|
47
|
+
shouldNotifyUpdate = true;
|
|
48
|
+
if (add) cache!.addToSegment(name);
|
|
49
|
+
else cache!.removeFromSegment(name);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
42
52
|
} else {
|
|
43
|
-
//
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
shouldNotifyUpdate = true;
|
|
47
|
-
if (add) mySegmentsCache.addToSegment(name);
|
|
48
|
-
else mySegmentsCache.removeFromSegment(name);
|
|
49
|
-
} else {
|
|
50
|
-
shouldNotifyUpdate = false;
|
|
51
|
-
}
|
|
53
|
+
// Reset the list of segment names
|
|
54
|
+
shouldNotifyUpdate = segments.resetSegments((segmentsData.ms?.k || []).map((segment) => segment.n), segmentsData.ms?.cn);
|
|
55
|
+
shouldNotifyUpdate = largeSegments!.resetSegments((segmentsData.ls?.k || []).map((segment) => segment.n), segmentsData.ls?.cn) || shouldNotifyUpdate;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
58
|
// Notify update if required
|
|
55
|
-
if (shouldNotifyUpdate || readyOnAlreadyExistentState) {
|
|
59
|
+
if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
56
60
|
readyOnAlreadyExistentState = false;
|
|
57
|
-
|
|
61
|
+
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -76,12 +76,10 @@ export class SSEClient implements ISSEClient {
|
|
|
76
76
|
open(authToken: IAuthTokenPushEnabled) {
|
|
77
77
|
this.close(); // it closes connection if previously opened
|
|
78
78
|
|
|
79
|
-
const channelsQueryParam = Object.keys(authToken.channels).map(
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
).join(',');
|
|
79
|
+
const channelsQueryParam = Object.keys(authToken.channels).map((channel) => {
|
|
80
|
+
const params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
|
|
81
|
+
return encodeURIComponent(params + channel);
|
|
82
|
+
}).join(',');
|
|
85
83
|
const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
|
|
86
84
|
|
|
87
85
|
this.connection = new this.eventSource!(
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { errorParser, messageParser } from './NotificationParser';
|
|
2
2
|
import { notificationKeeperFactory } from './NotificationKeeper';
|
|
3
|
-
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL,
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE_V3, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_LARGE_SEGMENTS_UPDATE } from '../constants';
|
|
4
4
|
import { IPushEventEmitter } from '../types';
|
|
5
5
|
import { ISseEventHandler } from '../SSEClient/types';
|
|
6
|
-
import { INotificationError, INotificationMessage } from './types';
|
|
6
|
+
import { IControlData, INotificationError, INotificationMessage, IOccupancyData } from './types';
|
|
7
7
|
import { ILogger } from '../../../logger/types';
|
|
8
8
|
import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
|
|
9
9
|
import { ABLY_ERROR, NON_REQUESTED, SSE_CONNECTION_ERROR } from '../../../utils/constants';
|
|
@@ -74,29 +74,27 @@ export function SSEHandlerFactory(log: ILogger, pushEmitter: IPushEventEmitter,
|
|
|
74
74
|
const { parsedData, data, channel, timestamp } = messageWithParsedData;
|
|
75
75
|
log.debug(STREAMING_NEW_MESSAGE, [data]);
|
|
76
76
|
|
|
77
|
-
// we only handle update events if streaming is up
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
// we only handle update events if streaming is up
|
|
78
|
+
// @ts-expect-error
|
|
79
|
+
const type = parsedData.type || parsedData.t;
|
|
80
|
+
if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(type) === -1) return;
|
|
80
81
|
|
|
81
|
-
switch (
|
|
82
|
+
switch (type) {
|
|
82
83
|
/* update events */
|
|
83
84
|
case SPLIT_UPDATE:
|
|
84
85
|
case SEGMENT_UPDATE:
|
|
85
|
-
case
|
|
86
|
+
case MY_SEGMENTS_UPDATE_V3:
|
|
86
87
|
case MY_LARGE_SEGMENTS_UPDATE:
|
|
87
88
|
case SPLIT_KILL:
|
|
88
|
-
pushEmitter.emit(
|
|
89
|
-
break;
|
|
90
|
-
case MY_SEGMENTS_UPDATE:
|
|
91
|
-
pushEmitter.emit(parsedData.type, parsedData, channel);
|
|
89
|
+
pushEmitter.emit(type, parsedData);
|
|
92
90
|
break;
|
|
93
91
|
|
|
94
92
|
/* occupancy & control events, handled by NotificationManagerKeeper */
|
|
95
93
|
case OCCUPANCY:
|
|
96
|
-
notificationKeeper.handleOccupancyEvent(parsedData.metrics.publishers, channel, timestamp);
|
|
94
|
+
notificationKeeper.handleOccupancyEvent((parsedData as IOccupancyData).metrics.publishers, channel, timestamp);
|
|
97
95
|
break;
|
|
98
96
|
case CONTROL:
|
|
99
|
-
notificationKeeper.handleControlEvent(parsedData.controlType, channel, timestamp);
|
|
97
|
+
notificationKeeper.handleControlEvent((parsedData as IControlData).controlType, channel, timestamp);
|
|
100
98
|
break;
|
|
101
99
|
|
|
102
100
|
default:
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { ControlType } from '../constants';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export interface IMySegmentsUpdateData {
|
|
5
|
-
type: MY_SEGMENTS_UPDATE,
|
|
6
|
-
changeNumber: number,
|
|
7
|
-
includesPayload: boolean,
|
|
8
|
-
segmentList?: string[]
|
|
9
|
-
}
|
|
2
|
+
import { SEGMENT_UPDATE, SPLIT_UPDATE, SPLIT_KILL, CONTROL, OCCUPANCY, MY_LARGE_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V3 } from '../types';
|
|
10
3
|
|
|
11
4
|
export enum Compression {
|
|
12
5
|
None = 0,
|
|
@@ -26,27 +19,22 @@ export interface KeyList {
|
|
|
26
19
|
r?: string[], // decimal hash64 of user keys
|
|
27
20
|
}
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
c
|
|
34
|
-
d
|
|
35
|
-
u: UpdateStrategy,
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface IMyLargeSegmentsUpdateData {
|
|
39
|
-
type: MY_LARGE_SEGMENTS_UPDATE,
|
|
40
|
-
changeNumber: number,
|
|
41
|
-
largeSegments: string[],
|
|
42
|
-
c: Compression,
|
|
43
|
-
d: string,
|
|
22
|
+
interface IMySegmentsUpdateData<T extends string> {
|
|
23
|
+
t: T,
|
|
24
|
+
cn: number,
|
|
25
|
+
n?: string[],
|
|
26
|
+
c?: Compression,
|
|
27
|
+
d?: string,
|
|
44
28
|
u: UpdateStrategy,
|
|
45
29
|
i?: number, // time interval in millis
|
|
46
|
-
h?: number, // hash function
|
|
30
|
+
h?: number, // hash function
|
|
47
31
|
s?: number, // seed for hash function
|
|
48
32
|
}
|
|
49
33
|
|
|
34
|
+
export interface IMySegmentsUpdateV3Data extends IMySegmentsUpdateData<MY_SEGMENTS_UPDATE_V3> { }
|
|
35
|
+
|
|
36
|
+
export interface IMyLargeSegmentsUpdateData extends IMySegmentsUpdateData<MY_LARGE_SEGMENTS_UPDATE> { }
|
|
37
|
+
|
|
50
38
|
export interface ISegmentUpdateData {
|
|
51
39
|
type: SEGMENT_UPDATE,
|
|
52
40
|
changeNumber: number,
|
|
@@ -80,6 +68,6 @@ export interface IOccupancyData {
|
|
|
80
68
|
}
|
|
81
69
|
}
|
|
82
70
|
|
|
83
|
-
export type INotificationData =
|
|
71
|
+
export type INotificationData = IMySegmentsUpdateV3Data | IMyLargeSegmentsUpdateData | ISegmentUpdateData | ISplitUpdateData | ISplitKillData | IControlData | IOccupancyData
|
|
84
72
|
export type INotificationMessage = { parsedData: INotificationData, channel: string, timestamp: number, data: string }
|
|
85
73
|
export type INotificationError = Event & { parsedData?: any, message?: string }
|
|
@@ -7,7 +7,7 @@ import { UpdatesFromSSEEnum } from '../../submitters/types';
|
|
|
7
7
|
/**
|
|
8
8
|
* MySegmentsUpdateWorker factory
|
|
9
9
|
*/
|
|
10
|
-
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker, updateType: UpdatesFromSSEEnum): IUpdateWorker {
|
|
10
|
+
export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask, telemetryTracker: ITelemetryTracker, updateType: UpdatesFromSSEEnum): IUpdateWorker<[changeNumber: number, segmentsData?: MySegmentsData, delay?: number]> {
|
|
11
11
|
|
|
12
12
|
let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
13
13
|
let currentChangeNumber = -1;
|
|
@@ -15,7 +15,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
15
15
|
let isHandlingEvent: boolean;
|
|
16
16
|
let _segmentsData: MySegmentsData | undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
17
17
|
let _delay: undefined | number;
|
|
18
|
-
let _delayTimeoutID:
|
|
18
|
+
let _delayTimeoutID: any;
|
|
19
19
|
const backoff = new Backoff(__handleMySegmentsUpdateCall);
|
|
20
20
|
|
|
21
21
|
function __handleMySegmentsUpdateCall() {
|
|
@@ -28,6 +28,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
28
28
|
const syncTask = _delay ?
|
|
29
29
|
new Promise(res => {
|
|
30
30
|
_delayTimeoutID = setTimeout(() => {
|
|
31
|
+
_delay = undefined;
|
|
31
32
|
mySegmentsSyncTask.execute(_segmentsData, true).then(res);
|
|
32
33
|
}, _delay);
|
|
33
34
|
}) :
|
|
@@ -35,7 +36,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
35
36
|
|
|
36
37
|
syncTask.then((result) => {
|
|
37
38
|
if (!isHandlingEvent) return; // halt if `stop` has been called
|
|
38
|
-
if (result !== false) {// Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
39
|
+
if (result !== false) { // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
39
40
|
if (_segmentsData) telemetryTracker.trackUpdatesFromSSE(updateType);
|
|
40
41
|
currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
|
|
41
42
|
}
|
|
@@ -52,13 +53,15 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
52
53
|
|
|
53
54
|
return {
|
|
54
55
|
/**
|
|
55
|
-
* Invoked by NotificationProcessor on
|
|
56
|
+
* Invoked by NotificationProcessor on MY_(LARGE)_SEGMENTS_UPDATE notifications
|
|
56
57
|
*
|
|
57
|
-
* @param
|
|
58
|
-
* @param
|
|
58
|
+
* @param changeNumber change number of the notification
|
|
59
|
+
* @param segmentsData data for KeyList or SegmentRemoval instant updates
|
|
60
|
+
* @param delay optional time to wait for BoundedFetchRequest or BoundedFetchRequest updates
|
|
59
61
|
*/
|
|
60
62
|
put(changeNumber: number, segmentsData?: MySegmentsData, delay?: number) {
|
|
61
|
-
if
|
|
63
|
+
// Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
|
|
64
|
+
if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber || _delay) return;
|
|
62
65
|
|
|
63
66
|
maxChangeNumber = changeNumber;
|
|
64
67
|
handleNewEvent = true;
|
|
@@ -71,6 +74,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask: IMySegmentsSyncTask,
|
|
|
71
74
|
|
|
72
75
|
stop() {
|
|
73
76
|
clearTimeout(_delayTimeoutID);
|
|
77
|
+
_delay = undefined;
|
|
74
78
|
isHandlingEvent = false;
|
|
75
79
|
backoff.reset();
|
|
76
80
|
}
|
|
@@ -9,7 +9,7 @@ import { IUpdateWorker } from './types';
|
|
|
9
9
|
/**
|
|
10
10
|
* SegmentsUpdateWorker factory
|
|
11
11
|
*/
|
|
12
|
-
export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSyncTask, segmentsCache: ISegmentsCacheSync): IUpdateWorker {
|
|
12
|
+
export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSyncTask, segmentsCache: ISegmentsCacheSync): IUpdateWorker<[ISegmentUpdateData]> {
|
|
13
13
|
|
|
14
14
|
// Handles retries with CDN bypass per segment name
|
|
15
15
|
function SegmentUpdateWorker(segment: string) {
|
|
@@ -14,7 +14,7 @@ import { IUpdateWorker } from './types';
|
|
|
14
14
|
/**
|
|
15
15
|
* SplitsUpdateWorker factory
|
|
16
16
|
*/
|
|
17
|
-
export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker & { killSplit(event: ISplitKillData): void } {
|
|
17
|
+
export function SplitsUpdateWorker(log: ILogger, splitsCache: ISplitsCacheSync, splitsSyncTask: ISplitsSyncTask, splitsEventEmitter: ISplitsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData, payload?: ISplit]> & { killSplit(event: ISplitKillData): void } {
|
|
18
18
|
|
|
19
19
|
let maxChangeNumber = 0;
|
|
20
20
|
let handleNewEvent = false;
|
|
@@ -25,8 +25,7 @@ export const PUSH_SUBSYSTEM_UP = 'PUSH_SUBSYSTEM_UP';
|
|
|
25
25
|
export const PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN';
|
|
26
26
|
|
|
27
27
|
// Update-type push notifications, handled by NotificationProcessor
|
|
28
|
-
export const
|
|
29
|
-
export const MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
|
|
28
|
+
export const MY_SEGMENTS_UPDATE_V3 = 'MY_SEGMENTS_UPDATE_V3';
|
|
30
29
|
export const SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
31
30
|
export const SPLIT_KILL = 'SPLIT_KILL';
|
|
32
31
|
export const SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { algorithms } from '../../utils/decompress';
|
|
2
2
|
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
|
-
import {
|
|
3
|
+
import { hash } from '../../utils/murmur3/murmur3';
|
|
4
|
+
import { Compression, IMyLargeSegmentsUpdateData, KeyList } from './SSEHandler/types';
|
|
5
|
+
import { ISplit } from '../../dtos/types';
|
|
4
6
|
|
|
5
7
|
const GZIP = 1;
|
|
6
8
|
const ZLIB = 2;
|
|
@@ -42,7 +44,7 @@ function decompress(data: string, compression: Compression) {
|
|
|
42
44
|
* @returns {{a?: string[], r?: string[] }}
|
|
43
45
|
* @throws if data string cannot be decoded, decompressed or parsed
|
|
44
46
|
*/
|
|
45
|
-
export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss
|
|
47
|
+
export function parseKeyList(data: string, compression: Compression, avoidPrecisionLoss = true): KeyList {
|
|
46
48
|
const binKeyList = decompress(data, compression);
|
|
47
49
|
let strKeyList = Uint8ArrayToString(binKeyList);
|
|
48
50
|
// replace numbers to strings, to avoid losing precision
|
|
@@ -80,14 +82,20 @@ export function isInBitmap(bitmap: Uint8Array, hash64hex: string) {
|
|
|
80
82
|
|
|
81
83
|
/**
|
|
82
84
|
* Parse feature flags notifications for instant feature flag updates
|
|
83
|
-
*
|
|
84
|
-
* @param {ISplitUpdateData} data
|
|
85
|
-
* @returns {KeyList}
|
|
86
85
|
*/
|
|
87
|
-
export function parseFFUpdatePayload(compression: Compression, data: string):
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
export function parseFFUpdatePayload(compression: Compression, data: string): ISplit | undefined {
|
|
87
|
+
return compression > 0 ?
|
|
88
|
+
parseKeyList(data, compression, false) :
|
|
89
|
+
JSON.parse(decodeFromBase64(data));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const DEFAULT_MAX_INTERVAL = 60000;
|
|
93
|
+
|
|
94
|
+
export function getDelay(parsedData: Pick<IMyLargeSegmentsUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
|
|
95
|
+
if (parsedData.h === 0) return 0;
|
|
96
|
+
|
|
97
|
+
const interval = parsedData.i || DEFAULT_MAX_INTERVAL;
|
|
98
|
+
const seed = parsedData.s || 0;
|
|
99
|
+
|
|
100
|
+
return hash(matchingKey, seed) % interval;
|
|
93
101
|
}
|
|
@@ -11,24 +11,15 @@ import { authenticateFactory, hashUserKey } from './AuthClient';
|
|
|
11
11
|
import { forOwn } from '../../utils/lang';
|
|
12
12
|
import { SSEClient } from './SSEClient';
|
|
13
13
|
import { getMatching } from '../../utils/key';
|
|
14
|
-
import {
|
|
15
|
-
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT,
|
|
16
|
-
import { IMyLargeSegmentsUpdateData,
|
|
17
|
-
import { isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
14
|
+
import { MY_SEGMENTS_UPDATE_V3, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType, MY_LARGE_SEGMENTS_UPDATE } from './constants';
|
|
15
|
+
import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MY_SEGMENTS_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
|
|
16
|
+
import { IMyLargeSegmentsUpdateData, IMySegmentsUpdateV3Data, KeyList, UpdateStrategy } from './SSEHandler/types';
|
|
17
|
+
import { getDelay, isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
|
|
18
18
|
import { ISet, _Set } from '../../utils/lang/sets';
|
|
19
|
-
import { hash } from '../../utils/murmur3/murmur3';
|
|
20
19
|
import { Hash64, hash64 } from '../../utils/murmur3/murmur3_64';
|
|
21
20
|
import { IAuthTokenPushEnabled } from './AuthClient/types';
|
|
22
21
|
import { TOKEN_REFRESH, AUTH_REJECTION, MY_LARGE_SEGMENT, MY_SEGMENT } from '../../utils/constants';
|
|
23
22
|
import { ISdkFactoryContextSync } from '../../sdkFactory/types';
|
|
24
|
-
import { IUpdateWorker } from './UpdateWorkers/types';
|
|
25
|
-
|
|
26
|
-
export function getDelay(parsedData: Pick<IMyLargeSegmentsUpdateData, 'i' | 'h' | 's'>, matchingKey: string) {
|
|
27
|
-
const interval = parsedData.i || 60000;
|
|
28
|
-
const seed = parsedData.s || 0;
|
|
29
|
-
|
|
30
|
-
return hash(matchingKey, seed) % interval;
|
|
31
|
-
}
|
|
32
23
|
|
|
33
24
|
/**
|
|
34
25
|
* PushManager factory:
|
|
@@ -71,8 +62,8 @@ export function pushManagerFactory(
|
|
|
71
62
|
// [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
|
|
72
63
|
const userKeyHashes: Record<string, string> = {};
|
|
73
64
|
// [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
|
|
74
|
-
// Hash64 is used to process
|
|
75
|
-
const clients: Record<string, { hash64: Hash64, worker:
|
|
65
|
+
// Hash64 is used to process MY_SEGMENTS_UPDATE events and dispatch actions to the corresponding MySegmentsUpdateWorker.
|
|
66
|
+
const clients: Record<string, { hash64: Hash64, worker: ReturnType<typeof MySegmentsUpdateWorker>, workerLarge: ReturnType<typeof MySegmentsUpdateWorker> }> = {};
|
|
76
67
|
|
|
77
68
|
// [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
|
|
78
69
|
let connectForNewClient = false;
|
|
@@ -181,7 +172,7 @@ export function pushManagerFactory(
|
|
|
181
172
|
splitsUpdateWorker.stop();
|
|
182
173
|
if (userKey) forOwn(clients, ({ worker, workerLarge }) => {
|
|
183
174
|
worker.stop();
|
|
184
|
-
workerLarge
|
|
175
|
+
workerLarge.stop();
|
|
185
176
|
});
|
|
186
177
|
else segmentsUpdateWorker!.stop();
|
|
187
178
|
}
|
|
@@ -247,24 +238,22 @@ export function pushManagerFactory(
|
|
|
247
238
|
splitsUpdateWorker.put(parsedData);
|
|
248
239
|
});
|
|
249
240
|
|
|
250
|
-
function handleMySegmentsUpdate(parsedData:
|
|
251
|
-
const isLS = parsedData.
|
|
241
|
+
function handleMySegmentsUpdate(parsedData: IMySegmentsUpdateV3Data | IMyLargeSegmentsUpdateData) {
|
|
242
|
+
const isLS = parsedData.t === MY_LARGE_SEGMENTS_UPDATE;
|
|
252
243
|
|
|
253
244
|
switch (parsedData.u) {
|
|
254
245
|
case UpdateStrategy.BoundedFetchRequest: {
|
|
255
246
|
let bitmap: Uint8Array;
|
|
256
247
|
try {
|
|
257
|
-
bitmap = parseBitmap(parsedData.d
|
|
248
|
+
bitmap = parseBitmap(parsedData.d!, parsedData.c!);
|
|
258
249
|
} catch (e) {
|
|
259
|
-
log.warn(
|
|
250
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['BoundedFetchRequest', e]);
|
|
260
251
|
break;
|
|
261
252
|
}
|
|
262
253
|
|
|
263
254
|
forOwn(clients, ({ hash64, worker, workerLarge }, matchingKey) => {
|
|
264
255
|
if (isInBitmap(bitmap, hash64.hex)) {
|
|
265
|
-
isLS ?
|
|
266
|
-
workerLarge && workerLarge.put(parsedData.changeNumber, undefined, getDelay(parsedData, matchingKey)) :
|
|
267
|
-
worker.put(parsedData.changeNumber);
|
|
256
|
+
(isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
|
|
268
257
|
}
|
|
269
258
|
});
|
|
270
259
|
return;
|
|
@@ -272,72 +261,56 @@ export function pushManagerFactory(
|
|
|
272
261
|
case UpdateStrategy.KeyList: {
|
|
273
262
|
let keyList: KeyList, added: ISet<string>, removed: ISet<string>;
|
|
274
263
|
try {
|
|
275
|
-
keyList = parseKeyList(parsedData.d
|
|
264
|
+
keyList = parseKeyList(parsedData.d!, parsedData.c!);
|
|
276
265
|
added = new _Set(keyList.a);
|
|
277
266
|
removed = new _Set(keyList.r);
|
|
278
267
|
} catch (e) {
|
|
279
|
-
log.warn(
|
|
268
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', e]);
|
|
269
|
+
break;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (!parsedData.n || !parsedData.n.length) {
|
|
273
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', 'No segment name was provided']);
|
|
280
274
|
break;
|
|
281
275
|
}
|
|
282
276
|
|
|
283
277
|
forOwn(clients, ({ hash64, worker, workerLarge }) => {
|
|
284
278
|
const add = added.has(hash64.dec) ? true : removed.has(hash64.dec) ? false : undefined;
|
|
285
279
|
if (add !== undefined) {
|
|
286
|
-
isLS ?
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
worker.put(parsedData.changeNumber, {
|
|
292
|
-
name: parsedData.segmentName,
|
|
293
|
-
add
|
|
294
|
-
});
|
|
280
|
+
(isLS ? workerLarge : worker).put(parsedData.cn, [{
|
|
281
|
+
isLS,
|
|
282
|
+
name: parsedData.n![0],
|
|
283
|
+
add,
|
|
284
|
+
}]);
|
|
295
285
|
}
|
|
296
286
|
});
|
|
297
287
|
return;
|
|
298
288
|
}
|
|
299
289
|
case UpdateStrategy.SegmentRemoval:
|
|
300
|
-
if (
|
|
301
|
-
log.warn(
|
|
290
|
+
if (!parsedData.n || !parsedData.n.length) {
|
|
291
|
+
log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
|
|
302
292
|
break;
|
|
303
293
|
}
|
|
304
294
|
|
|
305
295
|
forOwn(clients, ({ worker, workerLarge }) => {
|
|
306
|
-
isLS ?
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}) :
|
|
313
|
-
worker.put(parsedData.changeNumber, {
|
|
314
|
-
name: parsedData.segmentName,
|
|
315
|
-
add: false
|
|
316
|
-
});
|
|
296
|
+
(isLS ? workerLarge : worker).put(parsedData.cn, parsedData.n!.map(largeSegment => ({
|
|
297
|
+
isLS,
|
|
298
|
+
name: largeSegment,
|
|
299
|
+
add: false,
|
|
300
|
+
cn: parsedData.cn
|
|
301
|
+
})));
|
|
317
302
|
});
|
|
318
303
|
return;
|
|
319
304
|
}
|
|
320
305
|
|
|
321
306
|
// `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
|
|
322
307
|
forOwn(clients, ({ worker, workerLarge }, matchingKey) => {
|
|
323
|
-
isLS ?
|
|
324
|
-
workerLarge && workerLarge.put(parsedData.changeNumber, undefined, getDelay(parsedData, matchingKey)) :
|
|
325
|
-
worker.put(parsedData.changeNumber);
|
|
308
|
+
(isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
|
|
326
309
|
});
|
|
327
310
|
}
|
|
328
311
|
|
|
329
312
|
if (userKey) {
|
|
330
|
-
pushEmitter.on(
|
|
331
|
-
const userKeyHash = channel.split('_')[2];
|
|
332
|
-
const userKey = userKeyHashes[userKeyHash];
|
|
333
|
-
if (userKey && clients[userKey]) { // check existence since it can be undefined if client has been destroyed
|
|
334
|
-
clients[userKey].worker.put(
|
|
335
|
-
parsedData.changeNumber,
|
|
336
|
-
parsedData.includesPayload ? parsedData.segmentList ? parsedData.segmentList : [] : undefined);
|
|
337
|
-
}
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
pushEmitter.on(MY_SEGMENTS_UPDATE_V2, handleMySegmentsUpdate);
|
|
313
|
+
pushEmitter.on(MY_SEGMENTS_UPDATE_V3, handleMySegmentsUpdate);
|
|
341
314
|
pushEmitter.on(MY_LARGE_SEGMENTS_UPDATE, handleMySegmentsUpdate);
|
|
342
315
|
} else {
|
|
343
316
|
pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker!.put);
|
|
@@ -361,7 +334,7 @@ export function pushManagerFactory(
|
|
|
361
334
|
if (disabled || disconnected === false) return;
|
|
362
335
|
disconnected = false;
|
|
363
336
|
|
|
364
|
-
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask
|
|
337
|
+
if (userKey) this.add(userKey, pollingManager.segmentsSyncTask); // client-side
|
|
365
338
|
else setTimeout(connectPush); // server-side runs in next cycle as in client-side, for consistency with client-side
|
|
366
339
|
},
|
|
367
340
|
|
|
@@ -371,7 +344,7 @@ export function pushManagerFactory(
|
|
|
371
344
|
},
|
|
372
345
|
|
|
373
346
|
// [Only for client-side]
|
|
374
|
-
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask
|
|
347
|
+
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask) {
|
|
375
348
|
const hash = hashUserKey(userKey);
|
|
376
349
|
|
|
377
350
|
if (!userKeyHashes[hash]) {
|
|
@@ -379,7 +352,7 @@ export function pushManagerFactory(
|
|
|
379
352
|
clients[userKey] = {
|
|
380
353
|
hash64: hash64(userKey),
|
|
381
354
|
worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_SEGMENT),
|
|
382
|
-
workerLarge:
|
|
355
|
+
workerLarge: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_LARGE_SEGMENT)
|
|
383
356
|
};
|
|
384
357
|
connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
|
|
385
358
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IMySegmentsUpdateV3Data, ISegmentUpdateData, ISplitUpdateData, ISplitKillData, IMyLargeSegmentsUpdateData, INotificationData } from './SSEHandler/types';
|
|
2
2
|
import { ITask } from '../types';
|
|
3
3
|
import { IMySegmentsSyncTask } from '../polling/types';
|
|
4
4
|
import { IEventEmitter } from '../../types';
|
|
@@ -11,8 +11,7 @@ export type PUSH_NONRETRYABLE_ERROR = 'PUSH_NONRETRYABLE_ERROR'
|
|
|
11
11
|
export type PUSH_RETRYABLE_ERROR = 'PUSH_RETRYABLE_ERROR'
|
|
12
12
|
|
|
13
13
|
// Update-type push notifications, handled by NotificationProcessor
|
|
14
|
-
export type
|
|
15
|
-
export type MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
|
|
14
|
+
export type MY_SEGMENTS_UPDATE_V3 = 'MY_SEGMENTS_UPDATE_V3';
|
|
16
15
|
export type SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
17
16
|
export type SPLIT_KILL = 'SPLIT_KILL';
|
|
18
17
|
export type SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
@@ -22,24 +21,23 @@ export type MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
|
|
|
22
21
|
export type CONTROL = 'CONTROL';
|
|
23
22
|
export type OCCUPANCY = 'OCCUPANCY';
|
|
24
23
|
|
|
25
|
-
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR |
|
|
24
|
+
export type IPushEvent = PUSH_SUBSYSTEM_UP | PUSH_SUBSYSTEM_DOWN | PUSH_NONRETRYABLE_ERROR | PUSH_RETRYABLE_ERROR | MY_SEGMENTS_UPDATE_V3 | SEGMENT_UPDATE | SPLIT_UPDATE | SPLIT_KILL | MY_LARGE_SEGMENTS_UPDATE | ControlType.STREAMING_RESET
|
|
26
25
|
|
|
27
26
|
type IParsedData<T extends IPushEvent> =
|
|
28
|
-
T extends
|
|
29
|
-
T extends MY_SEGMENTS_UPDATE_V2 ? IMySegmentsUpdateV2Data :
|
|
27
|
+
T extends MY_SEGMENTS_UPDATE_V3 ? IMySegmentsUpdateV3Data :
|
|
30
28
|
T extends MY_LARGE_SEGMENTS_UPDATE ? IMyLargeSegmentsUpdateData :
|
|
31
29
|
T extends SEGMENT_UPDATE ? ISegmentUpdateData :
|
|
32
30
|
T extends SPLIT_UPDATE ? ISplitUpdateData :
|
|
33
|
-
T extends SPLIT_KILL ? ISplitKillData :
|
|
31
|
+
T extends SPLIT_KILL ? ISplitKillData : INotificationData;
|
|
34
32
|
|
|
35
33
|
/**
|
|
36
34
|
* EventEmitter used as Feedback Loop between the SyncManager and PushManager,
|
|
37
35
|
* where the latter pushes messages and the former consumes it
|
|
38
36
|
*/
|
|
39
37
|
export interface IPushEventEmitter extends IEventEmitter {
|
|
40
|
-
once<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T
|
|
41
|
-
on<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T
|
|
42
|
-
emit<T extends IPushEvent>(event: T, parsedData?: IParsedData<T
|
|
38
|
+
once<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>) => void): this;
|
|
39
|
+
on<T extends IPushEvent>(event: T, listener: (parsedData: IParsedData<T>) => void): this;
|
|
40
|
+
emit<T extends IPushEvent>(event: T, parsedData?: IParsedData<T>): boolean;
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
/**
|
|
@@ -47,6 +45,6 @@ export interface IPushEventEmitter extends IEventEmitter {
|
|
|
47
45
|
*/
|
|
48
46
|
export interface IPushManager extends ITask, IPushEventEmitter {
|
|
49
47
|
// Methods used in client-side, to support multiple clients
|
|
50
|
-
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask
|
|
48
|
+
add(userKey: string, mySegmentsSyncTask: IMySegmentsSyncTask): void,
|
|
51
49
|
remove(userKey: string): void
|
|
52
50
|
}
|
|
@@ -76,12 +76,10 @@ export function telemetryCacheConfigAdapter(telemetry: ITelemetryCacheSync, sett
|
|
|
76
76
|
|
|
77
77
|
return objectAssign(getTelemetryConfigStats(settings.mode, settings.storage.type), {
|
|
78
78
|
sE: settings.streamingEnabled,
|
|
79
|
-
lE: isClientSide ? settings.sync.largeSegmentsEnabled : undefined,
|
|
80
79
|
rR: {
|
|
81
80
|
sp: scheduler.featuresRefreshRate / 1000,
|
|
82
81
|
se: isClientSide ? undefined : scheduler.segmentsRefreshRate / 1000,
|
|
83
82
|
ms: isClientSide ? scheduler.segmentsRefreshRate / 1000 : undefined,
|
|
84
|
-
mls: isClientSide && settings.sync.largeSegmentsEnabled ? scheduler.largeSegmentsRefreshRate / 1000 : undefined,
|
|
85
83
|
im: scheduler.impressionsRefreshRate / 1000,
|
|
86
84
|
ev: scheduler.eventsPushRate / 1000,
|
|
87
85
|
te: scheduler.telemetryRefreshRate / 1000,
|
|
@@ -114,7 +114,7 @@ export type TOKEN = 'to';
|
|
|
114
114
|
export type SEGMENT = 'se';
|
|
115
115
|
export type MY_SEGMENT = 'ms';
|
|
116
116
|
export type MY_LARGE_SEGMENT = 'mls';
|
|
117
|
-
export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MY_SEGMENT
|
|
117
|
+
export type OperationType = SPLITS | IMPRESSIONS | IMPRESSIONS_COUNT | EVENTS | TELEMETRY | TOKEN | SEGMENT | MY_SEGMENT;
|
|
118
118
|
|
|
119
119
|
export type LastSync = Partial<Record<OperationType, number | undefined>>
|
|
120
120
|
export type HttpErrors = Partial<Record<OperationType, { [statusCode: string]: number }>>
|
|
@@ -205,7 +205,6 @@ export type RefreshRates = {
|
|
|
205
205
|
sp: number, // splits
|
|
206
206
|
se?: number, // segments
|
|
207
207
|
ms?: number, // mySegments
|
|
208
|
-
mls?: number, // myLargeSegments
|
|
209
208
|
im: number, // impressions
|
|
210
209
|
ev: number, // events
|
|
211
210
|
te: number, // telemetry
|
|
@@ -231,7 +230,6 @@ export type TelemetryConfigStats = {
|
|
|
231
230
|
// 'metrics/config' JSON request body
|
|
232
231
|
export type TelemetryConfigStatsPayload = TelemetryConfigStats & {
|
|
233
232
|
sE: boolean, // streamingEnabled
|
|
234
|
-
lE?: boolean, // largeSegmentsEnabled
|
|
235
233
|
rR: RefreshRates, // refreshRates
|
|
236
234
|
uO: UrlOverrides, // urlOverrides
|
|
237
235
|
iQ: number, // impressionsQueueSize
|