UNPKG

@hellotext/hellotext

Version:
197 lines 7.1 kB
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } import { Configuration } from '../core'; var ApplicationChannel = /*#__PURE__*/function () { function ApplicationChannel() { _classCallCheck(this, ApplicationChannel); ApplicationChannel.channels.add(this); } _createClass(ApplicationChannel, [{ key: "send", value: function send(_ref) { var { command, identifier, data } = _ref; var payload = { command, identifier: JSON.stringify(identifier), data: JSON.stringify(data || {}) }; var socket = ApplicationChannel.ensureWebSocket(); var message = JSON.stringify(payload); if (socket.readyState === WebSocket.OPEN) { socket.send(message); } else { socket.addEventListener('open', () => { socket.send(message); }); } } }, { key: "onMessage", value: function onMessage(callback) { var handler = event => { var data = JSON.parse(event.data); var { type, message } = data; if (this.ignoredEvents.includes(type)) { return; } callback(message); }; ApplicationChannel.messageHandlers.add(handler); ApplicationChannel.ensureWebSocket().addEventListener('message', handler); } }, { key: "onDisconnect", value: function onDisconnect(callback) { ApplicationChannel.disconnectHandlers.add(callback); } }, { key: "onSubscriptionConfirmed", value: function onSubscriptionConfirmed(callback) { ApplicationChannel.subscriptionConfirmHandlers.add(callback); } }, { key: "webSocket", get: function get() { return ApplicationChannel.ensureWebSocket(); } }, { key: "ignoredEvents", get: function get() { return ['ping', 'confirm_subscription', 'welcome']; } }], [{ key: "ensureWebSocket", value: function ensureWebSocket() { if (this.webSocket && !this.closedWebSocket(this.webSocket)) { return this.webSocket; } if (this.webSocket) { this.needsResubscribe = true; } return this.openWebSocket(); } }, { key: "openWebSocket", value: function openWebSocket() { this.clearReconnectTimeout(); var socket = new WebSocket(Configuration.actionCableUrl); this.webSocket = socket; this.installWebSocketHandlers(socket); return socket; } }, { key: "installWebSocketHandlers", value: function installWebSocketHandlers(socket) { socket.addEventListener('open', () => this.handleOpen(socket)); socket.addEventListener('close', () => this.handleDisconnect(socket)); socket.addEventListener('error', () => this.handleDisconnect(socket)); socket.addEventListener('message', event => this.handleControlMessage(event)); this.messageHandlers.forEach(handler => { socket.addEventListener('message', handler); }); } }, { key: "handleOpen", value: function handleOpen(socket) { if (socket !== this.webSocket) { return; } this.reconnectAttempts = 0; if (!this.needsResubscribe) { return; } this.needsResubscribe = false; this.resubscribeChannels(); } }, { key: "handleControlMessage", value: function handleControlMessage(event) { var data; try { data = JSON.parse(event.data); } catch (_unused) { return; } if (data.type !== 'confirm_subscription') { return; } this.subscriptionConfirmHandlers.forEach(callback => callback(data.identifier)); } }, { key: "handleDisconnect", value: function handleDisconnect(socket) { if (socket !== this.webSocket) { return; } this.disconnectHandlers.forEach(callback => callback()); this.webSocket = null; this.needsResubscribe = true; this.scheduleReconnect(); } }, { key: "scheduleReconnect", value: function scheduleReconnect() { if (this.reconnectTimeout) { return; } this.reconnectTimeout = setTimeout(() => { this.reconnectTimeout = null; this.reconnectAttempts += 1; this.openWebSocket(); }, this.reconnectDelay); } }, { key: "clearReconnectTimeout", value: function clearReconnectTimeout() { if (this.reconnectTimeout) { clearTimeout(this.reconnectTimeout); this.reconnectTimeout = null; } } }, { key: "resubscribeChannels", value: function resubscribeChannels() { this.channels.forEach(channel => { var resubscribe = channel.resubscribe || channel.subscribe; if (typeof resubscribe === 'function') { resubscribe.call(channel); } }); } }, { key: "closedWebSocket", value: function closedWebSocket(socket) { return socket.readyState === WebSocket.CLOSED || socket.readyState === WebSocket.CLOSING; } }, { key: "reconnectDelay", get: function get() { var delay = Math.min(this.reconnectMaxDelay, this.reconnectBaseDelay * 2 ** this.reconnectAttempts); var jitter = Math.round(delay * this.reconnectJitter * Math.random()); return delay + jitter; } }]); return ApplicationChannel; }(); ApplicationChannel.webSocket = void 0; ApplicationChannel.channels = new Set(); ApplicationChannel.messageHandlers = new Set(); ApplicationChannel.disconnectHandlers = new Set(); ApplicationChannel.subscriptionConfirmHandlers = new Set(); ApplicationChannel.reconnectTimeout = null; ApplicationChannel.reconnectAttempts = 0; ApplicationChannel.reconnectBaseDelay = 500; ApplicationChannel.reconnectMaxDelay = 10000; ApplicationChannel.reconnectJitter = 0.3; ApplicationChannel.needsResubscribe = false; export default ApplicationChannel;