From 07ec570a647cab2960e63f6a158821fae9b6a68e Mon Sep 17 00:00:00 2001 From: Demian Parkhomenko <95881717+DemianParkhomenko@users.noreply.github.com> Date: Tue, 26 Sep 2023 21:54:27 +0300 Subject: [PATCH] Add framework config and Fastify WS --- config/index.js | 3 +- .../fastify.js => framework/fastify/http.js} | 15 +++----- lib/framework/fastify/start.js | 8 +++++ lib/framework/fastify/ws.js | 22 ++++++++++++ lib/{transport => framework}/headers.js | 0 lib/{transport => framework/native}/http.js | 3 +- lib/framework/native/ws.js | 14 ++++++++ lib/framework/ws-handler.js | 27 ++++++++++++++ lib/main.js | 19 +++++----- lib/transport/ws.js | 35 ------------------- package-lock.json | 10 ++++++ package.json | 1 + static/client.js | 2 +- 13 files changed, 100 insertions(+), 59 deletions(-) rename lib/{transport/fastify.js => framework/fastify/http.js} (80%) create mode 100644 lib/framework/fastify/start.js create mode 100644 lib/framework/fastify/ws.js rename lib/{transport => framework}/headers.js (100%) rename lib/{transport => framework/native}/http.js (91%) create mode 100644 lib/framework/native/ws.js create mode 100644 lib/framework/ws-handler.js delete mode 100644 lib/transport/ws.js diff --git a/config/index.js b/config/index.js index 654cebc..53f7fcb 100644 --- a/config/index.js +++ b/config/index.js @@ -5,7 +5,8 @@ module.exports = { api: { path: './api', port: 8001, - transport: 'ws', + framework: 'native', + transport: 'http', }, static: { port: 8000, diff --git a/lib/transport/fastify.js b/lib/framework/fastify/http.js similarity index 80% rename from lib/transport/fastify.js rename to lib/framework/fastify/http.js index bd9cba7..1423f5a 100644 --- a/lib/transport/fastify.js +++ b/lib/framework/fastify/http.js @@ -2,7 +2,8 @@ const fastify = require('fastify')({ logger: false, }); const cors = require('@fastify/cors'); -const { HEADERS } = require('./headers.js'); +const { HEADERS } = require('../headers.js'); +const start = require('./start.js'); const setup = async (routing) => { const services = Object.keys(routing); @@ -23,17 +24,9 @@ const setup = async (routing) => { } }; -const start = async (port) => { - try { - await fastify.listen({ port }); - } catch (err) { - fastify.log.error(err); - process.exit(1); - } -}; - module.exports = async (routing, port) => { await fastify.register(cors, HEADERS); await setup(routing); - await start(port); + await start(fastify, port, console); + console.log('Fastify HTTP 🔌'); }; diff --git a/lib/framework/fastify/start.js b/lib/framework/fastify/start.js new file mode 100644 index 0000000..bbd55e6 --- /dev/null +++ b/lib/framework/fastify/start.js @@ -0,0 +1,8 @@ +module.exports = async (fastify, port, console) => { + try { + await fastify.listen({ port }); + } catch (err) { + console.error(err); + process.exit(1); + } +}; diff --git a/lib/framework/fastify/ws.js b/lib/framework/fastify/ws.js new file mode 100644 index 0000000..79b83f1 --- /dev/null +++ b/lib/framework/fastify/ws.js @@ -0,0 +1,22 @@ +'use strict'; + +const fastify = require('fastify')(); +const start = require('./start.js'); +const handler = require('../ws-handler.js'); + +const setup = async (routing) => { + fastify.register(async (fastify) => { + fastify.get('*', { websocket: true }, ({ socket }) => { + socket.on('message', (message) => + handler({ routing, socket, console, message }) + ); + }); + }); +}; + +module.exports = async (routing, port, console) => { + fastify.register(require('@fastify/websocket')); + await setup(routing); + await start(fastify, port, console); + console.log('🔌 Fastify WS'); +}; diff --git a/lib/transport/headers.js b/lib/framework/headers.js similarity index 100% rename from lib/transport/headers.js rename to lib/framework/headers.js diff --git a/lib/transport/http.js b/lib/framework/native/http.js similarity index 91% rename from lib/transport/http.js rename to lib/framework/native/http.js index 16bbbc7..fcb2707 100644 --- a/lib/transport/http.js +++ b/lib/framework/native/http.js @@ -1,7 +1,7 @@ 'use strict'; const http = require('node:http'); -const { HEADERS } = require('./headers.js'); +const { HEADERS } = require('../headers.js'); const parseBody = async (req) => { const buffer = []; @@ -27,4 +27,5 @@ module.exports = (routing, port, console) => { res.end(JSON.stringify(result)); }) .listen(port); + console.log('Native HTTP 🔌'); }; diff --git a/lib/framework/native/ws.js b/lib/framework/native/ws.js new file mode 100644 index 0000000..e168b8a --- /dev/null +++ b/lib/framework/native/ws.js @@ -0,0 +1,14 @@ +'use strict'; + +const { Server } = require('ws'); +const handler = require('../ws-handler.js'); + +module.exports = (routing, port, console) => { + const ws = new Server({ port }); + ws.on('connection', (socket) => { + socket.on('message', async (message) => + handler({ routing, socket, console, message }) + ); + }); + console.log('🔌 Native WS'); +}; diff --git a/lib/framework/ws-handler.js b/lib/framework/ws-handler.js new file mode 100644 index 0000000..bd616ae --- /dev/null +++ b/lib/framework/ws-handler.js @@ -0,0 +1,27 @@ +const handler = async ({ routing, socket, console, message }) => { + const send = (result) => { + socket.send(JSON.stringify(result), { binary: false }); + }; + const obj = JSON.parse(message); + const { name, method, args = [] } = obj; + const entity = routing[name]; + if (!entity) { + send({ error: 'Entity not found' }); + return; + } + const handler = entity[method]; + if (!handler) { + send({ error: 'Handler hot found' }); + return; + } + try { + const result = await handler(...args); + send(result); + } catch (err) { + console.error(err); + send({ error: 'Server error' }); + } +}; + +// TODO: unify and create http-handler.js +module.exports = handler; diff --git a/lib/main.js b/lib/main.js index ee0df50..3495b65 100644 --- a/lib/main.js +++ b/lib/main.js @@ -4,23 +4,22 @@ const fsp = require('node:fs/promises'); const path = require('node:path'); const config = require('../config/index.js'); const crud = require('./db/crud.js'); -const load = require('./utils/load.js')(config.sandbox); const deepFreeze = require('./utils/freeze.js'); const staticServer = require('./static/server.js'); -const server = require(`./transport/${config.api.transport}.js`); -const console = require(`./logger/${config.logger.name}.js`)(config.logger); -console.info(`📝 Logger ${config.logger.name} started`); +const server = require( + `./framework/${config.api.framework}/${config.api.transport}.js` +); +const load = require('./utils/load.js')(config.sandbox); +const logger = require(`./logger/${config.logger.name}.js`); const startDb = require('./db/start.js'); const start = async () => { + const console = logger(config.logger); + console.info(`📝 Logger ${config.logger.name} started`); const db = await startDb(config.db); console.info('✅ Connected to database'); - const sandbox = { - console: deepFreeze(console), - //? Can not be frozen because of prisma - db, - crud: deepFreeze(crud), - }; + //? Db can not be frozen because of Prisma + const sandbox = { console: deepFreeze(console), db, crud: deepFreeze(crud) }; const apiPath = path.join(process.cwd(), config.api.path); const routing = {}; const files = await fsp.readdir(apiPath); diff --git a/lib/transport/ws.js b/lib/transport/ws.js deleted file mode 100644 index 5528bc0..0000000 --- a/lib/transport/ws.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -const { Server } = require('ws'); - -module.exports = (routing, port, console) => { - const ws = new Server({ port }); - - ws.on('connection', (connection, req) => { - const ip = req.socket.remoteAddress; - connection.on('message', async (message) => { - const obj = JSON.parse(message); - const { name, method, args = [] } = obj; - const entity = routing[name]; - if (!entity) { - connection.send('"Not found"', { binary: false }); - return; - } - const handler = entity[method]; - if (!handler) { - connection.send('"Not found"', { binary: false }); - return; - } - const json = JSON.stringify(args); - const parameters = json.substring(1, json.length - 1); - console.log(`${ip} ${name}.${method}(${parameters})`); - try { - const result = await handler(...args); - connection.send(JSON.stringify(result), { binary: false }); - } catch (err) { - console.error(err); - connection.send('"Server error"', { binary: false }); - } - }); - }); -}; diff --git a/package-lock.json b/package-lock.json index bdd215a..5baf36c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@fastify/cors": "^8.3.0", + "@fastify/websocket": "^8.2.0", "@prisma/client": "^5.3.1", "fastify": "^4.23.2", "pg": "^8.8.0", @@ -170,6 +171,15 @@ "fast-json-stringify": "^5.7.0" } }, + "node_modules/@fastify/websocket": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@fastify/websocket/-/websocket-8.2.0.tgz", + "integrity": "sha512-B4tlHFBKCX7tenEG9aUcQEpksW2e0+dgRTaH/05+cro1Xsq1+kSj+9IB9Gep7a0KbHZGrat+zBsOas6lRs5dFQ==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "ws": "^8.0.0" + } + }, "node_modules/@flydotio/dockerfile": { "version": "0.4.10", "resolved": "https://registry.npmjs.org/@flydotio/dockerfile/-/dockerfile-0.4.10.tgz", diff --git a/package.json b/package.json index 5456e74..60b7785 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "license": "MIT", "dependencies": { "@fastify/cors": "^8.3.0", + "@fastify/websocket": "^8.2.0", "@prisma/client": "^5.3.1", "fastify": "^4.23.2", "pg": "^8.8.0", diff --git a/static/client.js b/static/client.js index 654544c..88e127e 100644 --- a/static/client.js +++ b/static/client.js @@ -1,6 +1,6 @@ 'use strict'; -const url = new URL('ws://localhost:8001'); +const url = new URL('http://localhost:8001'); const structure = { user: { create: ['record'],