@splitsoftware/splitio-commons 0.1.1-canary.6 → 0.1.1-rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/evaluator/matchers/matcherTypes.js +4 -4
- package/cjs/evaluator/matchersTransform/index.js +11 -11
- package/cjs/evaluator/value/sanitize.js +6 -6
- package/cjs/listeners/browser.js +5 -2
- package/cjs/listeners/node.js +9 -2
- package/cjs/logger/constants.js +3 -1
- package/cjs/logger/messages/error.js +3 -2
- package/cjs/logger/messages/info.js +2 -2
- package/cjs/logger/messages/warn.js +2 -1
- package/cjs/readiness/readinessManager.js +10 -7
- package/cjs/sdkFactory/index.js +1 -1
- package/cjs/services/splitApi.js +9 -1
- package/cjs/services/splitHttpClient.js +5 -4
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/inLocalStorage/index.js +5 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/cjs/storages/inRedis/index.js +5 -2
- package/cjs/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +6 -7
- package/cjs/storages/pluggable/index.js +5 -2
- package/cjs/storages/pluggable/wrapperAdapter.js +0 -1
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +92 -89
- package/cjs/sync/offline/splitsParser/splitsParserFromSettings.js +45 -42
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -4
- package/cjs/sync/polling/fetchers/segmentChangesFetcher.js +0 -8
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/cjs/sync/polling/updaters/segmentChangesUpdater.js +2 -4
- package/cjs/sync/streaming/SSEClient/index.js +38 -20
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/cjs/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/cjs/sync/streaming/SSEHandler/index.js +8 -9
- package/cjs/sync/streaming/SSEHandler/types.js +14 -0
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/cjs/sync/streaming/constants.js +3 -1
- package/cjs/sync/streaming/mySegmentsV2utils.js +75 -0
- package/cjs/sync/streaming/pushManager.js +148 -40
- package/cjs/sync/submitters/metricsSyncTask.js +1 -1
- package/cjs/sync/submitters/submitterSyncTask.js +2 -2
- package/cjs/sync/syncManagerFromFile.js +15 -0
- package/cjs/sync/syncManagerFromObject.js +14 -0
- package/cjs/sync/syncManagerOffline.js +3 -3
- package/cjs/sync/syncManagerOnline.js +18 -5
- package/cjs/sync/syncTask.js +1 -1
- package/cjs/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/cjs/trackers/impressionObserver/buildKey.js +3 -9
- package/cjs/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/cjs/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/cjs/utils/constants/index.js +4 -1
- package/cjs/utils/decompress/index.js +427 -0
- package/cjs/utils/murmur3/{commons.js → common.js} +2 -6
- package/cjs/utils/murmur3/murmur3.js +11 -12
- package/cjs/utils/murmur3/murmur3_128.js +7 -142
- package/cjs/utils/murmur3/murmur3_128_x86.js +154 -0
- package/cjs/utils/murmur3/murmur3_64.js +36 -0
- package/cjs/utils/murmur3/utfx.js +100 -106
- package/cjs/utils/promise/wrapper.js +14 -11
- package/cjs/utils/settingsValidation/index.js +5 -2
- package/cjs/utils/settingsValidation/localhost/index.js +20 -0
- package/cjs/utils/settingsValidation/splitFilters.js +0 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +18 -8
- package/cjs/utils/settingsValidation/url.js +1 -1
- package/esm/evaluator/matchers/matcherTypes.js +2 -2
- package/esm/evaluator/matchersTransform/index.js +12 -12
- package/esm/evaluator/value/sanitize.js +7 -7
- package/esm/listeners/browser.js +5 -2
- package/esm/listeners/node.js +9 -2
- package/esm/logger/constants.js +2 -0
- package/esm/logger/messages/error.js +3 -2
- package/esm/logger/messages/info.js +2 -2
- package/esm/logger/messages/warn.js +2 -1
- package/esm/readiness/readinessManager.js +10 -7
- package/esm/sdkFactory/index.js +1 -1
- package/esm/services/splitApi.js +9 -1
- package/esm/services/splitHttpClient.js +5 -4
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/inLocalStorage/index.js +5 -2
- package/esm/storages/inMemory/InMemoryStorage.js +2 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/esm/storages/inRedis/index.js +5 -2
- package/esm/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +6 -7
- package/esm/storages/pluggable/index.js +5 -2
- package/esm/storages/pluggable/wrapperAdapter.js +0 -1
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +90 -88
- package/esm/sync/offline/splitsParser/splitsParserFromSettings.js +43 -41
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +15 -5
- package/esm/sync/polling/fetchers/segmentChangesFetcher.js +0 -8
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/esm/sync/polling/updaters/segmentChangesUpdater.js +2 -4
- package/esm/sync/streaming/SSEClient/index.js +38 -20
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/esm/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/esm/sync/streaming/SSEHandler/index.js +9 -10
- package/esm/sync/streaming/SSEHandler/types.js +13 -1
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/esm/sync/streaming/constants.js +2 -0
- package/esm/sync/streaming/mySegmentsV2utils.js +69 -0
- package/esm/sync/streaming/pushManager.js +150 -42
- package/esm/sync/submitters/metricsSyncTask.js +1 -1
- package/esm/sync/submitters/submitterSyncTask.js +2 -2
- package/esm/sync/syncManagerFromFile.js +11 -0
- package/esm/sync/syncManagerFromObject.js +10 -0
- package/esm/sync/syncManagerOffline.js +3 -3
- package/esm/sync/syncManagerOnline.js +18 -5
- package/esm/sync/syncTask.js +1 -1
- package/esm/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/esm/trackers/impressionObserver/buildKey.js +2 -9
- package/esm/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/esm/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/esm/utils/constants/index.js +3 -0
- package/esm/utils/decompress/index.js +424 -0
- package/esm/utils/murmur3/{commons.js → common.js} +1 -4
- package/esm/utils/murmur3/murmur3.js +1 -2
- package/esm/utils/murmur3/murmur3_128.js +7 -142
- package/esm/utils/murmur3/murmur3_128_x86.js +150 -0
- package/esm/utils/murmur3/murmur3_64.js +32 -0
- package/esm/utils/murmur3/utfx.js +96 -106
- package/esm/utils/promise/wrapper.js +14 -11
- package/esm/utils/settingsValidation/index.js +5 -2
- package/esm/utils/settingsValidation/localhost/index.js +16 -0
- package/esm/utils/settingsValidation/splitFilters.js +0 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +16 -7
- package/esm/utils/settingsValidation/url.js +1 -1
- package/package.json +5 -5
- package/src/evaluator/matchers/matcherTypes.ts +2 -2
- package/src/evaluator/matchersTransform/index.ts +12 -12
- package/src/evaluator/value/sanitize.ts +7 -7
- package/src/listeners/browser.ts +5 -2
- package/src/listeners/node.ts +14 -2
- package/src/logger/constants.ts +2 -0
- package/src/logger/messages/error.ts +3 -2
- package/src/logger/messages/info.ts +2 -2
- package/src/logger/messages/warn.ts +3 -1
- package/src/readiness/readinessManager.ts +9 -7
- package/src/sdkFactory/index.ts +1 -1
- package/src/sdkFactory/types.ts +4 -5
- package/src/services/splitApi.ts +12 -3
- package/src/services/splitHttpClient.ts +6 -5
- package/src/services/types.ts +7 -3
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/inLocalStorage/index.ts +8 -4
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +3 -1
- package/src/storages/inRedis/index.ts +8 -4
- package/src/storages/pluggable/SegmentsCachePluggable.ts +1 -1
- package/src/storages/pluggable/SplitsCachePluggable.ts +3 -1
- package/src/storages/pluggable/inMemoryWrapper.ts +6 -7
- package/src/storages/pluggable/index.ts +8 -4
- package/src/storages/pluggable/wrapperAdapter.ts +0 -1
- package/src/storages/types.ts +18 -15
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +110 -105
- package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +45 -41
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +15 -5
- package/src/sync/polling/fetchers/segmentChangesFetcher.ts +0 -7
- package/src/sync/polling/types.ts +2 -1
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +28 -10
- package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -3
- package/src/sync/streaming/AuthClient/types.ts +3 -0
- package/src/sync/streaming/SSEClient/index.ts +43 -23
- package/src/sync/streaming/SSEClient/types.ts +0 -1
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +8 -0
- package/src/sync/streaming/SSEHandler/NotificationParser.ts +4 -2
- package/src/sync/streaming/SSEHandler/index.ts +11 -20
- package/src/sync/streaming/SSEHandler/types.ts +37 -3
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +7 -6
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +2 -1
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +4 -3
- package/src/sync/streaming/UpdateWorkers/types.ts +1 -1
- package/src/sync/streaming/constants.ts +2 -0
- package/src/sync/streaming/mySegmentsV2utils.ts +77 -0
- package/src/sync/streaming/pushManager.ts +145 -42
- package/src/sync/streaming/types.ts +14 -22
- package/src/sync/submitters/metricsSyncTask.ts +1 -1
- package/src/sync/submitters/submitterSyncTask.ts +2 -1
- package/src/sync/syncManagerFromFile.ts +13 -0
- package/src/sync/syncManagerFromObject.ts +12 -0
- package/src/sync/syncManagerOffline.ts +3 -3
- package/src/sync/syncManagerOnline.ts +19 -5
- package/src/sync/syncTask.ts +1 -1
- package/src/sync/types.ts +3 -1
- package/src/trackers/impressionObserver/ImpressionObserver.ts +4 -6
- package/src/trackers/impressionObserver/buildKey.ts +2 -16
- package/src/trackers/impressionObserver/impressionObserverCS.ts +2 -2
- package/src/trackers/impressionObserver/impressionObserverSS.ts +3 -3
- package/src/types.ts +16 -2
- package/src/utils/constants/index.ts +6 -1
- package/src/utils/decompress/index.ts +429 -0
- package/src/utils/lang/index.ts +1 -1
- package/src/utils/murmur3/{commons.ts → common.ts} +1 -5
- package/src/utils/murmur3/murmur3.ts +5 -5
- package/src/utils/murmur3/murmur3_128.ts +7 -180
- package/src/utils/murmur3/murmur3_128_x86.ts +188 -0
- package/src/utils/murmur3/murmur3_64.ts +36 -0
- package/src/utils/murmur3/utfx.ts +92 -110
- package/src/utils/promise/wrapper.ts +12 -9
- package/src/utils/settingsValidation/index.ts +8 -4
- package/src/utils/settingsValidation/localhost/index.ts +19 -0
- package/src/utils/settingsValidation/splitFilters.ts +0 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +21 -8
- package/src/utils/settingsValidation/types.ts +2 -11
- package/src/utils/settingsValidation/url.ts +1 -1
- package/types/evaluator/matchers/matcherTypes.d.ts +2 -2
- package/types/listeners/browser.d.ts +3 -3
- package/types/listeners/node.d.ts +3 -2
- package/types/logger/constants.d.ts +2 -0
- package/types/sdkFactory/types.d.ts +4 -5
- package/types/services/types.d.ts +4 -0
- package/types/storages/inLocalStorage/index.d.ts +2 -2
- package/types/storages/inMemory/InMemoryStorage.d.ts +3 -0
- package/types/storages/inMemory/InMemoryStorageCS.d.ts +3 -0
- package/types/storages/inRedis/index.d.ts +2 -2
- package/types/storages/pluggable/index.d.ts +2 -2
- package/types/storages/types.d.ts +15 -15
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -7
- package/types/sync/offline/splitsParser/splitsParserFromSettings.d.ts +1 -5
- package/types/sync/polling/types.d.ts +2 -1
- package/types/sync/streaming/AuthClient/indexV1.d.ts +12 -0
- package/types/sync/streaming/AuthClient/indexV2.d.ts +8 -0
- package/types/sync/streaming/AuthClient/types.d.ts +2 -0
- package/types/sync/streaming/SSEClient/index.d.ts +9 -12
- package/types/sync/streaming/SSEClient/types.d.ts +0 -1
- package/types/sync/streaming/SSEHandler/NotificationParser.d.ts +3 -2
- package/types/sync/streaming/SSEHandler/types.d.ts +30 -2
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +4 -3
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +2 -1
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +3 -2
- package/types/sync/streaming/UpdateWorkers/types.d.ts +1 -1
- package/types/sync/streaming/constants.d.ts +3 -1
- package/types/sync/streaming/mySegmentsV2utils.d.ts +27 -0
- package/types/sync/streaming/pushManagerNoUsers.d.ts +13 -0
- package/types/sync/streaming/types.d.ts +9 -5
- package/types/sync/submitters/submitterSyncTask.d.ts +1 -1
- package/types/sync/syncManagerFromFile.d.ts +2 -0
- package/types/sync/syncManagerFromObject.d.ts +2 -0
- package/types/sync/syncManagerOffline.d.ts +1 -1
- package/types/sync/syncTask.d.ts +1 -1
- package/types/sync/types.d.ts +2 -0
- package/types/trackers/impressionObserver/ImpressionObserver.d.ts +2 -2
- package/types/trackers/impressionObserver/buildKey.d.ts +1 -1
- package/types/trackers/impressionObserver/impressionObserverCS.d.ts +2 -2
- package/types/trackers/impressionObserver/impressionObserverSS.d.ts +2 -2
- package/types/types.d.ts +16 -2
- package/types/utils/constants/index.d.ts +5 -1
- package/types/utils/decompress/index.d.ts +16 -0
- package/types/utils/lang/index.d.ts +1 -1
- package/types/utils/murmur3/common.d.ts +12 -0
- package/types/utils/murmur3/murmur3.d.ts +2 -2
- package/types/utils/murmur3/murmur3_128.d.ts +5 -0
- package/types/utils/murmur3/murmur3_128_x86.d.ts +7 -0
- package/types/utils/murmur3/murmur3_64.d.ts +10 -0
- package/types/utils/murmur3/utfx.d.ts +24 -6
- package/types/utils/settingsValidation/index.d.ts +3 -2
- package/types/utils/settingsValidation/localhost/index.d.ts +9 -0
- package/types/utils/settingsValidation/storage/storageCS.d.ts +7 -1
- package/types/utils/settingsValidation/types.d.ts +2 -10
- package/cjs/sync/streaming/pushManagerCS.js +0 -178
- package/cjs/sync/streaming/pushManagerSS.js +0 -128
- package/esm/sync/streaming/pushManagerCS.js +0 -174
- package/esm/sync/streaming/pushManagerSS.js +0 -124
- package/src/sync/streaming/pushManagerCS.ts +0 -237
- package/src/sync/streaming/pushManagerSS.ts +0 -177
|
@@ -8,7 +8,6 @@ import { isString, endsWith, find, forOwn, uniq, } from '../../../utils/lang';
|
|
|
8
8
|
import parseCondition from './parseCondition';
|
|
9
9
|
var logPrefix = 'sync:offline:splits-fetcher: ';
|
|
10
10
|
var DEFAULT_FILENAME = '.split';
|
|
11
|
-
var previousMock = 'NO_MOCK_LOADED';
|
|
12
11
|
function configFilesPath(configFilePath) {
|
|
13
12
|
if (configFilePath === DEFAULT_FILENAME || !isString(configFilePath)) {
|
|
14
13
|
var root = process.env.HOME;
|
|
@@ -25,81 +24,6 @@ function configFilesPath(configFilePath) {
|
|
|
25
24
|
throw new Error("Split configuration not found in " + configFilePath + " - Please review your Split file location.");
|
|
26
25
|
return configFilePath;
|
|
27
26
|
}
|
|
28
|
-
// Parse `.split` configuration file and return a map of "Split Objects"
|
|
29
|
-
function readSplitConfigFile(log, filePath) {
|
|
30
|
-
var SPLIT_POSITION = 0;
|
|
31
|
-
var TREATMENT_POSITION = 1;
|
|
32
|
-
var data;
|
|
33
|
-
try {
|
|
34
|
-
data = fs.readFileSync(filePath, 'utf-8');
|
|
35
|
-
}
|
|
36
|
-
catch (e) {
|
|
37
|
-
log.error(e.message);
|
|
38
|
-
return {};
|
|
39
|
-
}
|
|
40
|
-
if (data === previousMock)
|
|
41
|
-
return false;
|
|
42
|
-
previousMock = data;
|
|
43
|
-
var splitObjects = data.split(/\r?\n/).reduce(function (accum, line, index) {
|
|
44
|
-
var tuple = line.trim();
|
|
45
|
-
if (tuple === '' || tuple.charAt(0) === '#') {
|
|
46
|
-
log.debug(logPrefix + ("Ignoring empty line or comment at #" + index));
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
tuple = tuple.split(/\s+/);
|
|
50
|
-
if (tuple.length !== 2) {
|
|
51
|
-
log.debug(logPrefix + ("Ignoring line since it does not have exactly two columns #" + index));
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
var splitName = tuple[SPLIT_POSITION];
|
|
55
|
-
var condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] });
|
|
56
|
-
accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' };
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return accum;
|
|
60
|
-
}, {});
|
|
61
|
-
return splitObjects;
|
|
62
|
-
}
|
|
63
|
-
// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects"
|
|
64
|
-
function readYAMLConfigFile(log, filePath) {
|
|
65
|
-
var data = '';
|
|
66
|
-
var yamldoc = null;
|
|
67
|
-
try {
|
|
68
|
-
data = fs.readFileSync(filePath, 'utf8');
|
|
69
|
-
if (data === previousMock)
|
|
70
|
-
return false;
|
|
71
|
-
previousMock = data;
|
|
72
|
-
yamldoc = yaml.safeLoad(data);
|
|
73
|
-
}
|
|
74
|
-
catch (e) {
|
|
75
|
-
log.error(e);
|
|
76
|
-
return {};
|
|
77
|
-
}
|
|
78
|
-
// Each entry will be mapped to a condition, but we'll also keep the configurations map.
|
|
79
|
-
var mocksData = yamldoc.reduce(function (accum, splitEntry) {
|
|
80
|
-
var splitName = Object.keys(splitEntry)[0];
|
|
81
|
-
if (!splitName || !isString(splitEntry[splitName].treatment))
|
|
82
|
-
log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.');
|
|
83
|
-
var mockData = splitEntry[splitName];
|
|
84
|
-
// "Template" for each split accumulated data
|
|
85
|
-
if (!accum[splitName]) {
|
|
86
|
-
accum[splitName] = {
|
|
87
|
-
configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost'
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
// Assign the config if there is one on the mock
|
|
91
|
-
if (mockData.config)
|
|
92
|
-
accum[splitName].configurations[mockData.treatment] = mockData.config;
|
|
93
|
-
// Parse the condition from the entry.
|
|
94
|
-
var condition = parseCondition(mockData);
|
|
95
|
-
accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition);
|
|
96
|
-
// Also keep track of the treatments, will be useful for manager functionality.
|
|
97
|
-
accum[splitName].treatments.push(mockData.treatment);
|
|
98
|
-
return accum;
|
|
99
|
-
}, {});
|
|
100
|
-
arrangeConditions(mocksData);
|
|
101
|
-
return mocksData;
|
|
102
|
-
}
|
|
103
27
|
// This function is not pure nor meant to be. Here we apply modifications to cover
|
|
104
28
|
// for behaviour that's ensured by the BE.
|
|
105
29
|
function arrangeConditions(mocksData) {
|
|
@@ -127,18 +51,96 @@ function arrangeConditions(mocksData) {
|
|
|
127
51
|
delete data.treatments;
|
|
128
52
|
});
|
|
129
53
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
54
|
+
export function splitsParserFromFileFactory() {
|
|
55
|
+
var previousMock = 'NO_MOCK_LOADED';
|
|
56
|
+
// Parse `.split` configuration file and return a map of "Split Objects"
|
|
57
|
+
function readSplitConfigFile(log, filePath) {
|
|
58
|
+
var SPLIT_POSITION = 0;
|
|
59
|
+
var TREATMENT_POSITION = 1;
|
|
60
|
+
var data;
|
|
61
|
+
try {
|
|
62
|
+
data = fs.readFileSync(filePath, 'utf-8');
|
|
63
|
+
}
|
|
64
|
+
catch (e) {
|
|
65
|
+
log.error(e.message);
|
|
66
|
+
return {};
|
|
67
|
+
}
|
|
68
|
+
if (data === previousMock)
|
|
69
|
+
return false;
|
|
70
|
+
previousMock = data;
|
|
71
|
+
var splitObjects = data.split(/\r?\n/).reduce(function (accum, line, index) {
|
|
72
|
+
var tuple = line.trim();
|
|
73
|
+
if (tuple === '' || tuple.charAt(0) === '#') {
|
|
74
|
+
log.debug(logPrefix + ("Ignoring empty line or comment at #" + index));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
tuple = tuple.split(/\s+/);
|
|
78
|
+
if (tuple.length !== 2) {
|
|
79
|
+
log.debug(logPrefix + ("Ignoring line since it does not have exactly two columns #" + index));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
var splitName = tuple[SPLIT_POSITION];
|
|
83
|
+
var condition = parseCondition({ treatment: tuple[TREATMENT_POSITION] });
|
|
84
|
+
accum[splitName] = { conditions: [condition], configurations: {}, trafficTypeName: 'localhost' };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return accum;
|
|
88
|
+
}, {});
|
|
89
|
+
return splitObjects;
|
|
139
90
|
}
|
|
140
|
-
|
|
141
|
-
|
|
91
|
+
// Parse `.yml` or `.yaml` configuration files and return a map of "Split Objects"
|
|
92
|
+
function readYAMLConfigFile(log, filePath) {
|
|
93
|
+
var data = '';
|
|
94
|
+
var yamldoc = null;
|
|
95
|
+
try {
|
|
96
|
+
data = fs.readFileSync(filePath, 'utf8');
|
|
97
|
+
if (data === previousMock)
|
|
98
|
+
return false;
|
|
99
|
+
previousMock = data;
|
|
100
|
+
yamldoc = yaml.safeLoad(data);
|
|
101
|
+
}
|
|
102
|
+
catch (e) {
|
|
103
|
+
log.error(e);
|
|
104
|
+
return {};
|
|
105
|
+
}
|
|
106
|
+
// Each entry will be mapped to a condition, but we'll also keep the configurations map.
|
|
107
|
+
var mocksData = yamldoc.reduce(function (accum, splitEntry) {
|
|
108
|
+
var splitName = Object.keys(splitEntry)[0];
|
|
109
|
+
if (!splitName || !isString(splitEntry[splitName].treatment))
|
|
110
|
+
log.error(logPrefix + 'Ignoring entry on YAML since the format is incorrect.');
|
|
111
|
+
var mockData = splitEntry[splitName];
|
|
112
|
+
// "Template" for each split accumulated data
|
|
113
|
+
if (!accum[splitName]) {
|
|
114
|
+
accum[splitName] = {
|
|
115
|
+
configurations: {}, conditions: [], treatments: [], trafficTypeName: 'localhost'
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
// Assign the config if there is one on the mock
|
|
119
|
+
if (mockData.config)
|
|
120
|
+
accum[splitName].configurations[mockData.treatment] = mockData.config;
|
|
121
|
+
// Parse the condition from the entry.
|
|
122
|
+
var condition = parseCondition(mockData);
|
|
123
|
+
accum[splitName].conditions[condition.conditionType === 'ROLLOUT' ? 'push' : 'unshift'](condition);
|
|
124
|
+
// Also keep track of the treatments, will be useful for manager functionality.
|
|
125
|
+
accum[splitName].treatments.push(mockData.treatment);
|
|
126
|
+
return accum;
|
|
127
|
+
}, {});
|
|
128
|
+
arrangeConditions(mocksData);
|
|
129
|
+
return mocksData;
|
|
142
130
|
}
|
|
143
|
-
|
|
131
|
+
// Load the content of a configuration file into an Object
|
|
132
|
+
return function splitsParserFromFile(_a) {
|
|
133
|
+
var features = _a.features, log = _a.log;
|
|
134
|
+
var filePath = configFilesPath(features);
|
|
135
|
+
var mockData;
|
|
136
|
+
// If we have a filePath, it means the extension is correct, choose the parser.
|
|
137
|
+
if (endsWith(filePath, '.split')) {
|
|
138
|
+
log.warn(logPrefix + '.split mocks will be deprecated soon in favor of YAML files, which provide more targeting power. Take a look in our documentation.');
|
|
139
|
+
mockData = readSplitConfigFile(log, filePath);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
mockData = readYAMLConfigFile(log, filePath);
|
|
143
|
+
}
|
|
144
|
+
return mockData;
|
|
145
|
+
};
|
|
144
146
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { isObject, forOwn } from '../../../utils/lang';
|
|
2
2
|
import parseCondition from './parseCondition';
|
|
3
|
-
var previousMock = { 'emptyMock': '1' };
|
|
4
3
|
function hasTreatmentChanged(prev, curr) {
|
|
5
4
|
if (typeof prev !== typeof curr)
|
|
6
5
|
return true;
|
|
@@ -11,46 +10,49 @@ function hasTreatmentChanged(prev, curr) {
|
|
|
11
10
|
return prev.treatment !== curr.treatment || prev.config !== curr.config;
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
|
-
function
|
|
15
|
-
var
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
return names.some(function (name) {
|
|
22
|
-
var newSplit = !previousMock[name];
|
|
23
|
-
var newTreatment = hasTreatmentChanged(previousMock[name], currentData[name]);
|
|
24
|
-
var changed = newSplit || newTreatment;
|
|
25
|
-
if (changed)
|
|
13
|
+
export function splitsParserFromSettingsFactory() {
|
|
14
|
+
var previousMock = { 'emptyMock': '1' };
|
|
15
|
+
function mockUpdated(currentData) {
|
|
16
|
+
var names = Object.keys(currentData);
|
|
17
|
+
// Different amount of items
|
|
18
|
+
if (names.length !== Object.keys(previousMock).length) {
|
|
26
19
|
previousMock = currentData;
|
|
27
|
-
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
32
|
-
* @param features validated object with mocked features mapping.
|
|
33
|
-
*/
|
|
34
|
-
export default function splitsParserFromSettings(settings) {
|
|
35
|
-
var features = settings.features || {};
|
|
36
|
-
if (!mockUpdated(features))
|
|
37
|
-
return false;
|
|
38
|
-
var splitObjects = {};
|
|
39
|
-
forOwn(features, function (data, splitName) {
|
|
40
|
-
var treatment = data;
|
|
41
|
-
var config = null;
|
|
42
|
-
if (isObject(data)) {
|
|
43
|
-
treatment = data.treatment;
|
|
44
|
-
config = data.config || config;
|
|
20
|
+
return true;
|
|
45
21
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
22
|
+
return names.some(function (name) {
|
|
23
|
+
var newSplit = !previousMock[name];
|
|
24
|
+
var newTreatment = hasTreatmentChanged(previousMock[name], currentData[name]);
|
|
25
|
+
var changed = newSplit || newTreatment;
|
|
26
|
+
if (changed)
|
|
27
|
+
previousMock = currentData;
|
|
28
|
+
return changed;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
*
|
|
33
|
+
* @param settings validated object with mocked features mapping.
|
|
34
|
+
*/
|
|
35
|
+
return function splitsParserFromSettings(settings) {
|
|
36
|
+
var features = settings.features || {};
|
|
37
|
+
if (!mockUpdated(features))
|
|
38
|
+
return false;
|
|
39
|
+
var splitObjects = {};
|
|
40
|
+
forOwn(features, function (data, splitName) {
|
|
41
|
+
var treatment = data;
|
|
42
|
+
var config = null;
|
|
43
|
+
if (isObject(data)) {
|
|
44
|
+
treatment = data.treatment;
|
|
45
|
+
config = data.config || config;
|
|
46
|
+
}
|
|
47
|
+
var configurations = {};
|
|
48
|
+
if (config !== null)
|
|
49
|
+
configurations[treatment] = config;
|
|
50
|
+
splitObjects[splitName] = {
|
|
51
|
+
trafficTypeName: 'localhost',
|
|
52
|
+
conditions: [parseCondition({ treatment: treatment })],
|
|
53
|
+
configurations: configurations
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
return splitObjects;
|
|
57
|
+
};
|
|
56
58
|
}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { forOwn } from '../../../utils/lang';
|
|
2
2
|
import syncTaskFactory from '../../syncTask';
|
|
3
3
|
import { CONTROL } from '../../../utils/constants';
|
|
4
|
-
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
|
|
4
|
+
import { SDK_SPLITS_ARRIVED, SDK_SEGMENTS_ARRIVED, SDK_SPLITS_CACHE_LOADED } from '../../../readiness/constants';
|
|
5
5
|
import { SYNC_OFFLINE_DATA, ERROR_SYNC_OFFLINE_LOADING } from '../../../logger/constants';
|
|
6
6
|
/**
|
|
7
7
|
* Offline equivalent of `splitChangesUpdaterFactory`
|
|
8
8
|
*/
|
|
9
9
|
export function fromObjectUpdaterFactory(splitsParser, storage, readiness, settings) {
|
|
10
|
-
var log = settings.log;
|
|
10
|
+
var log = settings.log, splitsCache = storage.splits;
|
|
11
|
+
var startingUp = true;
|
|
11
12
|
return function objectUpdater() {
|
|
12
13
|
var splits = [];
|
|
13
14
|
var loadError = null;
|
|
@@ -37,11 +38,20 @@ export function fromObjectUpdaterFactory(splitsParser, storage, readiness, setti
|
|
|
37
38
|
]);
|
|
38
39
|
});
|
|
39
40
|
return Promise.all([
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
splitsCache.clear(),
|
|
42
|
+
splitsCache.addSplits(splits)
|
|
42
43
|
]).then(function () {
|
|
43
44
|
readiness.splits.emit(SDK_SPLITS_ARRIVED);
|
|
44
|
-
|
|
45
|
+
if (startingUp) {
|
|
46
|
+
startingUp = false;
|
|
47
|
+
Promise.resolve(splitsCache.checkCache()).then(function (cacheReady) {
|
|
48
|
+
// Emits SDK_READY_FROM_CACHE
|
|
49
|
+
if (cacheReady)
|
|
50
|
+
readiness.splits.emit(SDK_SPLITS_CACHE_LOADED);
|
|
51
|
+
// Emits SDK_READY
|
|
52
|
+
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
45
55
|
return true;
|
|
46
56
|
});
|
|
47
57
|
}
|
|
@@ -12,14 +12,6 @@ function greedyFetch(fetchSegmentChanges, since, segmentName, noCache) {
|
|
|
12
12
|
return __spreadArrays([flatMe[0]], flatMe[1]);
|
|
13
13
|
});
|
|
14
14
|
}
|
|
15
|
-
})
|
|
16
|
-
.catch(function (err) {
|
|
17
|
-
// If the operation is forbidden it may be due to permissions, don't recover and propagate the error.
|
|
18
|
-
if (err.statusCode === 403)
|
|
19
|
-
throw err;
|
|
20
|
-
// if something goes wrong with the request to the server, we are going to
|
|
21
|
-
// stop requesting information till the next round of downloading
|
|
22
|
-
return [];
|
|
23
15
|
});
|
|
24
16
|
}
|
|
25
17
|
/**
|
|
@@ -20,19 +20,36 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, splitsCache, my
|
|
|
20
20
|
// mySegmentsPromise = tracker.start(tracker.TaskNames.MY_SEGMENTS_FETCH, startingUp ? metricCollectors : false, mySegmentsPromise);
|
|
21
21
|
}
|
|
22
22
|
// @TODO if allowing custom storages, handle async execution
|
|
23
|
-
function updateSegments(
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
function updateSegments(segmentsData) {
|
|
24
|
+
var shouldNotifyUpdate;
|
|
25
|
+
if (Array.isArray(segmentsData)) {
|
|
26
|
+
// Update the list of segment names available
|
|
27
|
+
shouldNotifyUpdate = mySegmentsCache.resetSegments(segmentsData);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Add/Delete the segment
|
|
31
|
+
var name_1 = segmentsData.name, add = segmentsData.add;
|
|
32
|
+
if (mySegmentsCache.isInSegment(name_1) !== add) {
|
|
33
|
+
shouldNotifyUpdate = true;
|
|
34
|
+
if (add)
|
|
35
|
+
mySegmentsCache.addToSegment(name_1);
|
|
36
|
+
else
|
|
37
|
+
mySegmentsCache.removeFromSegment(name_1);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
shouldNotifyUpdate = false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
26
43
|
// Notify update if required
|
|
27
44
|
if (splitsCache.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
|
|
28
45
|
readyOnAlreadyExistentState = false;
|
|
29
46
|
segmentsEventEmitter.emit(SDK_SEGMENTS_ARRIVED);
|
|
30
47
|
}
|
|
31
48
|
}
|
|
32
|
-
function _mySegmentsUpdater(retry,
|
|
33
|
-
var updaterPromise =
|
|
34
|
-
// If
|
|
35
|
-
new Promise(function (res) { updateSegments(
|
|
49
|
+
function _mySegmentsUpdater(retry, segmentsData, noCache) {
|
|
50
|
+
var updaterPromise = segmentsData ?
|
|
51
|
+
// If segmentsData is provided, there is no need to fetch mySegments
|
|
52
|
+
new Promise(function (res) { updateSegments(segmentsData); res(true); }) :
|
|
36
53
|
// If not provided, fetch mySegments
|
|
37
54
|
mySegmentsFetcher(noCache, _promiseDecorator).then(function (segments) {
|
|
38
55
|
// Only when we have downloaded segments completely, we should not keep retrying anymore
|
|
@@ -56,10 +73,13 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, splitsCache, my
|
|
|
56
73
|
* MySegments updater returns a promise that resolves with a `false` boolean value if it fails to fetch mySegments or synchronize them with the storage.
|
|
57
74
|
* Returned promise will not be rejected.
|
|
58
75
|
*
|
|
59
|
-
* @param {
|
|
76
|
+
* @param {SegmentsData | undefined} segmentsData it can be:
|
|
77
|
+
* (1) the list of mySegments names to sync in the storage,
|
|
78
|
+
* (2) an object with a segment name and action (true: add, or false: delete) to update the storage,
|
|
79
|
+
* (3) or `undefined`, for which the updater will fetch mySegments in order to sync the storage.
|
|
60
80
|
* @param {boolean | undefined} noCache true to revalidate data to fetch
|
|
61
81
|
*/
|
|
62
|
-
return function mySegmentsUpdater(
|
|
63
|
-
return _mySegmentsUpdater(0,
|
|
82
|
+
return function mySegmentsUpdater(segmentsData, noCache) {
|
|
83
|
+
return _mySegmentsUpdater(0, segmentsData, noCache);
|
|
64
84
|
};
|
|
65
85
|
}
|
|
@@ -78,15 +78,13 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
|
|
|
78
78
|
if (readiness)
|
|
79
79
|
readiness.segments.emit(SDK_SEGMENTS_ARRIVED);
|
|
80
80
|
}
|
|
81
|
-
// if at least one segment fetch fails, return false to indicate that there was some error (e.g., invalid json, HTTP error, etc)
|
|
82
|
-
if (shouldUpdateFlags.indexOf(-1) !== -1)
|
|
83
|
-
return false;
|
|
84
81
|
return true;
|
|
85
82
|
});
|
|
86
83
|
})
|
|
87
84
|
// Handles rejected promises at `segmentChangesFetcher`, `segments.getRegisteredSegments` and other segment storage operations.
|
|
88
85
|
.catch(function (error) {
|
|
89
|
-
if (error.statusCode === 403) {
|
|
86
|
+
if (error && error.statusCode === 403) {
|
|
87
|
+
// If the operation is forbidden, it may be due to permissions. Destroy the SDK instance.
|
|
90
88
|
// @TODO although factory status is destroyed, synchronization is not stopped
|
|
91
89
|
if (readiness)
|
|
92
90
|
readiness.destroy();
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
var VERSION = '1.1';
|
|
2
2
|
var CONTROL_CHANNEL_REGEX = /^control_/;
|
|
3
|
+
/**
|
|
4
|
+
* Build metadata headers for SSE connection.
|
|
5
|
+
*
|
|
6
|
+
* @param {ISettings} settings Validated settings.
|
|
7
|
+
* @returns {Record<string, string>} Headers object
|
|
8
|
+
*/
|
|
9
|
+
function buildSSEHeaders(settings) {
|
|
10
|
+
var headers = {
|
|
11
|
+
SplitSDKClientKey: settings.core.authorizationKey.slice(-4),
|
|
12
|
+
SplitSDKVersion: settings.version,
|
|
13
|
+
};
|
|
14
|
+
// ip and hostname are false if IPAddressesEnabled is false
|
|
15
|
+
var _a = settings.runtime, ip = _a.ip, hostname = _a.hostname;
|
|
16
|
+
if (ip)
|
|
17
|
+
headers['SplitSDKMachineIP'] = ip;
|
|
18
|
+
if (hostname)
|
|
19
|
+
headers['SplitSDKMachineName'] = hostname;
|
|
20
|
+
return headers;
|
|
21
|
+
}
|
|
3
22
|
/**
|
|
4
23
|
* Handles streaming connections with EventSource API
|
|
5
24
|
*/
|
|
@@ -7,18 +26,21 @@ var SSEClient = /** @class */ (function () {
|
|
|
7
26
|
/**
|
|
8
27
|
* SSEClient constructor.
|
|
9
28
|
*
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
12
|
-
* @
|
|
29
|
+
* @param settings Validated settings.
|
|
30
|
+
* @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
|
|
31
|
+
* @param getEventSource Function to get the EventSource constructor.
|
|
32
|
+
* @throws 'EventSource API is not available. ' if EventSource is not available.
|
|
13
33
|
*/
|
|
14
|
-
function SSEClient(
|
|
34
|
+
function SSEClient(settings, useHeaders, getEventSource) {
|
|
15
35
|
// @ts-expect-error
|
|
16
36
|
this.eventSource = getEventSource && getEventSource();
|
|
17
37
|
// if eventSource is not available, throw an exception
|
|
18
38
|
if (!this.eventSource)
|
|
19
39
|
throw new Error('EventSource API is not available. ');
|
|
20
|
-
this.streamingUrl =
|
|
21
|
-
|
|
40
|
+
this.streamingUrl = settings.urls.streaming + '/sse';
|
|
41
|
+
// @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
|
|
42
|
+
this.useHeaders = useHeaders;
|
|
43
|
+
this.headers = buildSSEHeaders(settings);
|
|
22
44
|
}
|
|
23
45
|
SSEClient.prototype.setEventHandler = function (handler) {
|
|
24
46
|
this.handler = handler;
|
|
@@ -27,21 +49,25 @@ var SSEClient = /** @class */ (function () {
|
|
|
27
49
|
* Open the connection with a given authToken
|
|
28
50
|
*
|
|
29
51
|
* @param {IAuthTokenPushEnabled} authToken
|
|
30
|
-
* @throws {TypeError} if `authToken` is undefined
|
|
52
|
+
* @throws {TypeError} Will throw an error if `authToken` is undefined
|
|
31
53
|
*/
|
|
32
54
|
SSEClient.prototype.open = function (authToken) {
|
|
33
55
|
this.close(); // it closes connection if previously opened
|
|
34
|
-
this.authToken = authToken;
|
|
35
56
|
var channelsQueryParam = Object.keys(authToken.channels).map(function (channel) {
|
|
36
57
|
var params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
|
|
37
58
|
return encodeURIComponent(params + channel);
|
|
38
59
|
}).join(',');
|
|
39
60
|
var url = this.streamingUrl + "?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
|
|
40
|
-
this.connection = new this.eventSource(
|
|
61
|
+
this.connection = new this.eventSource(
|
|
62
|
+
// For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
|
|
63
|
+
// because native EventSource implementations for browser doesn't support headers.
|
|
64
|
+
this.useHeaders ? url : url + ("&SplitSDKVersion=" + this.headers.SplitSDKVersion + "&SplitSDKClientKey=" + this.headers.SplitSDKClientKey),
|
|
65
|
+
// @ts-ignore. For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
|
|
66
|
+
this.useHeaders ? { headers: this.headers } : undefined);
|
|
41
67
|
if (this.handler) { // no need to check if SSEClient is used only by PushManager
|
|
42
|
-
this.connection.
|
|
43
|
-
this.connection.
|
|
44
|
-
this.connection.
|
|
68
|
+
this.connection.addEventListener('open', this.handler.handleOpen);
|
|
69
|
+
this.connection.addEventListener('message', this.handler.handleMessage);
|
|
70
|
+
this.connection.addEventListener('error', this.handler.handleError);
|
|
45
71
|
}
|
|
46
72
|
};
|
|
47
73
|
/** Close connection */
|
|
@@ -49,14 +75,6 @@ var SSEClient = /** @class */ (function () {
|
|
|
49
75
|
if (this.connection)
|
|
50
76
|
this.connection.close();
|
|
51
77
|
};
|
|
52
|
-
/**
|
|
53
|
-
* Re-open the connection with the last given authToken.
|
|
54
|
-
*
|
|
55
|
-
* @throws {TypeError} if `open` has not been previously called with an authToken
|
|
56
|
-
*/
|
|
57
|
-
SSEClient.prototype.reopen = function () {
|
|
58
|
-
this.open(this.authToken);
|
|
59
|
-
};
|
|
60
78
|
return SSEClient;
|
|
61
79
|
}());
|
|
62
80
|
export default SSEClient;
|
|
@@ -52,6 +52,13 @@ export default function notificationKeeperFactory(pushEmitter) {
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
handleControlEvent: function (controlType, channel, timestamp) {
|
|
55
|
+
/* STREAMING_RESET control event is handled by PushManager directly since it doesn't require
|
|
56
|
+
* tracking timestamp and state like OCCUPANCY or CONTROL. It also ignores previous
|
|
57
|
+
* OCCUPANCY and CONTROL notifications, and whether PUSH_SUBSYSTEM_DOWN has been emitted or not */
|
|
58
|
+
if (controlType === ControlType.STREAMING_RESET) {
|
|
59
|
+
pushEmitter.emit(controlType);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
55
62
|
for (var i = 0; i < channels.length; i++) {
|
|
56
63
|
var c = channels[i];
|
|
57
64
|
if (c.regex.test(channel)) {
|
|
@@ -19,10 +19,13 @@ export function errorParser(error) {
|
|
|
19
19
|
* Also assigns the type OCCUPANCY, if it corresponds, so that all supported messages (e.g., SPLIT_UPDATE, CONTROL) have a type.
|
|
20
20
|
*
|
|
21
21
|
* @param message
|
|
22
|
-
* @returns parsed notification message
|
|
22
|
+
* @returns parsed notification message or undefined if the given event data is falsy (e.g, '' or undefined).
|
|
23
|
+
* For example, the EventSource implementation of React-Native for iOS emits a message event with empty data for Ably keepalive comments.
|
|
23
24
|
* @throws {SyntaxError} if `message.data` or `JSON.parse(message.data).data` are invalid JSON strings
|
|
24
25
|
*/
|
|
25
26
|
export function messageParser(message) {
|
|
27
|
+
if (!message.data)
|
|
28
|
+
return;
|
|
26
29
|
var messageData = JSON.parse(message.data);
|
|
27
30
|
messageData.parsedData = JSON.parse(messageData.data);
|
|
28
31
|
// set the event type to OCCUPANCY, to handle all events uniformely
|
|
@@ -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, MY_SEGMENTS_UPDATE, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants';
|
|
3
|
+
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE, MY_SEGMENTS_UPDATE_V2, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE } from '../constants';
|
|
4
4
|
import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
|
|
5
5
|
function isRetryableError(error) {
|
|
6
6
|
if (error.parsedData && error.parsedData.code) {
|
|
@@ -36,7 +36,7 @@ export default function SSEHandlerFactory(log, pushEmitter) {
|
|
|
36
36
|
catch (err) {
|
|
37
37
|
log.warn(STREAMING_PARSING_ERROR_FAILS, [err]);
|
|
38
38
|
}
|
|
39
|
-
var errorMessage = errorWithParsedData.parsedData && errorWithParsedData.parsedData.message;
|
|
39
|
+
var errorMessage = (errorWithParsedData.parsedData && errorWithParsedData.parsedData.message) || errorWithParsedData.message;
|
|
40
40
|
log.error(ERROR_STREAMING_SSE, [errorMessage]);
|
|
41
41
|
if (isRetryableError(errorWithParsedData)) {
|
|
42
42
|
pushEmitter.emit(PUSH_RETRYABLE_ERROR);
|
|
@@ -50,6 +50,8 @@ export default function SSEHandlerFactory(log, pushEmitter) {
|
|
|
50
50
|
var messageWithParsedData;
|
|
51
51
|
try {
|
|
52
52
|
messageWithParsedData = messageParser(message);
|
|
53
|
+
if (!messageWithParsedData)
|
|
54
|
+
return; // Messages with empty data are ignored
|
|
53
55
|
}
|
|
54
56
|
catch (err) {
|
|
55
57
|
log.warn(STREAMING_PARSING_MESSAGE_FAILS, [err]);
|
|
@@ -58,21 +60,18 @@ export default function SSEHandlerFactory(log, pushEmitter) {
|
|
|
58
60
|
var parsedData = messageWithParsedData.parsedData, data = messageWithParsedData.data, channel = messageWithParsedData.channel, timestamp = messageWithParsedData.timestamp;
|
|
59
61
|
log.debug(STREAMING_NEW_MESSAGE, [data]);
|
|
60
62
|
// we only handle update events if streaming is up.
|
|
61
|
-
if (!notificationKeeper.isStreamingUp() &&
|
|
63
|
+
if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
|
|
62
64
|
return;
|
|
63
65
|
switch (parsedData.type) {
|
|
64
66
|
/* update events */
|
|
65
67
|
case SPLIT_UPDATE:
|
|
66
|
-
pushEmitter.emit(SPLIT_UPDATE, parsedData.changeNumber);
|
|
67
|
-
break;
|
|
68
68
|
case SEGMENT_UPDATE:
|
|
69
|
-
|
|
69
|
+
case MY_SEGMENTS_UPDATE_V2:
|
|
70
|
+
case SPLIT_KILL:
|
|
71
|
+
pushEmitter.emit(parsedData.type, parsedData);
|
|
70
72
|
break;
|
|
71
73
|
case MY_SEGMENTS_UPDATE:
|
|
72
|
-
pushEmitter.emit(
|
|
73
|
-
break;
|
|
74
|
-
case SPLIT_KILL:
|
|
75
|
-
pushEmitter.emit(SPLIT_KILL, parsedData.changeNumber, parsedData.splitName, parsedData.defaultTreatment);
|
|
74
|
+
pushEmitter.emit(parsedData.type, parsedData, channel);
|
|
76
75
|
break;
|
|
77
76
|
/* occupancy & control events, handled by NotificationManagerKeeper */
|
|
78
77
|
case OCCUPANCY:
|
|
@@ -1 +1,13 @@
|
|
|
1
|
-
export
|
|
1
|
+
export var Compression;
|
|
2
|
+
(function (Compression) {
|
|
3
|
+
Compression[Compression["None"] = 0] = "None";
|
|
4
|
+
Compression[Compression["Gzip"] = 1] = "Gzip";
|
|
5
|
+
Compression[Compression["Zlib"] = 2] = "Zlib";
|
|
6
|
+
})(Compression || (Compression = {}));
|
|
7
|
+
export var UpdateStrategy;
|
|
8
|
+
(function (UpdateStrategy) {
|
|
9
|
+
UpdateStrategy[UpdateStrategy["UnboundedFetchRequest"] = 0] = "UnboundedFetchRequest";
|
|
10
|
+
UpdateStrategy[UpdateStrategy["BoundedFetchRequest"] = 1] = "BoundedFetchRequest";
|
|
11
|
+
UpdateStrategy[UpdateStrategy["KeyList"] = 2] = "KeyList";
|
|
12
|
+
UpdateStrategy[UpdateStrategy["SegmentRemoval"] = 3] = "SegmentRemoval";
|
|
13
|
+
})(UpdateStrategy || (UpdateStrategy = {}));
|