From bd720c913f2d98a455974e0682547c582ca22f7e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 4 Dec 2023 07:08:50 +0000 Subject: [PATCH] switch to websockets for reading logs --- package-lock.json | 71 +++++++++++++++++++++++++++++++++++++++++------ package.json | 3 +- svc/web.mjs | 34 +++++++++-------------- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/package-lock.json b/package-lock.json index d86cb0b25..a07891749 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,7 +40,8 @@ "steam-resources": "github:odota/node-steam-resources", "stripe": "^9.12.0", "supertest": "^4.0.2", - "uuid": "^3.3.3" + "uuid": "^3.3.3", + "ws": "^8.14.2" }, "devDependencies": { "@apidevtools/swagger-parser": "^10.0.2", @@ -1392,6 +1393,26 @@ "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" }, + "node_modules/@pm2/agent/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@pm2/io": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@pm2/io/-/io-5.0.0.tgz", @@ -1453,6 +1474,26 @@ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" }, + "node_modules/@pm2/js-api/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@pm2/pm2-version-check": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@pm2/pm2-version-check/-/pm2-version-check-1.0.4.tgz", @@ -10907,15 +10948,15 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -12249,6 +12290,12 @@ "version": "1.8.36", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", "integrity": "sha512-3VmRXEtw7RZKAf+4Tv1Ym9AGeo8r8+CjDi26x+7SYQil1UqtqdaokhzoEJohqlzt0m5kacJSDhJQkG/LWhpRBw==" + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} } } }, @@ -12305,6 +12352,12 @@ "version": "6.4.9", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==" + }, + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} } } }, @@ -19682,9 +19735,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "requires": {} }, "xtend": { diff --git a/package.json b/package.json index b18f1aef0..99258c960 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,8 @@ "steam-resources": "github:odota/node-steam-resources", "stripe": "^9.12.0", "supertest": "^4.0.2", - "uuid": "^3.3.3" + "uuid": "^3.3.3", + "ws": "^8.14.2" }, "devDependencies": { "@apidevtools/swagger-parser": "^10.0.2", diff --git a/svc/web.mjs b/svc/web.mjs index 47e6f8f48..d2469393f 100644 --- a/svc/web.mjs +++ b/svc/web.mjs @@ -13,7 +13,7 @@ import cors from 'cors'; import bodyParser from 'body-parser'; import stripeLib from 'stripe'; import Redis from 'ioredis'; -import uuid from 'uuid'; +import { WebSocketServer } from 'ws'; import keys from '../routes/keyManagement.mjs'; import api from '../routes/api.mjs'; import queries from '../store/queries.mjs'; @@ -338,26 +338,6 @@ app.route('/manageSub').post(async (req, res) => { return res.json(session); }); app.use('/api', api); -const logReaders = {}; -const logSub = new Redis(config.REDIS_URL); -logSub.subscribe(['api', 'parsed', 'gcdata']); -logSub.on('message', (channel, message) => { - // Emit it to all the connected logs - Object.values(logReaders).forEach(([req, res]) => { - const matched = - Array.isArray(req.query.channel) && req.query.channel?.includes(channel); - if (!req.query.channel || req.query.channel === channel || matched) { - res.write(message + '\n'); - } - }); -}); -app.get('/logs', (req, res) => { - const id = uuid.v4(); - logReaders[id] = [req, res]; - req.on('close', () => { - delete logReaders[id]; - }); -}); // CORS Preflight for API keys // NB: make sure UI_HOST is set e.g. http://localhost:3000 otherwise CSRF check above will stop preflight from working app.options('/keys', cors()); @@ -385,6 +365,18 @@ const port = config.PORT || config.FRONTEND_PORT; const server = app.listen(port, () => { console.log('[WEB] listening on %s', port); }); +const wss = new WebSocketServer({ server }); +const logSub = new Redis(config.REDIS_URL); +logSub.subscribe(['api', 'parsed', 'gcdata']); +logSub.on('message', (channel, message) => { + // Emit it to all the connected websockets + // Can we let the user choose channels to sub to? + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(message); + } + }); +}); /** * Wait for connections to end, then shut down * */