From 9e894c45b4aca30a031a8f92d8b3de1c0d98ee59 Mon Sep 17 00:00:00 2001 From: Roman B Date: Thu, 1 Feb 2024 23:26:09 +0400 Subject: [PATCH 1/2] Adds configuration --- .prettierrc | 10 ++++++++++ JavaScript/9-logger/config.js | 14 ++++++++++++++ JavaScript/9-logger/db.js | 12 +++--------- JavaScript/9-logger/http.js | 2 +- JavaScript/9-logger/logger.js | 2 +- JavaScript/9-logger/main.js | 14 +++++++++----- JavaScript/9-logger/package.json | 3 +++ JavaScript/9-logger/static.js | 26 ++++++++++++++------------ JavaScript/9-logger/ws.js | 3 +-- 9 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 .prettierrc create mode 100644 JavaScript/9-logger/config.js diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..c43f7a3 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "singleQuote": true, + "trailingComma": "all", + "overrides": [ + { + "files": ["**/.*rc", "**/*.json"], + "options": { "parser": "json" } + } + ] +} diff --git a/JavaScript/9-logger/config.js b/JavaScript/9-logger/config.js new file mode 100644 index 0000000..adb268e --- /dev/null +++ b/JavaScript/9-logger/config.js @@ -0,0 +1,14 @@ +module.exports = { + transport: "http", // ws | http + apiPort: 8001, + staticPort: 8000, + staticPath: "./static", + logPath: "./log", + db: { + host: "127.0.0.1", + port: 5432, + database: "example", + user: "marcus", + password: "marcus", + }, +}; diff --git a/JavaScript/9-logger/db.js b/JavaScript/9-logger/db.js index afc5d04..5a4fd28 100644 --- a/JavaScript/9-logger/db.js +++ b/JavaScript/9-logger/db.js @@ -2,15 +2,7 @@ const pg = require('pg'); -const pool = new pg.Pool({ - host: '127.0.0.1', - port: 5432, - database: 'example', - user: 'marcus', - password: 'marcus', -}); - -module.exports = (table) => ({ +const createDBCrud = (pool) => (table) => ({ async query(sql, args) { return await pool.query(sql, args); }, @@ -57,3 +49,5 @@ module.exports = (table) => ({ return await pool.query(sql, [id]); }, }); + +module.exports = (poolOptions) => createDBCrud(new pg.Pool(poolOptions)); diff --git a/JavaScript/9-logger/http.js b/JavaScript/9-logger/http.js index 9f3f87f..f95a38a 100644 --- a/JavaScript/9-logger/http.js +++ b/JavaScript/9-logger/http.js @@ -9,7 +9,7 @@ const receiveArgs = async (req) => { return JSON.parse(data); }; -module.exports = (routing, port) => { +module.exports = (routing, port, console) => { http.createServer(async (req, res) => { const { url, socket } = req; const [name, method, id] = url.substring(1).split('/'); diff --git a/JavaScript/9-logger/logger.js b/JavaScript/9-logger/logger.js index d1006f2..3699d20 100644 --- a/JavaScript/9-logger/logger.js +++ b/JavaScript/9-logger/logger.js @@ -68,4 +68,4 @@ class Logger { } } -module.exports = new Logger('./log'); +module.exports = Logger; diff --git a/JavaScript/9-logger/main.js b/JavaScript/9-logger/main.js index 6e64123..59a9d0b 100644 --- a/JavaScript/9-logger/main.js +++ b/JavaScript/9-logger/main.js @@ -2,12 +2,16 @@ const fsp = require('node:fs').promises; const path = require('node:path'); -const server = require('./ws.js'); const staticServer = require('./static.js'); const load = require('./load.js'); -const db = require('./db.js'); +const createDbQueryConstructor = require('./db.js'); const hash = require('./hash.js'); -const logger = require('./logger.js'); +const Logger = require('./logger.js'); +const config = require('./config.js'); +const server = require(`./${config.transport}.js`); + +const logger = new Logger(config.logPath); +const db = createDbQueryConstructor(config.db); const sandbox = { console: Object.freeze(logger), @@ -26,6 +30,6 @@ const routing = {}; routing[serviceName] = await load(filePath, sandbox); } - staticServer('./static', 8000); - server(routing, 8001); + staticServer(config.staticPath, config.staticPort, logger); + server(routing, config.apiPort, logger); })(); diff --git a/JavaScript/9-logger/package.json b/JavaScript/9-logger/package.json index 6ba9eb5..3f2f30c 100644 --- a/JavaScript/9-logger/package.json +++ b/JavaScript/9-logger/package.json @@ -8,6 +8,9 @@ "engines": { "node": "14 || 16 || 18" }, + "scripts": { + "start": "node --experimental-vm-modules main.js" + }, "dependencies": { "pg": "^8.8.0", "ws": "^8.12.0" diff --git a/JavaScript/9-logger/static.js b/JavaScript/9-logger/static.js index 1bdb5ea..2973a20 100644 --- a/JavaScript/9-logger/static.js +++ b/JavaScript/9-logger/static.js @@ -4,18 +4,20 @@ const http = require('node:http'); const path = require('node:path'); const fs = require('node:fs'); -module.exports = (root, port) => { - http.createServer(async (req, res) => { - const url = req.url === '/' ? '/index.html' : req.url; - const filePath = path.join(root, url); - try { - const data = await fs.promises.readFile(filePath); - res.end(data); - } catch (err) { - res.statusCode = 404; - res.end('"File is not found"'); - } - }).listen(port); +module.exports = (root, port, console) => { + http + .createServer(async (req, res) => { + const url = req.url === '/' ? '/index.html' : req.url; + const filePath = path.join(root, url); + try { + const data = await fs.promises.readFile(filePath); + res.end(data); + } catch (err) { + res.statusCode = 404; + res.end('"File is not found"'); + } + }) + .listen(port); console.log(`Static on port ${port}`); }; diff --git a/JavaScript/9-logger/ws.js b/JavaScript/9-logger/ws.js index ad9cd74..5d740fa 100644 --- a/JavaScript/9-logger/ws.js +++ b/JavaScript/9-logger/ws.js @@ -1,9 +1,8 @@ 'use strict'; -const console = require('./logger.js'); const { Server } = require('ws'); -module.exports = (routing, port) => { +module.exports = (routing, port, console) => { const ws = new Server({ port }); ws.on('connection', (connection, req) => { From 3a02b6b06f1e9545ab744a39a3d818630bbeada7 Mon Sep 17 00:00:00 2001 From: Roman B Date: Thu, 1 Feb 2024 23:45:25 +0400 Subject: [PATCH 2/2] Implements client-side http transport * Adds support of node 20 to package.json --- JavaScript/9-logger/config.js | 14 +++--- JavaScript/9-logger/http.js | 49 ++++++++++++------ JavaScript/9-logger/package.json | 2 +- JavaScript/9-logger/static/client.js | 74 ++++++++++++++++++++++------ 4 files changed, 99 insertions(+), 40 deletions(-) diff --git a/JavaScript/9-logger/config.js b/JavaScript/9-logger/config.js index adb268e..3018cb8 100644 --- a/JavaScript/9-logger/config.js +++ b/JavaScript/9-logger/config.js @@ -1,14 +1,14 @@ module.exports = { - transport: "http", // ws | http + transport: 'ws', // ws | http apiPort: 8001, staticPort: 8000, - staticPath: "./static", - logPath: "./log", + staticPath: './static', + logPath: './log', db: { - host: "127.0.0.1", + host: '127.0.0.1', port: 5432, - database: "example", - user: "marcus", - password: "marcus", + database: 'example', + user: 'marcus', + password: 'marcus', }, }; diff --git a/JavaScript/9-logger/http.js b/JavaScript/9-logger/http.js index f95a38a..a22115a 100644 --- a/JavaScript/9-logger/http.js +++ b/JavaScript/9-logger/http.js @@ -2,6 +2,11 @@ const http = require('node:http'); +const answerNotFound = (res, headers) => { + res.writeHead(404, headers); + res.end('Not found'); +}; + const receiveArgs = async (req) => { const buffers = []; for await (const chunk of req) buffers.push(chunk); @@ -10,22 +15,34 @@ const receiveArgs = async (req) => { }; module.exports = (routing, port, console) => { - http.createServer(async (req, res) => { - const { url, socket } = req; - const [name, method, id] = url.substring(1).split('/'); - const entity = routing[name]; - if (!entity) return void res.end('Not found'); - const handler = entity[method]; - if (!handler) return void res.end('Not found'); - const src = handler.toString(); - const signature = src.substring(0, src.indexOf(')')); - const args = []; - if (signature.includes('(id')) args.push(id); - if (signature.includes('{')) args.push(await receiveArgs(req)); - console.log(`${socket.remoteAddress} ${method} ${url}`); - const result = await handler(...args); - res.end(JSON.stringify(result.rows)); - }).listen(port); + http + .createServer(async (req, res) => { + const headers = { + 'Access-Control-Allow-Origin': + '*' /* @dev First, read about security */, + 'Access-Control-Allow-Methods': 'POST', + 'Access-Control-Max-Age': 2592000, // 30 days + /** add other headers as per requirement */ + }; + + const { url, socket } = req; + const [name, method, id] = url.substring(1).split('/'); + const entity = routing[name]; + if (!entity) return void answerNotFound(res, headers); + const handler = entity[method]; + if (!handler) return void answerNotFound(res, headers); + + res.writeHead(200, headers); + const src = handler.toString(); + const signature = src.substring(0, src.indexOf(')')); + const args = []; + if (signature.includes('(id')) args.push(id); + args.push(...(await receiveArgs(req))); + console.log(`${socket.remoteAddress} ${req.method} ${url}`); + const result = await handler(...args); + res.end(JSON.stringify(result.rows)); + }) + .listen(port); console.log(`API on port ${port}`); }; diff --git a/JavaScript/9-logger/package.json b/JavaScript/9-logger/package.json index 3f2f30c..da770a7 100644 --- a/JavaScript/9-logger/package.json +++ b/JavaScript/9-logger/package.json @@ -6,7 +6,7 @@ "private": true, "main": "main.js", "engines": { - "node": "14 || 16 || 18" + "node": "14 || 16 || 18 || 20" }, "scripts": { "start": "node --experimental-vm-modules main.js" diff --git a/JavaScript/9-logger/static/client.js b/JavaScript/9-logger/static/client.js index 17e68c1..1421fef 100644 --- a/JavaScript/9-logger/static/client.js +++ b/JavaScript/9-logger/static/client.js @@ -1,8 +1,44 @@ 'use strict'; -const socket = new WebSocket('ws://127.0.0.1:8001/'); +const API_URL = 'ws://localhost:8001'; -const scaffold = (structure) => { +const getTransport = (url) => { + let socket; + const protocol = url.split(':')[0]; + + const transports = { + ws: (name, method) => { + if (!socket) socket = new WebSocket(url); + return (...args) => { + return new Promise((resolve) => { + const packet = { name, method, args }; + socket.send(JSON.stringify(packet)); + socket.onmessage = (event) => { + const data = JSON.parse(event.data); + resolve(data); + }; + }); + }; + }, + + http: + (name, method, methodArgs) => + (...args) => { + const urlParts = [url, name, method]; + if (methodArgs[0] === 'id') urlParts.push(args.shift()); + + return fetch(urlParts.join('/'), { + method: 'POST', + body: JSON.stringify(args), + }).then((response) => response.json()); + }, + }; + + return transports[protocol]; +}; + +const scaffold = (url, structure) => { + const transport = getTransport(url); const api = {}; const services = Object.keys(structure); for (const serviceName of services) { @@ -10,20 +46,17 @@ const scaffold = (structure) => { const service = structure[serviceName]; const methods = Object.keys(service); for (const methodName of methods) { - api[serviceName][methodName] = (...args) => new Promise((resolve) => { - const packet = { name: serviceName, method: methodName, args }; - socket.send(JSON.stringify(packet)); - socket.onmessage = (event) => { - const data = JSON.parse(event.data); - resolve(data); - }; - }); + api[serviceName][methodName] = transport( + serviceName, + methodName, + service[methodName], + ); } } return api; }; -const api = scaffold({ +const api = scaffold(API_URL, { user: { create: ['record'], read: ['id'], @@ -31,14 +64,23 @@ const api = scaffold({ delete: ['id'], find: ['mask'], }, + city: { + read: ['id'], + create: ['record'], + update: ['id', 'record'], + delete: ['id'], + }, country: { read: ['id'], + create: ['record'], + update: ['id', 'record'], delete: ['id'], - find: ['mask'], }, }); -socket.addEventListener('open', async () => { - const data = await api.user.read(3); - console.dir({ data }); -}); +// socket.addEventListener('open', async () => { +// const data = await api.user.read(3); +// console.dir({ data }); +// }); + +(async () => console.log(await api.user.read(3)))();