UNPKG

@interopio/gateway-server

Version:

## `@glue42/gateway-ent` compatibility

91 lines (84 loc) 3.17 kB
import * as ws from 'ws'; import getLogger from '../../logger.js'; import {socketKey} from '../../utils.js'; import {HttpServerRequest} from '../../server/exchange.js'; import {IOGateway} from '@interopio/gateway'; import GatewayEncoders = IOGateway.Encoding; const log = getLogger('ws'); const codec = GatewayEncoders.json<IOGateway.Message>(); function initClient(this: IOGateway.Gateway, key: string, socket: ws.WebSocket, host?: string): IOGateway.GatewayClient<string> | undefined { const opts = { key, host, codec, onPing: () => { socket.ping((err?: Error) => { if (err) { log.warn(`failed to ping ${key}`, err); } else { log.info(`ping sent to ${key}`); } }); }, onDisconnect: (reason: 'inactive' | 'shutdown') => { switch (reason) { case 'inactive': { log.warn(`no heartbeat (ping) received from ${key}, closing socket`); socket.close(4001, 'ping expected'); break; } case 'shutdown': { socket.close(1001, 'shutdown'); break; } } } }; try { return this.client((data) => socket.send(data), opts); } catch (err) { log.warn(`${key} failed to create client`, err); } } async function create(this: IOGateway.Gateway, server: {endpoint: string, wss: ws.WebSocketServer}): Promise<{ close: () => Promise<void> }> { log.info('start gateway'); await this.start({endpoint: server.endpoint}); server.wss .on('error', (err: Error) => { log.error('error starting the gateway websocket server', err); }) .on('connection', (socket, req) => { const request = new HttpServerRequest(req); const key = socketKey(request.socket); const host = request.host; log.info(`${key} connected on gw from ${host}`); const client = initClient.call(this, key, socket); if (!client) { log.error(`${key} gw client init failed`); socket.terminate(); return; } socket.on('error', (err: Error) => { log.error(`${key} websocket error: ${err}`, err); }); socket.on('message', (data, _isBinary) => { if (Array.isArray(data)) { data = Buffer.concat(data); } // JSON.parse will invoke abstract operation ToString (coerce it) prior parsing (https://262.ecma-international.org/5.1/#sec-15.12.2) client.send(data as unknown as string); }); socket.on('close', (code) => { log.info(`${key} disconnected from gw. code: ${code}`); client.close(); }); }); return { close: async () => { server.wss.close(); await this.stop(); } } } export default create;