@splitsoftware/splitio-commons
Version:
Split JavaScript SDK common components
94 lines (93 loc) • 4.35 kB
JavaScript
import { errorParser, messageParser } from './NotificationParser';
import { notificationKeeperFactory } from './NotificationKeeper';
import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIPS_MS_UPDATE, MEMBERSHIPS_LS_UPDATE, RB_SEGMENT_UPDATE } from '../constants';
import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
import { ABLY_ERROR, NON_REQUESTED, SSE_CONNECTION_ERROR } from '../../../utils/constants';
/**
* Factory for SSEHandler, which processes SSEClient messages and emits the corresponding push events.
*
* @param log - factory logger
* @param pushEmitter - emitter for events related to streaming support
*/
export function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
var notificationKeeper = notificationKeeperFactory(pushEmitter, telemetryTracker);
function isRetryableError(error) {
if (error.parsedData && error.parsedData.code) {
// Ably error
var code = error.parsedData.code;
telemetryTracker.streamingEvent(ABLY_ERROR, code);
// 401 errors due to invalid or expired token (e.g., if refresh token coudn't be executed)
if (40140 <= code && code <= 40149)
return true;
// Others 4XX errors (e.g., bad request from the SDK)
if (40000 <= code && code <= 49999)
return false;
}
else {
// network errors or 5XX HTTP errors
telemetryTracker.streamingEvent(SSE_CONNECTION_ERROR, NON_REQUESTED);
}
return true;
}
return {
handleOpen: function () {
notificationKeeper.handleOpen();
},
/* HTTP & Network errors */
handleError: function (error) {
var errorWithParsedData = error;
try {
errorWithParsedData = errorParser(error);
}
catch (err) {
log.warn(STREAMING_PARSING_ERROR_FAILS, [err]);
}
var errorMessage = (errorWithParsedData.parsedData && errorWithParsedData.parsedData.message) || errorWithParsedData.message;
log.error(ERROR_STREAMING_SSE, [errorMessage]);
if (isRetryableError(errorWithParsedData)) {
pushEmitter.emit(PUSH_RETRYABLE_ERROR);
}
else {
pushEmitter.emit(PUSH_NONRETRYABLE_ERROR);
}
},
/* NotificationProcessor */
handleMessage: function (message) {
var messageWithParsedData;
try {
messageWithParsedData = messageParser(message);
if (!messageWithParsedData)
return; // Messages with empty data are ignored
}
catch (err) {
log.warn(STREAMING_PARSING_MESSAGE_FAILS, [err]);
return;
}
var parsedData = messageWithParsedData.parsedData, data = messageWithParsedData.data, channel = messageWithParsedData.channel, timestamp = messageWithParsedData.timestamp;
log.debug(STREAMING_NEW_MESSAGE, [data]);
// we only handle update events if streaming is up
if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
return;
switch (parsedData.type) {
/* update events */
case SPLIT_UPDATE:
case SEGMENT_UPDATE:
case MEMBERSHIPS_MS_UPDATE:
case MEMBERSHIPS_LS_UPDATE:
case SPLIT_KILL:
case RB_SEGMENT_UPDATE:
pushEmitter.emit(parsedData.type, parsedData);
break;
/* occupancy & control events, handled by NotificationManagerKeeper */
case OCCUPANCY:
notificationKeeper.handleOccupancyEvent(parsedData.metrics.publishers, channel, timestamp);
break;
case CONTROL:
notificationKeeper.handleControlEvent(parsedData.controlType, channel, timestamp);
break;
default:
break;
}
},
};
}