UNPKG

featurehub-repository

Version:

Core package of API that exposes FeatureHub feature flags, values and configuration to client applications written in Typescript or Javascript.

198 lines 7.96 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.FeatureHubPollingClient = void 0; const models_1 = require("./models/models"); const feature_hub_config_1 = require("./feature_hub_config"); class PollingBase { constructor(url, frequency, callback) { this.stopped = false; this.url = url; this.frequency = frequency; this._callback = callback; } attributeHeader(header) { return __awaiter(this, void 0, void 0, function* () { this._header = header; return this.poll(); }); } stop() { this.stopped = true; } delayTimer() { return __awaiter(this, void 0, void 0, function* () { return new Promise(((resolve, reject) => { if (!this.stopped && this.frequency > 0) { setTimeout(() => this.poll().then(resolve).catch(reject), this.frequency); } else { resolve(); } })); }); } } class BrowserPollingService extends PollingBase { constructor(options, url, frequency, callback) { super(url, frequency, callback); this._options = options; } poll() { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const req = new XMLHttpRequest(); req.open('GET', this.url); req.setRequestHeader('Content-type', 'application/json'); if (this._header) { req.setRequestHeader('x-featurehub', this._header); } req.send(); req.onreadystatechange = () => { if (req.readyState === 4) { if (req.status === 200) { this._callback(models_1.ObjectSerializer.deserialize(JSON.parse(req.responseText), 'Array<Environment>')); resolve(); } else if (req.status >= 400 && req.status < 500) { reject(`Failed to connect to ${this.url} with ${req.status}`); } else { this.delayTimer().then(resolve).catch(reject); } } }; }); }); } } class NodejsPollingService extends PollingBase { constructor(options, url, frequency, _callback) { super(url, frequency, _callback); this._options = options; this.uri = new URL(this.url); } poll() { return __awaiter(this, void 0, void 0, function* () { return new Promise(((resolve, reject) => { const http = this.uri.protocol === 'http:' ? require('http') : require('https'); let data = ''; let headers = this._header === undefined ? {} : { 'x-featurehub': this._header }; const reqOptions = { protocol: this.uri.protocol, host: this.uri.host, hostname: this.uri.hostname, port: this.uri.port, method: 'GET', path: this.uri.pathname + this.uri.search, headers: headers, timeout: this._options.timeout || 8000 }; const req = http.request(reqOptions, (res) => { res.on('data', (chunk) => data += chunk); res.on('end', () => { if (res.statusCode === 200) { this._callback(models_1.ObjectSerializer.deserialize(JSON.parse(data), 'Array<Environment>')); resolve(); } else if (res.statusCode >= 400 && res.statusCode < 500) { reject(`Failed to connect to ${this.url} with ${res.statusCode}`); } else { this.delayTimer().then(resolve).catch(reject); } }); }); req.end(); })); }); } } class FeatureHubPollingClient { constructor(repository, config, frequency, options = {}) { this._frequency = frequency; this._repository = repository; this._options = options; this._config = config; this._url = config.getHost() + 'features?' + config.getApiKeys().map(e => 'sdkUrl=' + encodeURIComponent(e)).join('&'); } _initService() { if (this._pollingService === undefined) { if (Object.prototype.toString.call(global.process) !== '[object process]') { this._pollingService = new BrowserPollingService(this._options, this._url, this._frequency, (e) => this.response(e)); } else { this._pollingService = new NodejsPollingService(this._options, this._url, this._frequency, (e) => this.response(e)); } feature_hub_config_1.fhLog.log(`featurehub: initialized polling client to ${this._url}`); } } contextChange(header) { return __awaiter(this, void 0, void 0, function* () { if (!this._config.clientEvaluated()) { if (this._xHeader !== header) { this._xHeader = header; this._initService(); return this._pollingService.attributeHeader(header); } } }); } clientEvaluated() { return this._config.clientEvaluated(); } requiresReplacementOnHeaderChange() { return false; } close() { if (this._pollingService) { this._pollingService.stop(); } } poll() { this._initService(); return this._pollingService.poll(); } stop() { this._pollingService.stop(); this._pollingService = undefined; } _restartTimer() { setTimeout(() => this._pollingService.poll().catch((e) => { feature_hub_config_1.fhLog.error(`Failed to poll, restarting in ${this._frequency}ms: ${e}`); this._repository.notify(models_1.SSEResultState.Failure, null); }).finally(() => this._restartTimer()), this._frequency); } response(environments) { if (environments.length === 0) { this._startable = false; this.stop(); this._repository.notify(models_1.SSEResultState.Failure, null); } else { const features = new Array(); environments.forEach(e => { if (e.features.length > 0) { e.features.forEach(f => { f.environmentId = e.id; }); features.push(...e.features); } }); this._repository.notify(models_1.SSEResultState.Features, features); this._restartTimer(); } } } exports.FeatureHubPollingClient = FeatureHubPollingClient; //# sourceMappingURL=polling_sdk.js.map