@splitsoftware/splitio-commons 0.1.1-canary.9 → 0.1.1-rc.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/evaluator/matchers/matcherTypes.js +4 -4
- package/cjs/evaluator/matchersTransform/index.js +11 -11
- package/cjs/evaluator/value/sanitize.js +6 -6
- package/cjs/listeners/browser.js +1 -2
- package/cjs/listeners/node.js +0 -3
- package/cjs/logger/constants.js +3 -1
- package/cjs/logger/messages/error.js +3 -2
- package/cjs/logger/messages/info.js +2 -2
- package/cjs/logger/messages/warn.js +2 -1
- package/cjs/readiness/readinessManager.js +10 -7
- package/cjs/sdkFactory/index.js +1 -4
- package/cjs/services/splitApi.js +1 -1
- package/cjs/services/splitHttpClient.js +5 -4
- package/cjs/storages/AbstractSplitsCacheSync.js +1 -1
- package/cjs/storages/inLocalStorage/index.js +5 -2
- package/cjs/storages/inMemory/InMemoryStorage.js +2 -0
- package/cjs/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/cjs/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/cjs/storages/inRedis/index.js +5 -2
- package/cjs/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/cjs/storages/pluggable/inMemoryWrapper.js +6 -7
- package/cjs/storages/pluggable/index.js +5 -2
- package/cjs/storages/pluggable/wrapperAdapter.js +0 -1
- package/cjs/sync/offline/splitsParser/splitsParserFromFile.js +92 -89
- package/cjs/sync/offline/splitsParser/splitsParserFromSettings.js +45 -42
- package/cjs/sync/offline/syncTasks/fromObjectSyncTask.js +14 -4
- package/cjs/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/cjs/sync/streaming/SSEClient/index.js +0 -11
- package/cjs/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/cjs/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/cjs/sync/streaming/SSEHandler/index.js +8 -9
- package/cjs/sync/streaming/SSEHandler/types.js +14 -0
- package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/cjs/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/cjs/sync/streaming/constants.js +3 -1
- package/cjs/sync/streaming/mySegmentsV2utils.js +75 -0
- package/cjs/sync/streaming/pushManager.js +141 -40
- package/cjs/sync/submitters/metricsSyncTask.js +1 -1
- package/cjs/sync/submitters/submitterSyncTask.js +2 -2
- package/cjs/sync/syncManagerFromFile.js +15 -0
- package/cjs/sync/syncManagerFromObject.js +14 -0
- package/cjs/sync/syncManagerOffline.js +3 -3
- package/cjs/sync/syncManagerOnline.js +5 -3
- package/cjs/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/cjs/trackers/impressionObserver/buildKey.js +3 -9
- package/cjs/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/cjs/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/cjs/utils/constants/index.js +4 -1
- package/cjs/utils/decompress/index.js +427 -0
- package/cjs/utils/murmur3/{commons.js → common.js} +2 -6
- package/cjs/utils/murmur3/murmur3.js +11 -12
- package/cjs/utils/murmur3/murmur3_128.js +7 -142
- package/cjs/utils/murmur3/murmur3_128_x86.js +154 -0
- package/cjs/utils/murmur3/murmur3_64.js +36 -0
- package/cjs/utils/murmur3/utfx.js +100 -106
- package/cjs/utils/promise/wrapper.js +14 -11
- package/cjs/utils/settingsValidation/index.js +5 -2
- package/cjs/utils/settingsValidation/localhost/index.js +20 -0
- package/cjs/utils/settingsValidation/splitFilters.js +0 -1
- package/cjs/utils/settingsValidation/storage/storageCS.js +18 -8
- package/cjs/utils/settingsValidation/url.js +1 -1
- package/esm/evaluator/matchers/matcherTypes.js +2 -2
- package/esm/evaluator/matchersTransform/index.js +12 -12
- package/esm/evaluator/value/sanitize.js +7 -7
- package/esm/listeners/browser.js +1 -2
- package/esm/listeners/node.js +0 -3
- package/esm/logger/constants.js +2 -0
- package/esm/logger/messages/error.js +3 -2
- package/esm/logger/messages/info.js +2 -2
- package/esm/logger/messages/warn.js +2 -1
- package/esm/readiness/readinessManager.js +10 -7
- package/esm/sdkFactory/index.js +1 -4
- package/esm/services/splitApi.js +1 -1
- package/esm/services/splitHttpClient.js +5 -4
- package/esm/storages/AbstractSplitsCacheSync.js +1 -1
- package/esm/storages/inLocalStorage/index.js +5 -2
- package/esm/storages/inMemory/InMemoryStorage.js +2 -0
- package/esm/storages/inMemory/InMemoryStorageCS.js +2 -0
- package/esm/storages/inRedis/SplitsCacheInRedis.js +6 -2
- package/esm/storages/inRedis/index.js +5 -2
- package/esm/storages/pluggable/SplitsCachePluggable.js +6 -2
- package/esm/storages/pluggable/inMemoryWrapper.js +6 -7
- package/esm/storages/pluggable/index.js +5 -2
- package/esm/storages/pluggable/wrapperAdapter.js +0 -1
- package/esm/sync/offline/splitsParser/splitsParserFromFile.js +90 -88
- package/esm/sync/offline/splitsParser/splitsParserFromSettings.js +43 -41
- package/esm/sync/offline/syncTasks/fromObjectSyncTask.js +15 -5
- package/esm/sync/polling/updaters/mySegmentsUpdater.js +30 -10
- package/esm/sync/streaming/SSEClient/index.js +0 -11
- package/esm/sync/streaming/SSEHandler/NotificationKeeper.js +7 -0
- package/esm/sync/streaming/SSEHandler/NotificationParser.js +4 -1
- package/esm/sync/streaming/SSEHandler/index.js +9 -10
- package/esm/sync/streaming/SSEHandler/types.js +13 -1
- package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +5 -5
- package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +2 -1
- package/esm/sync/streaming/UpdateWorkers/SplitsUpdateWorker.js +5 -3
- package/esm/sync/streaming/constants.js +2 -0
- package/esm/sync/streaming/mySegmentsV2utils.js +69 -0
- package/esm/sync/streaming/pushManager.js +143 -42
- package/esm/sync/submitters/metricsSyncTask.js +1 -1
- package/esm/sync/submitters/submitterSyncTask.js +2 -2
- package/esm/sync/syncManagerFromFile.js +11 -0
- package/esm/sync/syncManagerFromObject.js +10 -0
- package/esm/sync/syncManagerOffline.js +3 -3
- package/esm/sync/syncManagerOnline.js +5 -3
- package/esm/trackers/impressionObserver/ImpressionObserver.js +0 -2
- package/esm/trackers/impressionObserver/buildKey.js +2 -9
- package/esm/trackers/impressionObserver/impressionObserverCS.js +2 -2
- package/esm/trackers/impressionObserver/impressionObserverSS.js +3 -3
- package/esm/utils/constants/index.js +3 -0
- package/esm/utils/decompress/index.js +424 -0
- package/esm/utils/murmur3/{commons.js → common.js} +1 -4
- package/esm/utils/murmur3/murmur3.js +1 -2
- package/esm/utils/murmur3/murmur3_128.js +7 -142
- package/esm/utils/murmur3/murmur3_128_x86.js +150 -0
- package/esm/utils/murmur3/murmur3_64.js +32 -0
- package/esm/utils/murmur3/utfx.js +96 -106
- package/esm/utils/promise/wrapper.js +14 -11
- package/esm/utils/settingsValidation/index.js +5 -2
- package/esm/utils/settingsValidation/localhost/index.js +16 -0
- package/esm/utils/settingsValidation/splitFilters.js +0 -1
- package/esm/utils/settingsValidation/storage/storageCS.js +16 -7
- package/esm/utils/settingsValidation/url.js +1 -1
- package/package.json +5 -5
- package/src/evaluator/matchers/matcherTypes.ts +2 -2
- package/src/evaluator/matchersTransform/index.ts +12 -12
- package/src/evaluator/value/sanitize.ts +7 -7
- package/src/listeners/browser.ts +1 -1
- package/src/listeners/node.ts +1 -2
- package/src/logger/constants.ts +2 -0
- package/src/logger/messages/error.ts +3 -2
- package/src/logger/messages/info.ts +2 -2
- package/src/logger/messages/warn.ts +3 -1
- package/src/readiness/readinessManager.ts +9 -7
- package/src/sdkFactory/index.ts +1 -3
- package/src/sdkFactory/types.ts +3 -3
- package/src/services/splitApi.ts +2 -3
- package/src/services/splitHttpClient.ts +6 -5
- package/src/services/types.ts +5 -5
- package/src/storages/AbstractSplitsCacheSync.ts +1 -1
- package/src/storages/inLocalStorage/index.ts +8 -4
- package/src/storages/inMemory/InMemoryStorage.ts +3 -0
- package/src/storages/inMemory/InMemoryStorageCS.ts +3 -0
- package/src/storages/inRedis/SplitsCacheInRedis.ts +3 -1
- package/src/storages/inRedis/index.ts +8 -4
- package/src/storages/pluggable/SplitsCachePluggable.ts +3 -1
- package/src/storages/pluggable/inMemoryWrapper.ts +6 -7
- package/src/storages/pluggable/index.ts +8 -4
- package/src/storages/pluggable/wrapperAdapter.ts +0 -1
- package/src/storages/types.ts +18 -15
- package/src/sync/offline/splitsParser/splitsParserFromFile.ts +110 -105
- package/src/sync/offline/splitsParser/splitsParserFromSettings.ts +45 -41
- package/src/sync/offline/syncTasks/fromObjectSyncTask.ts +15 -5
- package/src/sync/polling/types.ts +2 -1
- package/src/sync/polling/updaters/mySegmentsUpdater.ts +28 -10
- package/src/sync/streaming/AuthClient/types.ts +3 -0
- package/src/sync/streaming/SSEClient/index.ts +1 -15
- package/src/sync/streaming/SSEClient/types.ts +0 -1
- package/src/sync/streaming/SSEHandler/NotificationKeeper.ts +8 -0
- package/src/sync/streaming/SSEHandler/NotificationParser.ts +4 -2
- package/src/sync/streaming/SSEHandler/index.ts +11 -20
- package/src/sync/streaming/SSEHandler/types.ts +37 -3
- package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +7 -6
- package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +2 -1
- package/src/sync/streaming/UpdateWorkers/SplitsUpdateWorker.ts +4 -3
- package/src/sync/streaming/UpdateWorkers/types.ts +1 -1
- package/src/sync/streaming/constants.ts +2 -0
- package/src/sync/streaming/mySegmentsV2utils.ts +77 -0
- package/src/sync/streaming/pushManager.ts +139 -42
- package/src/sync/streaming/types.ts +14 -22
- package/src/sync/submitters/metricsSyncTask.ts +1 -1
- package/src/sync/submitters/submitterSyncTask.ts +2 -1
- package/src/sync/syncManagerFromFile.ts +13 -0
- package/src/sync/syncManagerFromObject.ts +12 -0
- package/src/sync/syncManagerOffline.ts +3 -3
- package/src/sync/syncManagerOnline.ts +6 -3
- package/src/trackers/impressionObserver/ImpressionObserver.ts +4 -6
- package/src/trackers/impressionObserver/buildKey.ts +2 -16
- package/src/trackers/impressionObserver/impressionObserverCS.ts +2 -2
- package/src/trackers/impressionObserver/impressionObserverSS.ts +3 -3
- package/src/types.ts +16 -2
- package/src/utils/constants/index.ts +6 -1
- package/src/utils/decompress/index.ts +429 -0
- package/src/utils/murmur3/{commons.ts → common.ts} +1 -5
- package/src/utils/murmur3/murmur3.ts +5 -5
- package/src/utils/murmur3/murmur3_128.ts +7 -180
- package/src/utils/murmur3/murmur3_128_x86.ts +188 -0
- package/src/utils/murmur3/murmur3_64.ts +36 -0
- package/src/utils/murmur3/utfx.ts +92 -110
- package/src/utils/promise/wrapper.ts +12 -9
- package/src/utils/settingsValidation/index.ts +8 -4
- package/src/utils/settingsValidation/localhost/index.ts +19 -0
- package/src/utils/settingsValidation/splitFilters.ts +0 -1
- package/src/utils/settingsValidation/storage/storageCS.ts +21 -8
- package/src/utils/settingsValidation/types.ts +2 -11
- package/src/utils/settingsValidation/url.ts +1 -1
- package/types/evaluator/matchers/matcherTypes.d.ts +2 -2
- package/types/listeners/browser.d.ts +1 -0
- package/types/listeners/node.d.ts +0 -1
- package/types/logger/constants.d.ts +2 -0
- package/types/sdkFactory/types.d.ts +3 -3
- package/types/services/types.d.ts +1 -0
- package/types/storages/inLocalStorage/index.d.ts +2 -2
- package/types/storages/inMemory/InMemoryStorage.d.ts +3 -0
- package/types/storages/inMemory/InMemoryStorageCS.d.ts +3 -0
- package/types/storages/inRedis/index.d.ts +2 -2
- package/types/storages/pluggable/index.d.ts +2 -2
- package/types/storages/types.d.ts +15 -15
- package/types/sync/offline/splitsParser/splitsParserFromFile.d.ts +2 -7
- package/types/sync/offline/splitsParser/splitsParserFromSettings.d.ts +1 -5
- package/types/sync/polling/types.d.ts +2 -1
- package/types/sync/streaming/AuthClient/indexV1.d.ts +12 -0
- package/types/sync/streaming/AuthClient/indexV2.d.ts +8 -0
- package/types/sync/streaming/AuthClient/types.d.ts +2 -0
- package/types/sync/streaming/SSEClient/index.d.ts +1 -9
- package/types/sync/streaming/SSEClient/types.d.ts +0 -1
- package/types/sync/streaming/SSEHandler/NotificationParser.d.ts +3 -2
- package/types/sync/streaming/SSEHandler/types.d.ts +30 -2
- package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +4 -3
- package/types/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.d.ts +2 -1
- package/types/sync/streaming/UpdateWorkers/SplitsUpdateWorker.d.ts +3 -2
- package/types/sync/streaming/UpdateWorkers/types.d.ts +1 -1
- package/types/sync/streaming/constants.d.ts +3 -1
- package/types/sync/streaming/mySegmentsV2utils.d.ts +27 -0
- package/types/sync/streaming/pushManagerNoUsers.d.ts +13 -0
- package/types/sync/streaming/types.d.ts +9 -5
- package/types/sync/submitters/submitterSyncTask.d.ts +1 -1
- package/types/sync/syncManagerFromFile.d.ts +2 -0
- package/types/sync/syncManagerFromObject.d.ts +2 -0
- package/types/sync/syncManagerOffline.d.ts +1 -1
- package/types/trackers/impressionObserver/ImpressionObserver.d.ts +2 -2
- package/types/trackers/impressionObserver/buildKey.d.ts +1 -1
- package/types/trackers/impressionObserver/impressionObserverCS.d.ts +2 -2
- package/types/trackers/impressionObserver/impressionObserverSS.d.ts +2 -2
- package/types/types.d.ts +16 -2
- package/types/utils/constants/index.d.ts +5 -1
- package/types/utils/decompress/index.d.ts +16 -0
- package/types/utils/murmur3/common.d.ts +12 -0
- package/types/utils/murmur3/murmur3.d.ts +2 -2
- package/types/utils/murmur3/murmur3_128.d.ts +5 -0
- package/types/utils/murmur3/murmur3_128_x86.d.ts +7 -0
- package/types/utils/murmur3/murmur3_64.d.ts +10 -0
- package/types/utils/murmur3/utfx.d.ts +24 -6
- package/types/utils/settingsValidation/index.d.ts +3 -2
- package/types/utils/settingsValidation/localhost/index.d.ts +9 -0
- package/types/utils/settingsValidation/storage/storageCS.d.ts +7 -1
- package/types/utils/settingsValidation/types.d.ts +2 -10
- package/cjs/sync/streaming/pushManagerCS.js +0 -179
- package/cjs/sync/streaming/pushManagerSS.js +0 -128
- package/esm/sync/streaming/pushManagerCS.js +0 -175
- package/esm/sync/streaming/pushManagerSS.js +0 -124
- package/src/sync/streaming/pushManagerCS.ts +0 -238
- package/src/sync/streaming/pushManagerSS.ts +0 -177
|
@@ -1,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
|
}
|
|
@@ -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
|
}
|
|
@@ -38,7 +38,6 @@ var SSEClient = /** @class */ (function () {
|
|
|
38
38
|
if (!this.eventSource)
|
|
39
39
|
throw new Error('EventSource API is not available. ');
|
|
40
40
|
this.streamingUrl = settings.urls.streaming + '/sse';
|
|
41
|
-
this.reopen = this.reopen.bind(this);
|
|
42
41
|
// @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
|
|
43
42
|
this.useHeaders = useHeaders;
|
|
44
43
|
this.headers = buildSSEHeaders(settings);
|
|
@@ -54,7 +53,6 @@ var SSEClient = /** @class */ (function () {
|
|
|
54
53
|
*/
|
|
55
54
|
SSEClient.prototype.open = function (authToken) {
|
|
56
55
|
this.close(); // it closes connection if previously opened
|
|
57
|
-
this.authToken = authToken;
|
|
58
56
|
var channelsQueryParam = Object.keys(authToken.channels).map(function (channel) {
|
|
59
57
|
var params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
|
|
60
58
|
return encodeURIComponent(params + channel);
|
|
@@ -77,15 +75,6 @@ var SSEClient = /** @class */ (function () {
|
|
|
77
75
|
if (this.connection)
|
|
78
76
|
this.connection.close();
|
|
79
77
|
};
|
|
80
|
-
/**
|
|
81
|
-
* Re-open the connection with the last given authToken.
|
|
82
|
-
*
|
|
83
|
-
* @throws {TypeError} if `open` has not been previously called with an authToken
|
|
84
|
-
* @TODO this method is not used currently and could be removed.
|
|
85
|
-
*/
|
|
86
|
-
SSEClient.prototype.reopen = function () {
|
|
87
|
-
this.open(this.authToken);
|
|
88
|
-
};
|
|
89
78
|
return SSEClient;
|
|
90
79
|
}());
|
|
91
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 = {}));
|
|
@@ -10,7 +10,7 @@ var MySegmentsUpdateWorker = /** @class */ (function () {
|
|
|
10
10
|
this.mySegmentsSyncTask = mySegmentsSyncTask;
|
|
11
11
|
this.maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
|
|
12
12
|
this.handleNewEvent = false;
|
|
13
|
-
this.
|
|
13
|
+
this.segmentsData = undefined; // keeps the segmentsData (if included in notification payload) from the queued event with maximum changeNumber
|
|
14
14
|
this.currentChangeNumber = -1; // @TODO: remove once `/mySegments` endpoint provides the changeNumber
|
|
15
15
|
this.put = this.put.bind(this);
|
|
16
16
|
this.__handleMySegmentsUpdateCall = this.__handleMySegmentsUpdateCall.bind(this);
|
|
@@ -24,7 +24,7 @@ var MySegmentsUpdateWorker = /** @class */ (function () {
|
|
|
24
24
|
this.handleNewEvent = false;
|
|
25
25
|
var currentMaxChangeNumber_1 = this.maxChangeNumber;
|
|
26
26
|
// fetch mySegments revalidating data if cached
|
|
27
|
-
this.mySegmentsSyncTask.execute(this.
|
|
27
|
+
this.mySegmentsSyncTask.execute(this.segmentsData, true).then(function (result) {
|
|
28
28
|
if (result !== false) // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
|
|
29
29
|
_this.currentChangeNumber = Math.max(_this.currentChangeNumber, currentMaxChangeNumber_1); // use `currentMaxChangeNumber`, in case that `this.maxChangeNumber` was updated during fetch.
|
|
30
30
|
if (_this.handleNewEvent) {
|
|
@@ -40,15 +40,15 @@ var MySegmentsUpdateWorker = /** @class */ (function () {
|
|
|
40
40
|
* Invoked by NotificationProcessor on MY_SEGMENTS_UPDATE event
|
|
41
41
|
*
|
|
42
42
|
* @param {number} changeNumber change number of the MY_SEGMENTS_UPDATE notification
|
|
43
|
-
* @param {
|
|
43
|
+
* @param {SegmentsData | undefined} segmentsData might be undefined
|
|
44
44
|
*/
|
|
45
|
-
MySegmentsUpdateWorker.prototype.put = function (changeNumber,
|
|
45
|
+
MySegmentsUpdateWorker.prototype.put = function (changeNumber, segmentsData) {
|
|
46
46
|
if (changeNumber <= this.currentChangeNumber || changeNumber <= this.maxChangeNumber)
|
|
47
47
|
return;
|
|
48
48
|
this.maxChangeNumber = changeNumber;
|
|
49
49
|
this.handleNewEvent = true;
|
|
50
50
|
this.backoff.reset();
|
|
51
|
-
this.
|
|
51
|
+
this.segmentsData = segmentsData;
|
|
52
52
|
if (this.mySegmentsSyncTask.isExecuting())
|
|
53
53
|
return;
|
|
54
54
|
this.__handleMySegmentsUpdateCall();
|
|
@@ -54,7 +54,8 @@ var SegmentsUpdateWorker = /** @class */ (function () {
|
|
|
54
54
|
* @param {number} changeNumber change number of the SEGMENT_UPDATE notification
|
|
55
55
|
* @param {string} segmentName segment name of the SEGMENT_UPDATE notification
|
|
56
56
|
*/
|
|
57
|
-
SegmentsUpdateWorker.prototype.put = function (
|
|
57
|
+
SegmentsUpdateWorker.prototype.put = function (_a) {
|
|
58
|
+
var changeNumber = _a.changeNumber, segmentName = _a.segmentName;
|
|
58
59
|
var currentChangeNumber = this.segmentsCache.getChangeNumber(segmentName);
|
|
59
60
|
if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumbers[segmentName])
|
|
60
61
|
return;
|
|
@@ -46,7 +46,8 @@ var SplitsUpdateWorker = /** @class */ (function () {
|
|
|
46
46
|
*
|
|
47
47
|
* @param {number} changeNumber change number of the SPLIT_UPDATE notification
|
|
48
48
|
*/
|
|
49
|
-
SplitsUpdateWorker.prototype.put = function (
|
|
49
|
+
SplitsUpdateWorker.prototype.put = function (_a) {
|
|
50
|
+
var changeNumber = _a.changeNumber;
|
|
50
51
|
var currentChangeNumber = this.splitsCache.getChangeNumber();
|
|
51
52
|
if (changeNumber <= currentChangeNumber || changeNumber <= this.maxChangeNumber)
|
|
52
53
|
return;
|
|
@@ -64,14 +65,15 @@ var SplitsUpdateWorker = /** @class */ (function () {
|
|
|
64
65
|
* @param {string} splitName name of split to kill
|
|
65
66
|
* @param {string} defaultTreatment default treatment value
|
|
66
67
|
*/
|
|
67
|
-
SplitsUpdateWorker.prototype.killSplit = function (
|
|
68
|
+
SplitsUpdateWorker.prototype.killSplit = function (_a) {
|
|
69
|
+
var changeNumber = _a.changeNumber, splitName = _a.splitName, defaultTreatment = _a.defaultTreatment;
|
|
68
70
|
// @TODO handle retry due to errors in storage, once we allow the definition of custom async storages
|
|
69
71
|
if (this.splitsCache.killLocally(splitName, defaultTreatment, changeNumber)) {
|
|
70
72
|
// trigger an SDK_UPDATE if Split was killed locally
|
|
71
73
|
this.splitsEventEmitter.emit(SDK_SPLITS_ARRIVED, true);
|
|
72
74
|
}
|
|
73
75
|
// queues the SplitChanges fetch (only if changeNumber is newer)
|
|
74
|
-
this.put(changeNumber);
|
|
76
|
+
this.put({ changeNumber: changeNumber });
|
|
75
77
|
};
|
|
76
78
|
return SplitsUpdateWorker;
|
|
77
79
|
}());
|
|
@@ -23,6 +23,7 @@ export var PUSH_SUBSYSTEM_UP = 'PUSH_SUBSYSTEM_UP';
|
|
|
23
23
|
export var PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN';
|
|
24
24
|
// Update-type push notifications, handled by NotificationProcessor
|
|
25
25
|
export var MY_SEGMENTS_UPDATE = 'MY_SEGMENTS_UPDATE';
|
|
26
|
+
export var MY_SEGMENTS_UPDATE_V2 = 'MY_SEGMENTS_UPDATE_V2';
|
|
26
27
|
export var SEGMENT_UPDATE = 'SEGMENT_UPDATE';
|
|
27
28
|
export var SPLIT_KILL = 'SPLIT_KILL';
|
|
28
29
|
export var SPLIT_UPDATE = 'SPLIT_UPDATE';
|
|
@@ -34,4 +35,5 @@ export var ControlType;
|
|
|
34
35
|
ControlType["STREAMING_DISABLED"] = "STREAMING_DISABLED";
|
|
35
36
|
ControlType["STREAMING_PAUSED"] = "STREAMING_PAUSED";
|
|
36
37
|
ControlType["STREAMING_RESUMED"] = "STREAMING_RESUMED";
|
|
38
|
+
ControlType["STREAMING_RESET"] = "STREAMING_RESET";
|
|
37
39
|
})(ControlType || (ControlType = {}));
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { algorithms } from '../../utils/decompress';
|
|
2
|
+
import { decodeFromBase64 } from '../../utils/base64';
|
|
3
|
+
var GZIP = 1;
|
|
4
|
+
var ZLIB = 2;
|
|
5
|
+
function Uint8ArrayToString(myUint8Arr) {
|
|
6
|
+
return String.fromCharCode.apply(null, myUint8Arr);
|
|
7
|
+
}
|
|
8
|
+
function StringToUint8Array(myString) {
|
|
9
|
+
var charCodes = myString.split('').map(function (e) { return e.charCodeAt(0); });
|
|
10
|
+
return new Uint8Array(charCodes);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Decode and decompress 'data' with 'compression' algorithm
|
|
14
|
+
*
|
|
15
|
+
* @param {string} data
|
|
16
|
+
* @param {number} compression 1 GZIP, 2 ZLIB
|
|
17
|
+
* @returns {Uint8Array}
|
|
18
|
+
* @throws if data string cannot be decoded, decompressed or the provided compression value is invalid (not 1 or 2)
|
|
19
|
+
*/
|
|
20
|
+
function decompress(data, compression) {
|
|
21
|
+
var compressData = decodeFromBase64(data);
|
|
22
|
+
var binData = StringToUint8Array(compressData);
|
|
23
|
+
if (typeof algorithms === 'string')
|
|
24
|
+
throw new Error(algorithms);
|
|
25
|
+
if (compression === GZIP)
|
|
26
|
+
return algorithms.gunzipSync(binData);
|
|
27
|
+
if (compression === ZLIB)
|
|
28
|
+
return algorithms.unzlibSync(binData);
|
|
29
|
+
throw new Error("Invalid compression algorithm #" + compression);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Decode, decompress and parse the provided 'data' into a KeyList object
|
|
33
|
+
*
|
|
34
|
+
* @param {string} data
|
|
35
|
+
* @param {number} compression
|
|
36
|
+
* @returns {{a?: string[], r?: string[] }}
|
|
37
|
+
* @throws if data string cannot be decoded, decompressed or parsed
|
|
38
|
+
*/
|
|
39
|
+
export function parseKeyList(data, compression) {
|
|
40
|
+
var binKeyList = decompress(data, compression);
|
|
41
|
+
var strKeyList = Uint8ArrayToString(binKeyList);
|
|
42
|
+
// replace numbers to strings, to avoid losing precision
|
|
43
|
+
return JSON.parse(strKeyList.replace(/\d+/g, '"$&"'));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Decode, decompress and parse the provided 'data' into a Bitmap object
|
|
47
|
+
*
|
|
48
|
+
* @param {string} data
|
|
49
|
+
* @param {number} compression
|
|
50
|
+
* @returns {Uint8Array}
|
|
51
|
+
* @throws if data string cannot be decoded or decompressed
|
|
52
|
+
*/
|
|
53
|
+
export function parseBitmap(data, compression) {
|
|
54
|
+
return decompress(data, compression);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Check if the 'bitmap' bit at 'hash64hex' position is 1
|
|
58
|
+
*
|
|
59
|
+
* @param {Uint8Array} bitmap
|
|
60
|
+
* @param {string} hash64hex 16-chars string, representing a number in hexa
|
|
61
|
+
* @returns {boolean}
|
|
62
|
+
*/
|
|
63
|
+
export function isInBitmap(bitmap, hash64hex) {
|
|
64
|
+
// using the lowest 32 bits as index, to avoid losing precision when converting to number
|
|
65
|
+
var index = parseInt(hash64hex.slice(8), 16) % (bitmap.length * 8);
|
|
66
|
+
var internal = Math.floor(index / 8);
|
|
67
|
+
var offset = index % 8;
|
|
68
|
+
return (bitmap[internal] & 1 << offset) > 0;
|
|
69
|
+
}
|