UNPKG

@ryinner/web-socket-manager

Version:
126 lines 4.65 kB
import parseQueryParams from './parseQueryParams'; class WebSocketManager { get ws() { if (!this.isWebSocket(this.webSocketInstance) || this.isClose()) { const openHandler = this.onOpenHandler.bind(this); const closeHandler = this.onCloseHandler.bind(this); const messageHandler = this.onMessageHandler.bind(this); const errorHandler = this.onErrorHandler.bind(this); this.webSocketInstance = new WebSocket(this.wss); this.webSocketInstance.onclose = closeHandler; this.webSocketInstance.onopen = openHandler; this.webSocketInstance.onmessage = messageHandler; this.webSocketInstance.onerror = errorHandler; } return this.webSocketInstance; } constructor(settings) { this.operations = new Map(); this.isTesting = false; this.wss = settings.url + parseQueryParams(settings.additionalQueryParams); this.defaultInterval = settings.interval ?? DEFAULT_SOCKET_INTERVAL; } open() { this.ws; } close() { if (!this.isClose() && !this.isClosing()) { this.ws.close(); clearInterval(this.reconnectInterval); } } addOperation(operationSetting) { const operation = this.findOperation(operationSetting.method); if (operation !== undefined && Array.isArray(operationSetting.handlers)) { this.addHandlers(operation, operationSetting.handlers); } else { const callback = () => { this.ws.send(JSON.stringify({ method: operationSetting.method, ...operationSetting.request() })); }; this.operations.set(operationSetting.method, { ...operationSetting, callback }); } this.open(); } removeOperation(method) { this.operations.delete(method); } removeHandler(method, handler) { const operation = this.findOperation(method); if (operation !== undefined && Array.isArray(operation?.handlers)) { const handlerIndex = operation.handlers.findIndex(existHandler => existHandler === handler); operation.handlers.splice(handlerIndex, 1); } } findOperation(method) { return this.operations.get(method); } addHandlers(operation, handlers) { if (!Array.isArray(operation.handlers)) { operation.handlers = []; } operation.handlers.push(...handlers); } onCloseHandler(event) { if (!event.wasClean) { this.reconnectInterval = setInterval(this.open, this.defaultInterval); } for (const operation of this.operations.values()) { if (this.isIntervaledOperation(operation)) { clearInterval(operation._interval); } } } onOpenHandler() { clearInterval(this.reconnectInterval); for (const operation of this.operations.values()) { this.pickOperationStrategy(operation); } } onMessageHandler(event) { const answer = JSON.parse(event.data); const operation = this.findOperation(answer.method); if (this.isValidWebSocketAnswer(answer) && operation !== undefined) { const { handlers } = operation; if (Array.isArray(handlers)) { handlers.forEach(handler => { handler(answer.data); }); } } } onErrorHandler(error) { this.close(); console.log(error); } pickOperationStrategy(operation) { if (this.isIntervaledOperation(operation)) { const interval = typeof operation.interval !== 'number' ? this.defaultInterval : operation.interval; operation._interval = setInterval(operation.callback, interval); } else { operation.callback(); } } isWebSocket(instance) { return instance instanceof WebSocket || this.isTesting; } isClosing() { return this.webSocketInstance?.readyState === WebSocket.CLOSING; } isClose() { return this.webSocketInstance?.readyState === WebSocket.CLOSED; } isOpen() { return this.webSocketInstance?.readyState === WebSocket.OPEN; } isIntervaledOperation(operation) { return 'interval' in operation; } isValidWebSocketAnswer(answer) { return typeof answer === 'object' && answer !== null && 'method' in answer; } } export default WebSocketManager; export const DEFAULT_SOCKET_INTERVAL = 3000; //# sourceMappingURL=websocket.js.map