infobip-rtc
Version:
Infobip RTC JavaScript SDK - Infobip WebRTC API Implementation
200 lines • 7.65 kB
JavaScript
import jwtDecode from 'jwt-decode';
import Properties from "./Properties";
import Status from "./Status";
import { version } from "../Version";
import Retry from '../util/Retry';
import Browser from '../util/Browser';
export class InfobipGatewayImpl {
constructor(eventEmitter, logger, token) {
this.eventEmitter = eventEmitter;
this.logger = logger;
this.token = token;
this.status = Status.OFFLINE;
this.host = this.generatePortunusHost(jwtDecode(token));
this.deviceInfo = this.encodeDeviceInfo();
this.initRetry();
}
connect(isReconnect = false) {
this.ws = new WebSocket(this.generatePortunusUrl(), [this.token, this.deviceInfo]);
this.status = isReconnect ? Status.RECONNECTING : Status.CONNECTING;
this.ws.onopen = this.onOpen.bind(this);
this.ws.onclose = this.onClose.bind(this);
this.ws.onmessage = this.onMessage.bind(this);
this.ws.onerror = this.onError.bind(this);
}
disconnect() {
if ([Status.RECONNECTING, Status.CONNECTING, Status.CONNECTED].indexOf(this.status) >= 0) {
this.ws.close(4000, "USER_DISCONNECT");
}
if (this.retry.cancel()) {
this.eventEmitter.emit('disconnected', ({ code: 4000, reason: 'USER_DISCONNECT' }));
}
this.status = Status.OFFLINE;
}
;
send(data) {
var _a;
if (this.status !== Status.CONNECTED) {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`Socket to Infobip WebRTC Gateway not opened, could not send ${JSON.stringify(data)}!`);
return;
}
this.logSendingMessage(data);
let message = JSON.stringify(data);
this.ws.send(message);
}
setLogger(logger) {
this.logger = logger;
}
encodeDeviceInfo() {
let generatedDeviceInfo = JSON.stringify(this.generateDeviceInfo());
return this.base64EncodeUrl(window.btoa(generatedDeviceInfo));
}
generatePortunusHost(token) {
let location = token.location;
if (!location) {
return "portunus.infobip.com";
}
if (location === "io") {
return "portunus.ioinfobip.com";
}
if (["iop1", "iop2"].includes(location)) {
return `portunus-${location}.ioinfobip.com`;
}
return "portunus-" + location + ".infobip.com";
}
generatePortunusUrl() {
let url = `wss://${this.host}`;
if (this.portunusInstanceHash) {
url += `?instance=${this.portunusInstanceHash}`;
}
return url;
}
logSendingMessage(message) {
var _a;
if (message.action !== 'heartbeat' && message.action !== 'heartbeat_resp') {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Sending ${JSON.stringify(message)} to Infobip WebRTC Gateway...`);
}
}
onOpen() {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info('Socket to Infobip WebRTC Gateway opened.');
this.eventEmitter.once("registered", event => {
this.portunusInstanceHash = event.instanceHash;
});
let reconnected = this.status === Status.RECONNECTING;
if (reconnected) {
this.eventEmitter.once("registered", args => {
this.eventEmitter.emit('reconnected');
});
}
this.status = Status.CONNECTED;
this.scheduleHeartbeat();
this.initRetry();
}
onMessage(message) {
let data = JSON.parse(message.data);
this.logReceivedMessage(data);
if (data.event === 'heartbeat_resp') {
this.cancelHeartbeatCheck();
return;
}
if (data.event === 'heartbeat') {
this.sendHeartbeatResponse();
return;
}
if (data.event === 'registration_failed') {
this.disconnect();
}
this.eventEmitter.emit(data.event, data);
}
sendHeartbeatResponse() {
this.send({ action: 'heartbeat_resp' });
}
logReceivedMessage(message) {
var _a;
if (message.event !== 'heartbeat_resp' && message.event !== 'heartbeat') {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.debug(`Received message from Infobip Gateway: ${JSON.stringify(message)}.`);
}
}
onClose(event) {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Socket closed, code ${event.code}, reason: ${event.reason}.`);
if (event.code === 1013) {
this.portunusInstanceHash = null;
}
const prevStatus = this.status;
this.status = Status.OFFLINE;
this.cleanup();
if (prevStatus !== Status.OFFLINE && event.code < 4000) {
this.retry.retry();
if (prevStatus === Status.CONNECTED) {
this.eventEmitter.emit('reconnecting');
}
}
else {
this.eventEmitter.emit('disconnected', event);
}
}
cleanup() {
clearInterval(this.heartbeat);
this.cancelHeartbeatCheck();
this.ws.onopen = null;
this.ws.onclose = null;
this.ws.onmessage = null;
this.ws.onerror = null;
delete this.ws;
}
onError(event) {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.error(`Socket error: ${JSON.stringify(event)}.`);
}
scheduleHeartbeat() {
this.heartbeat = setInterval(() => {
if (this.ws.readyState === WebSocket.OPEN) {
this.send({ 'action': 'heartbeat' });
this.scheduleHeartbeatCheck();
}
}, Properties.HEARTBEAT_PERIOD);
}
scheduleHeartbeatCheck() {
var _a;
if (this.heartbeatCheck) {
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.warn("Did not receive previous heartbeat response, skipping new heartbeat check.");
return;
}
this.heartbeatCheck = setTimeout(() => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`No heartbeat response in ${Properties.HEARTBEAT_TIMEOUT} milliseconds. Closing socket...`);
this.onClose({ code: 3000, reason: 'Heartbeat timeout.' });
}, Properties.HEARTBEAT_TIMEOUT);
}
initRetry() {
var _a;
(_a = this.retry) === null || _a === void 0 ? void 0 : _a.cancel();
this.retry = new Retry(iteration => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Reconnect attempt ${iteration}...`);
this.connect(true);
}, Retry.exponentialDelay(Properties.RECONNECT_INITIAL_DELAY), Properties.RECONNECT_MAX_DELAY, Properties.RECONNECT_MAX)
.catch(reason => {
var _a;
(_a = this.logger) === null || _a === void 0 ? void 0 : _a.info(`Reconnecting failed, reason: ${reason}`);
this.eventEmitter.emit('disconnected', { reason: 'Connection error.' });
});
}
generateDeviceInfo() {
let browser = new Browser();
return {
sdk: { type: 'js', version: version },
device: { browser: browser.getBrowser(), os: browser.getOS() }
};
}
base64EncodeUrl(value) {
return value.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
cancelHeartbeatCheck() {
clearTimeout(this.heartbeatCheck);
this.heartbeatCheck = undefined;
}
}
//# sourceMappingURL=InfobipGateway.js.map