Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homework #1 #32

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions JavaScript/9-logger/api.di.container.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
common: Object.freeze({hash: require('./hash')}),
db: Object.freeze(require('./db')),
console: Object.freeze(require('./logger.di.container')),
};
5 changes: 4 additions & 1 deletion JavaScript/9-logger/api/city.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
db('city');
'use strict';
const {db} = require('../api.di.container');

module.exports = db('city');
24 changes: 14 additions & 10 deletions JavaScript/9-logger/api/country.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
'use strict';
const { db } = require('../api.di.container');
const { console } = require('../api.di.container');

const country = db('country');

({
async read(id) {
console.log({ db });
return await country.read(id);
},
module.exports = {
async read(id) {
console.log({ db });
return await country.read(id);
},

async find(mask) {
const sql = 'SELECT * from country where name like $1';
return await country.query(sql, [mask]);
},
});
async find(mask) {
const sql = 'SELECT * from country where name like $1';
return await country.query(sql, [mask]);
},
};
44 changes: 24 additions & 20 deletions JavaScript/9-logger/api/user.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
({
async read(id) {
return await db('users').read(id, ['id', 'login']);
},
'use strict';
const {db, common, console} = require('../api.di.container');

async create({ login, password }) {
const passwordHash = await common.hash(password);
return await db('users').create({ login, password: passwordHash });
},
module.exports = {
async read(id) {
return await db('users').read(id, ['id', 'login']);
},

async update(id, { login, password }) {
const passwordHash = await common.hash(password);
return await db('users').update(id, { login, password: passwordHash });
},
async create({login, password}) {
console.log({login});
const passwordHash = await common.hash(password);
return await db('users').create({login, password: passwordHash});
},

async delete(id) {
return await db('users').delete(id);
},
async update(id, {login, password}) {
const passwordHash = await common.hash(password);
return await db('users').update(id, {login, password: passwordHash});
},

async find(mask) {
const sql = 'SELECT login from users where login like $1';
return await db('users').query(sql, [mask]);
},
});
async delete(id) {
return await db('users').delete(id);
},

async find(mask) {
const sql = 'SELECT login from users where login like $1';
return await db('users').query(sql, [mask]);
},
};
10 changes: 10 additions & 0 deletions JavaScript/9-logger/body.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

const receiveArgs = async (req) => {
const buffers = [];
for await (const chunk of req) buffers.push(chunk);
const data = Buffer.concat(buffers).toString();
return JSON.parse(data);
};

module.exports = receiveArgs;
27 changes: 27 additions & 0 deletions JavaScript/9-logger/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module.exports = {
apiServer: {
/**
* @type {string} 'http' | 'ws'
*/
transport: 'http',
port: 3000,
},
staticServer: {
port: 8000,
},
crypto: {
saltLenByte: 16,
scryptLenByte: 64,
},
database: {
host: 'localhost',
port: 5432,
database: 'metatech',
user: 'admin',
password: 'admin',
},
/**
* @type {string} 'pino' | 'meta'
*/
logger: 'pino'
};
71 changes: 71 additions & 0 deletions JavaScript/9-logger/custom-logger.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
'use strict';

const fs = require('node:fs');
const util = require('node:util');
const path = require('node:path');

const COLORS = {
info: '\x1b[1;37m',
debug: '\x1b[1;33m',
error: '\x1b[0;31m',
system: '\x1b[1;34m',
access: '\x1b[1;38m',
};

const DATETIME_LENGTH = 19;

class Logger {
constructor(logPath) {
this.path = logPath;
const date = new Date().toISOString().substring(0, 10);
const filePath = path.join(logPath, `${date}.log`);
this.stream = fs.createWriteStream(filePath, { flags: 'a' });
this.regexp = new RegExp(path.dirname(this.path), 'g');
}

close() {
return new Promise((resolve) => this.stream.end(resolve));
}

write(type = 'info', s) {
const now = new Date().toISOString();
const date = now.substring(0, DATETIME_LENGTH);
const color = COLORS[type];
const line = date + '\t' + s;
console.log(color + line + '\x1b[0m');
const out = line.replace(/[\n\r]\s*/g, '; ') + '\n';
this.stream.write(out);
}

log(...args) {
const msg = util.format(...args);
this.write('info', msg);
}

dir(...args) {
const msg = util.inspect(...args);
this.write('info', msg);
}

debug(...args) {
const msg = util.format(...args);
this.write('debug', msg);
}

error(...args) {
const msg = util.format(...args).replace(/[\n\r]{2,}/g, '\n');
this.write('error', msg.replace(this.regexp, ''));
}

system(...args) {
const msg = util.format(...args);
this.write('system', msg);
}

access(...args) {
const msg = util.format(...args);
this.write('access', msg);
}
}

module.exports = new Logger('./log');
95 changes: 48 additions & 47 deletions JavaScript/9-logger/db.js
Original file line number Diff line number Diff line change
@@ -1,59 +1,60 @@
'use strict';

const pg = require('pg');
const config = require('./config');

const pool = new pg.Pool({
host: '127.0.0.1',
port: 5432,
database: 'example',
user: 'marcus',
password: 'marcus',
host: config.database.host,
port: config.database.port,
database: config.database.database,
user: config.database.user,
password: config.database.password,
});

module.exports = (table) => ({
async query(sql, args) {
return await pool.query(sql, args);
},
async query(sql, args) {
return await pool.query(sql, args);
},

async read(id, fields = ['*']) {
const names = fields.join(', ');
const sql = `SELECT ${names} FROM ${table}`;
if (!id) return pool.query(sql);
return await pool.query(`${sql} WHERE id = $1`, [id]);
},
async read(id, fields = ['*']) {
const names = fields.join(', ');
const sql = `SELECT ${names} FROM ${table}`;
if (!id) return pool.query(sql);
return await pool.query(`${sql} WHERE id = $1`, [id]);
},

async create({ ...record }) {
const keys = Object.keys(record);
const nums = new Array(keys.length);
const data = new Array(keys.length);
let i = 0;
for (const key of keys) {
data[i] = record[key];
nums[i] = `$${++i}`;
}
const fields = '"' + keys.join('", "') + '"';
const params = nums.join(', ');
const sql = `INSERT INTO "${table}" (${fields}) VALUES (${params})`;
return await pool.query(sql, data);
},
async create({ ...record }) {
const keys = Object.keys(record);
const nums = new Array(keys.length);
const data = new Array(keys.length);
let i = 0;
for (const key of keys) {
data[i] = record[key];
nums[i] = `$${++i}`;
}
const fields = '"' + keys.join('", "') + '"';
const params = nums.join(', ');
const sql = `INSERT INTO "${table}" (${fields}) VALUES (${params}) RETURNING id`;
return await pool.query(sql, data);
},

async update(id, { ...record }) {
const keys = Object.keys(record);
const updates = new Array(keys.length);
const data = new Array(keys.length);
let i = 0;
for (const key of keys) {
data[i] = record[key];
updates[i] = `${key} = $${++i}`;
}
const delta = updates.join(', ');
const sql = `UPDATE ${table} SET ${delta} WHERE id = $${++i}`;
data.push(id);
return await pool.query(sql, data);
},
async update(id, { ...record }) {
const keys = Object.keys(record);
const updates = new Array(keys.length);
const data = new Array(keys.length);
let i = 0;
for (const key of keys) {
data[i] = record[key];
updates[i] = `${key} = $${++i}`;
}
const delta = updates.join(', ');
const sql = `UPDATE ${table} SET ${delta} WHERE id = $${++i}`;
data.push(id);
return await pool.query(sql, data);
},

async delete(id) {
const sql = `DELETE FROM ${table} WHERE id = $1`;
return await pool.query(sql, [id]);
},
});
async delete(id) {
const sql = `DELETE FROM ${table} WHERE id = $1`;
return await pool.query(sql, [id]);
},
});
15 changes: 7 additions & 8 deletions JavaScript/9-logger/hash.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
'use strict';

const crypto = require('node:crypto');
const scrypt = require('node:util').promisify(crypto.scrypt);

const hash = (password) => new Promise((resolve, reject) => {
const salt = crypto.randomBytes(16).toString('base64');
crypto.scrypt(password, salt, 64, (err, result) => {
if (err) reject(err);
resolve(salt + ':' + result.toString('base64'));
});
});
const hash = async (password) => {
const salt = crypto.randomBytes(16).toString('base64');
const result = await scrypt(password, salt, 64);
return salt + ':' + result.toString('base64');
};

module.exports = hash;
module.exports = hash;
44 changes: 22 additions & 22 deletions JavaScript/9-logger/http.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,29 @@
const http = require('node:http');

const receiveArgs = async (req) => {
const buffers = [];
for await (const chunk of req) buffers.push(chunk);
const data = Buffer.concat(buffers).toString();
return JSON.parse(data);
const buffers = [];
for await (const chunk of req) buffers.push(chunk);
const data = Buffer.concat(buffers).toString();
return JSON.parse(data);
};

module.exports = (routing, port) => {
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 { 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);

console.log(`API on port ${port}`);
};
console.log(`Listen on port ${port}`);
};
Loading