UNPKG

sinch-rtc

Version:

RTC JavaScript/Web SDK

156 lines 7.24 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.FeaturesFactory = exports.Features = void 0; const Event_1 = require("../utils/Event"); const fsm_1 = require("../session/fsm"); const FeatureStorage_1 = require("../storage/FeatureStorage"); const TimeService_1 = require("../utils/TimeService"); const constants_1 = require("../constants"); const utils_1 = require("../utils"); class Features { constructor(featureStorage) { this.featureStorage = featureStorage; this.featureFlags = new Map(); this.timeService = TimeService_1.TimeServiceFactory.create(); this.onFeatureChanged = new Event_1.Event(); } getFeatureFlag(key) { return this.featureFlags.get(key); } initialiseFeatureFlags() { const shouldUseDefaultValues = this.featureStorage.isEmpty(); Object.keys(constants_1.FeatureFlag).forEach((featureFlagKey) => { const featureFlag = constants_1.FeatureFlag[featureFlagKey]; const featureFlagValue = shouldUseDefaultValues ? constants_1.FeatureFlagDefaults[featureFlag] : this.featureStorage.getFeatureFlag(featureFlag); this.featureFlags.set(featureFlag, featureFlagValue !== null && featureFlagValue !== void 0 ? featureFlagValue : false); }); } shouldRefresh() { const lastRefreshedAtMs = this.featureStorage.getFeatureFlag(FeatureStorage_1.FeatureStorage.LAST_REFRESHED_AT); if (!lastRefreshedAtMs) { return true; } const nowMs = this.timeService.now.getTime(); return nowMs - lastRefreshedAtMs >= FeatureStorage_1.FeatureStorage.REFRESH_INTERVAL_MS; } setUserInstance(userId, instanceId, applicationKey) { this.userId = userId; this.instanceId = instanceId; this.featureStorage.setApplicationConfig(userId, applicationKey); this.initialiseFeatureFlags(); } refresh(apiClient) { return __awaiter(this, void 0, void 0, function* () { const fetchedFeatureFlags = yield this.fetchFeatureFlags(apiClient); this.updateAndPublishFeaturesIfNeeded(fetchedFeatureFlags); }); } addListener(listener) { this.onFeatureChanged.add(listener); } resetListeners() { this.onFeatureChanged = new Event_1.Event(); } fetchFeatureFlags(apiClient) { return __awaiter(this, void 0, void 0, function* () { if (!this.userId) { throw new fsm_1.InvalidOperationError("Missing userId"); } if (!this.instanceId) { throw new fsm_1.InvalidOperationError("Missing instanceId"); } const fetchedFeatureFlags = new Map(); try { const featureFlagsResponse = yield apiClient.getFeatureFlags({ userId: this.userId, instanceId: this.instanceId, }); for (const [featureFlag, value] of Object.entries(featureFlagsResponse)) { fetchedFeatureFlags.set(featureFlag, value); } } catch (error) { console.error("Could not fetch feature flags. Will use default values", { error, }); fetchedFeatureFlags.clear(); } return fetchedFeatureFlags; }); } updateFeatureFlags(fetchedFeatureFlags) { // add default values if fetched values are undefined/wrong this.featureFlags.forEach((_, featureFlagKey) => { const fetchedFeatureFlagValue = fetchedFeatureFlags.get(featureFlagKey); const defaultValue = constants_1.FeatureFlagDefaults[featureFlagKey]; const isFetchedValueValid = utils_1.TypeHelper.isBoolean(fetchedFeatureFlagValue) || (utils_1.TypeHelper.isNumber(fetchedFeatureFlagValue) && typeof fetchedFeatureFlagValue === typeof defaultValue); this.featureFlags.set(featureFlagKey, isFetchedValueValid ? fetchedFeatureFlagValue : constants_1.FeatureFlagDefaults[featureFlagKey]); }); } updateAndPublishFeaturesIfNeeded(fetchedFeatureFlags) { if (this.hasFeaturesChanged(fetchedFeatureFlags)) { this.updateFeatureFlags(fetchedFeatureFlags); this.storeFeatures(); this.publishFeaturesChanged(); } } publishFeaturesChanged() { this.onFeatureChanged.fire(this.featureFlags); } hasFeaturesChanged(fetchedFeatureFlags) { const featureFlagsFromStorage = Object.entries(constants_1.FeatureFlag).reduce((accumulator, featureFlagEntry) => { const featureFlagFromStorage = this.featureStorage.getFeatureFlag(featureFlagEntry[1]); if (utils_1.TypeHelper.isBoolean(featureFlagFromStorage) || utils_1.TypeHelper.isNumber(featureFlagFromStorage)) { accumulator.set(featureFlagEntry[1], featureFlagFromStorage); } return accumulator; }, new Map()); // if a flag was removed on the server, we want to refresh it in local storage // otherwise if both fetched feature flags and features in storage are empty we want to use default values if (fetchedFeatureFlags.size < featureFlagsFromStorage.size || !(fetchedFeatureFlags.size && featureFlagsFromStorage.size)) { return true; } // otherwise we compare the features by key for (const [featureFlagKey, value] of fetchedFeatureFlags) { const valueFromStorage = featureFlagsFromStorage.get(featureFlagKey); if (valueFromStorage !== value || (valueFromStorage === undefined && !featureFlagsFromStorage.has(featureFlagKey))) { return true; } return false; } } storeFeatures() { this.featureStorage.removeAll(); for (const [featureFlagKey, value] of this.featureFlags) { this.featureStorage.setFeatureFlag(featureFlagKey, value); } this.featureStorage.setFeatureFlag(FeatureStorage_1.FeatureStorage.LAST_REFRESHED_AT, this.timeService.now.getTime()); } } exports.Features = Features; class FeaturesFactory { static create(featureStorage) { return new Features(featureStorage); } } exports.FeaturesFactory = FeaturesFactory; //# sourceMappingURL=Features.js.map