@launchdarkly/js-server-sdk-common
Version:
LaunchDarkly Server SDK for JavaScript - common code
110 lines • 5.48 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const js_sdk_common_1 = require("@launchdarkly/js-sdk-common");
const reportJsonError = (type, data, logger, errorHandler) => {
logger === null || logger === void 0 ? void 0 : logger.error(`Stream received invalid data in "${type}" message`);
logger === null || logger === void 0 ? void 0 : logger.debug(`Invalid JSON follows: ${data}`);
errorHandler === null || errorHandler === void 0 ? void 0 : errorHandler(new js_sdk_common_1.LDStreamingError(js_sdk_common_1.DataSourceErrorKind.InvalidData, 'Malformed JSON data in event stream'));
};
class StreamingProcessor {
constructor(clientContext, streamUriPath, parameters, _listeners, baseHeaders, _diagnosticsManager, _errorHandler, _streamInitialReconnectDelay = 1) {
this._listeners = _listeners;
this._diagnosticsManager = _diagnosticsManager;
this._errorHandler = _errorHandler;
this._streamInitialReconnectDelay = _streamInitialReconnectDelay;
const { basicConfiguration, platform } = clientContext;
const { logger } = basicConfiguration;
const { requests } = platform;
this._headers = Object.assign({}, baseHeaders);
this._logger = logger;
this._requests = requests;
this._streamUri = (0, js_sdk_common_1.getStreamingUri)(basicConfiguration.serviceEndpoints, streamUriPath, parameters);
}
_logConnectionStarted() {
this._connectionAttemptStartTime = Date.now();
}
_logConnectionResult(success) {
if (this._connectionAttemptStartTime && this._diagnosticsManager) {
this._diagnosticsManager.recordStreamInit(this._connectionAttemptStartTime, !success, Date.now() - this._connectionAttemptStartTime);
}
this._connectionAttemptStartTime = undefined;
}
/**
* This is a wrapper around the passed errorHandler which adds additional
* diagnostics and logging logic.
*
* @param err The error to be logged and handled.
* @return boolean whether to retry the connection.
*
* @private
*/
_retryAndHandleError(err) {
var _a, _b, _c;
if (!(0, js_sdk_common_1.shouldRetry)(err)) {
this._logConnectionResult(false);
(_a = this._errorHandler) === null || _a === void 0 ? void 0 : _a.call(this, new js_sdk_common_1.LDStreamingError(js_sdk_common_1.DataSourceErrorKind.ErrorResponse, err.message, err.status));
(_b = this._logger) === null || _b === void 0 ? void 0 : _b.error((0, js_sdk_common_1.httpErrorMessage)(err, 'streaming request'));
return false;
}
(_c = this._logger) === null || _c === void 0 ? void 0 : _c.warn((0, js_sdk_common_1.httpErrorMessage)(err, 'streaming request', 'will retry'));
this._logConnectionResult(false);
this._logConnectionStarted();
return true;
}
start() {
this._logConnectionStarted();
// TLS is handled by the platform implementation.
const eventSource = this._requests.createEventSource(this._streamUri, {
headers: this._headers,
errorFilter: (error) => this._retryAndHandleError(error),
initialRetryDelayMillis: 1000 * this._streamInitialReconnectDelay,
readTimeoutMillis: 5 * 60 * 1000,
retryResetIntervalMillis: 60 * 1000,
});
this._eventSource = eventSource;
eventSource.onclose = () => {
var _a;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info('Closed LaunchDarkly stream connection');
};
eventSource.onerror = () => {
// The work is done by `errorFilter`.
};
eventSource.onopen = () => {
var _a;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info('Opened LaunchDarkly stream connection');
};
eventSource.onretrying = (e) => {
var _a;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.info(`Will retry stream connection in ${e.delayMillis} milliseconds`);
};
this._listeners.forEach(({ deserializeData, processJson }, eventName) => {
eventSource.addEventListener(eventName, (event) => {
var _a, _b;
(_a = this._logger) === null || _a === void 0 ? void 0 : _a.debug(`Received ${eventName} event`);
if (event === null || event === void 0 ? void 0 : event.data) {
this._logConnectionResult(true);
const { data } = event;
const dataJson = deserializeData(data);
if (!dataJson) {
reportJsonError(eventName, data, this._logger, this._errorHandler);
return;
}
processJson(dataJson);
}
else {
(_b = this._errorHandler) === null || _b === void 0 ? void 0 : _b.call(this, new js_sdk_common_1.LDStreamingError(js_sdk_common_1.DataSourceErrorKind.Unknown, 'Unexpected payload from event stream'));
}
});
});
}
stop() {
var _a;
(_a = this._eventSource) === null || _a === void 0 ? void 0 : _a.close();
this._eventSource = undefined;
}
close() {
this.stop();
}
}
exports.default = StreamingProcessor;
//# sourceMappingURL=StreamingProcessor.js.map