UNPKG

@anam-ai/js-sdk

Version:

Client side JavaScript SDK for Anam AI

211 lines 8.58 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.SignallingClient = void 0; const constants_1 = require("../lib/constants"); const types_1 = require("../types"); const DEFAULT_HEARTBEAT_INTERVAL_SECONDS = 5; const DEFAULT_WS_RECONNECTION_ATTEMPTS = 5; class SignallingClient { constructor(sessionId, options, publicEventEmitter, internalEventEmitter) { var _a; this.stopSignal = false; this.sendingBuffer = []; this.wsConnectionAttempts = 0; this.socket = null; this.heartBeatIntervalRef = null; this.publicEventEmitter = publicEventEmitter; this.internalEventEmitter = internalEventEmitter; if (!sessionId) { throw new Error('Signalling Client: sessionId is required'); } this.sessionId = sessionId; const { heartbeatIntervalSeconds, maxWsReconnectionAttempts, url } = options; this.heartbeatIntervalSeconds = heartbeatIntervalSeconds || DEFAULT_HEARTBEAT_INTERVAL_SECONDS; this.maxWsReconnectionAttempts = maxWsReconnectionAttempts || DEFAULT_WS_RECONNECTION_ATTEMPTS; if (!url.baseUrl) { throw new Error('Signalling Client: baseUrl is required'); } const httpProtocol = url.protocol || 'https'; const initUrl = `${httpProtocol}://${url.baseUrl}`; this.url = new URL(initUrl); this.url.protocol = url.protocol === 'http' ? 'ws:' : 'wss:'; if (url.port) { this.url.port = url.port; } this.url.pathname = (_a = url.signallingPath) !== null && _a !== void 0 ? _a : '/ws'; this.url.searchParams.append('session_id', sessionId); } stop() { this.stopSignal = true; this.closeSocket(); } connect() { this.socket = new WebSocket(this.url.href); this.socket.onopen = this.onOpen.bind(this); this.socket.onclose = this.onClose.bind(this); this.socket.onerror = this.onError.bind(this); return this.socket; } sendOffer(localDescription) { return __awaiter(this, void 0, void 0, function* () { const offerMessagePayload = { connectionDescription: localDescription, userUid: this.sessionId, // TODO: this should be renamed to session Id on the server }; const offerMessage = { actionType: types_1.SignalMessageAction.OFFER, sessionId: this.sessionId, payload: offerMessagePayload, }; this.sendSignalMessage(offerMessage); }); } sendIceCandidate(candidate) { return __awaiter(this, void 0, void 0, function* () { const iceCandidateMessage = { actionType: types_1.SignalMessageAction.ICE_CANDIDATE, sessionId: this.sessionId, payload: candidate.toJSON(), }; this.sendSignalMessage(iceCandidateMessage); }); } sendSignalMessage(message) { var _a; if (((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) { try { this.socket.send(JSON.stringify(message)); } catch (error) { console.error('SignallingClient - sendSignalMessage: error sending message', error); } } else { this.sendingBuffer.push(message); } } sendTalkMessage(payload) { return __awaiter(this, void 0, void 0, function* () { const chatMessage = { actionType: types_1.SignalMessageAction.TALK_STREAM_INPUT, sessionId: this.sessionId, payload: payload, }; this.sendSignalMessage(chatMessage); }); } closeSocket() { if (this.socket) { this.socket.close(); this.socket = null; } if (this.heartBeatIntervalRef) { clearInterval(this.heartBeatIntervalRef); this.heartBeatIntervalRef = null; } } onOpen() { return __awaiter(this, void 0, void 0, function* () { if (!this.socket) { throw new Error('SignallingClient - onOpen: socket is null'); } try { this.wsConnectionAttempts = 0; this.flushSendingBuffer(); this.socket.onmessage = this.onMessage.bind(this); this.startSendingHeartBeats(); this.internalEventEmitter.emit(types_1.InternalEvent.WEB_SOCKET_OPEN); } catch (e) { console.error('SignallingClient - onOpen: error in onOpen', e); this.publicEventEmitter.emit(types_1.AnamEvent.CONNECTION_CLOSED, constants_1.CONNECTION_CLOSED_CODE_SIGNALLING_CLIENT_CONNECTION_FAILURE); } }); } onClose() { return __awaiter(this, void 0, void 0, function* () { this.wsConnectionAttempts += 1; if (this.stopSignal) { return; } if (this.wsConnectionAttempts <= this.maxWsReconnectionAttempts) { this.socket = null; setTimeout(() => { this.connect(); }, 100 * this.wsConnectionAttempts); } else { if (this.heartBeatIntervalRef) { clearInterval(this.heartBeatIntervalRef); this.heartBeatIntervalRef = null; } this.publicEventEmitter.emit(types_1.AnamEvent.CONNECTION_CLOSED, constants_1.CONNECTION_CLOSED_CODE_SIGNALLING_CLIENT_CONNECTION_FAILURE); } }); } onError(event) { if (this.stopSignal) { return; } console.error('SignallingClient - onError: ', event); } flushSendingBuffer() { const newBuffer = []; if (this.sendingBuffer.length > 0) { this.sendingBuffer.forEach((message) => { var _a; if (((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) { this.socket.send(JSON.stringify(message)); } else { newBuffer.push(message); } }); } this.sendingBuffer = newBuffer; } onMessage(event) { return __awaiter(this, void 0, void 0, function* () { const message = JSON.parse(event.data); this.internalEventEmitter.emit(types_1.InternalEvent.SIGNAL_MESSAGE_RECEIVED, message); }); } startSendingHeartBeats() { if (!this.socket) { throw new Error('SignallingClient - startSendingHeartBeats: socket is null'); } if (this.heartBeatIntervalRef) { console.warn('SignallingClient - startSendingHeartBeats: heartbeat interval already set'); } // send a heartbeat message every heartbeatIntervalSeconds const heartbeatInterval = this.heartbeatIntervalSeconds * 1000; const heartbeatMessage = { actionType: types_1.SignalMessageAction.HEARTBEAT, sessionId: this.sessionId, payload: '', }; const heartbeatMessageJson = JSON.stringify(heartbeatMessage); this.heartBeatIntervalRef = setInterval(() => { var _a; if (this.stopSignal) { return; } if (((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === WebSocket.OPEN) { this.socket.send(heartbeatMessageJson); } }, heartbeatInterval); } } exports.SignallingClient = SignallingClient; //# sourceMappingURL=SignallingClient.js.map