UNPKG

helene

Version:
145 lines 5.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WebSocketTransport = exports.WebSocketTransportEvents = void 0; const utils_1 = require("../../utils"); const socket_io_1 = require("socket.io"); const client_node_1 = require("../client-node"); var WebSocketTransportEvents; (function (WebSocketTransportEvents) { WebSocketTransportEvents["WEBSOCKET_SERVER_ERROR"] = "websocket:server:error"; })(WebSocketTransportEvents || (exports.WebSocketTransportEvents = WebSocketTransportEvents = {})); class WebSocketTransport { server; wss; options = { path: utils_1.HELENE_WS_PATH, }; constructor(server, origins, opts) { this.server = server; Object.assign(this.options, opts ?? {}); this.wss = new socket_io_1.Server(this.server.httpTransport.http, { ...this.options, connectionStateRecovery: { maxDisconnectionDuration: 2 * 60 * 1000, skipMiddlewares: true, ...this.options?.connectionStateRecovery, }, cors: { credentials: true, origin: origins ?? '*', ...this.options?.cors, }, }); this.wss.use((socket, next) => { if (!this.server.acceptConnections) { console.log('Helene: Connection Refused'); return next(new Error('Helene: Connection Refused')); } next(); }); this.wss.on(utils_1.WebSocketEvents.CONNECTION, this.handleConnection); this.wss.on(utils_1.WebSocketEvents.ERROR, (error) => server.emit(WebSocketTransportEvents.WEBSOCKET_SERVER_ERROR, error)); } handleConnection = (socket) => { const node = new client_node_1.ClientNode(this.server, socket, undefined, undefined, this.server.rateLimit); node.setId(socket.handshake.query.uuid); this.server.addClient(node); this.server.emit(utils_1.ServerEvents.CONNECTION, node); node.setTrackingProperties(socket); socket.on('disconnect', this.handleClose(node)); socket.on('error', (error) => this.server.emit(utils_1.ServerEvents.SOCKET_ERROR, socket, error)); socket.on('message', this.handleMessage(node)); }; handleClose = (node) => () => { node.close(); this.server.deleteClient(node); }; handleMessage = (node) => async (data) => { try { node.heartbeat.messageReceived(); const parsedData = utils_1.Presentation.decode(data); if (parsedData.type === utils_1.PayloadType.SETUP) { node.setId(parsedData.uuid); this.server.addClient(node); this.server.emit(utils_1.ServerEvents.CONNECTION, node); } if (parsedData.type !== utils_1.PayloadType.METHOD) return; await this.execute(parsedData, node); } catch (error) { return node.error({ message: utils_1.Errors.PARSE_ERROR, }); } }; async execute(payload, node) { if (node.limiter && !node.limiter.tryRemoveTokens(1)) { return node.error({ uuid: payload.uuid, message: utils_1.Errors.RATE_LIMIT_EXCEEDED, method: payload.method, }); } const uuid = payload?.uuid ? { uuid: payload.uuid } : null; const method = this.server.methods.get(payload.method); if (!method) return node.error({ uuid: payload.uuid, message: utils_1.Errors.METHOD_NOT_FOUND, method: payload.method, }); if (method.isProtected && !node.authenticated) return node.error({ uuid: payload.uuid, message: utils_1.Errors.METHOD_FORBIDDEN, method: payload.method, }); try { const methodPromise = method.exec(payload.params, node); if (payload.void) return; const response = await methodPromise; return node.result({ uuid: payload.uuid, method: payload.method, result: response, }); } catch (error) { console.error(error); if (payload.void) return; if (error instanceof utils_1.PublicError) { return node.error({ message: error.message, ...uuid, }); } if (error instanceof utils_1.SchemaValidationError) { return node.error({ message: error.message, errors: error.errors, ...uuid, }); } return node.error({ message: utils_1.Errors.INTERNAL_ERROR, ...uuid, }); } } close() { return new Promise(resolve => { if (!this.wss) return resolve(); this.server.allClients.forEach(node => { if (node.socket) node.close(); }); resolve(); }); } } exports.WebSocketTransport = WebSocketTransport; //# sourceMappingURL=websocket-transport.js.map