UNPKG

@multiplayer-app/session-recorder-browser

Version:
190 lines 6.73 kB
import io from 'socket.io-client'; import { Observable } from 'lib0/observable'; import messagingService from '../services/messaging.service'; import { SESSION_ADD_EVENT, SESSION_AUTO_CREATED, SESSION_STOPPED_EVENT, SESSION_SUBSCRIBE_EVENT, SESSION_UNSUBSCRIBE_EVENT, SOCKET_SET_USER_EVENT, REMOTE_SESSION_RECORDING_START, REMOTE_SESSION_RECORDING_STOP, SESSION_STARTED_EVENT, } from '../config'; const MAX_RECONNECTION_ATTEMPTS = 2; export class SocketService extends Observable { constructor() { super(); this.socket = null; this.queue = []; this.isConnecting = false; this.isConnected = false; this.attempts = 0; this.sessionId = null; this.usePostMessage = false; this.options = { apiKey: '', socketUrl: '', keepAlive: false, usePostMessageFallback: false, }; } /** * Initialize the socket service * @param config - Socket service configuration */ init(config) { this.options = { ...this.options, ...config, }; if (this.options.keepAlive && this.options.socketUrl && this.options.apiKey) { this._initConnection(); } } /** * Update the socket service configuration * @param config - Partial configuration to update */ updateConfigs(config) { var _a; // If any config changed, reconnect if connected const hasChanges = Object.keys(config).some((key) => { const typedKey = key; return (config[typedKey] !== undefined && config[typedKey] !== this.options[typedKey]); }); if (hasChanges) { this.options = { ...this.options, ...config }; if ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected) { this.close().then(() => { if (this.options.keepAlive && this.options.socketUrl && this.options.apiKey) { this._initConnection(); } }); } } } _initConnection() { if (this.isConnecting || this.isConnected) return; this.attempts++; this.isConnecting = true; this.usePostMessage = false; this.socket = io(this.options.socketUrl, { path: '/v0/radar/ws', auth: { 'x-api-key': this.options.apiKey, }, reconnectionAttempts: 2, transports: ['websocket'], }); this.socket.on('ready', () => { this.isConnecting = false; this.isConnected = true; this.usePostMessage = false; this.flushQueue(); }); this.socket.on('disconnect', (err) => { this.isConnecting = false; this.isConnected = false; }); this.socket.on('connect_error', (err) => { this.isConnecting = false; this.isConnected = false; this.checkReconnectionAttempts(); }); this.socket.on(SESSION_STOPPED_EVENT, (data) => { this.emit(SESSION_STOPPED_EVENT, [data]); }); this.socket.on(SESSION_AUTO_CREATED, (data) => { this.emit(SESSION_AUTO_CREATED, [data]); }); this.socket.on(REMOTE_SESSION_RECORDING_START, (data) => { this.emit(REMOTE_SESSION_RECORDING_START, [data]); }); this.socket.on(REMOTE_SESSION_RECORDING_STOP, (data) => { this.emit(REMOTE_SESSION_RECORDING_STOP, [data]); }); } checkReconnectionAttempts() { if (this.attempts >= MAX_RECONNECTION_ATTEMPTS) { this.usePostMessage = !!this.options.usePostMessageFallback; this.flushQueue(); } } sendViaPostMessage(name, data) { const action = name === SESSION_ADD_EVENT ? 'rrweb-event' : 'socket-emit'; messagingService.sendMessage(action, data); } emitSocketEvent(name, data) { if (this.usePostMessage) { this.sendViaPostMessage(name, data); } else if (this.socket && this.isConnected) { this.socket.emit(name, data); } else { this.queue.push({ data, name }); this._initConnection(); } } flushQueue() { while (this.queue.length > 0 && (this.usePostMessage || this.isConnected)) { const event = this.queue.shift(); if (!event) continue; if (this.usePostMessage) { this.sendViaPostMessage(event.name, event.data); } else if (this.socket && this.isConnected) { this.socket.emit(event.name, event.data); } } } send(event) { this.emitSocketEvent(SESSION_ADD_EVENT, event); } subscribeToSession(session) { this.sessionId = session.shortId || session._id; const payload = { projectId: session.project, workspaceId: session.workspace, debugSessionId: this.sessionId, sessionType: session.creationType, }; this.emitSocketEvent(SESSION_SUBSCRIBE_EVENT, payload); // use long id instead of short id this.emitSocketEvent(SESSION_STARTED_EVENT, { debugSessionId: session._id }); } unsubscribeFromSession(stopSession) { if (this.sessionId) { this.emitSocketEvent(SESSION_UNSUBSCRIBE_EVENT, { debugSessionId: this.sessionId }); if (stopSession) { this.emitSocketEvent(SESSION_STOPPED_EVENT, {}); } } } setUser(userAttributes) { this.emitSocketEvent(SOCKET_SET_USER_EVENT, userAttributes); } close() { return new Promise((resolve) => { var _a; if (this.usePostMessage) { this.sendViaPostMessage('close', {}); } if ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.connected) { setTimeout(() => { var _a; this.unsubscribeFromSession(); this.attempts = 0; this.isConnected = false; this.isConnecting = false; (_a = this.socket) === null || _a === void 0 ? void 0 : _a.disconnect(); this.socket = null; resolve(); }, 500); } else { resolve(); } }); } } //# sourceMappingURL=socket.service.js.map