├── ch2 ├── part5 │ ├── db │ │ ├── dumps │ │ │ └── .gitkeep │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── README.md │ ├── controllers │ │ ├── ping.js │ │ ├── addAlias.js │ │ └── resolveAlias.js │ ├── config │ │ └── index.js │ ├── middlewares │ │ ├── notFound.js │ │ ├── errorHandler.js │ │ └── accessLogs.js │ ├── utils │ │ ├── getDatabaseFilePath.js │ │ ├── dumpDatabase.js │ │ └── compressFile.js │ ├── modules │ │ └── error.js │ ├── services │ │ └── links.js │ └── server.js ├── part6 │ ├── db │ │ ├── dumps │ │ │ └── .gitkeep │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── controllers │ │ ├── ping.js │ │ ├── addAlias.js │ │ └── resolveAlias.js │ ├── README.md │ ├── config │ │ └── index.js │ ├── middlewares │ │ ├── notFound.js │ │ ├── errorHandler.js │ │ └── accessLogs.js │ ├── utils │ │ ├── getDatabaseFilePath.js │ │ ├── dumpDatabase.js │ │ ├── compressFile.js │ │ └── monitorProcess.js │ ├── modules │ │ └── error.js │ ├── services │ │ └── links.js │ └── server.js ├── part7 │ ├── db │ │ ├── dumps │ │ │ └── .gitkeep │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── README.md │ ├── controllers │ │ ├── ping.js │ │ ├── addAlias.js │ │ └── resolveAlias.js │ ├── config │ │ └── index.js │ ├── middlewares │ │ ├── disablePoweredBy.js │ │ ├── notFound.js │ │ ├── errorHandler.js │ │ ├── accessLogs.js │ │ └── security.js │ ├── utils │ │ ├── getDatabaseFilePath.js │ │ ├── dumpDatabase.js │ │ ├── compressFile.js │ │ └── monitorProcess.js │ ├── modules │ │ └── error.js │ ├── services │ │ └── links.js │ └── server.js ├── part8 │ ├── server │ │ ├── db │ │ │ ├── dumps │ │ │ │ └── .gitkeep │ │ │ ├── links.dev.json │ │ │ └── links.prod.json │ │ ├── README.md │ │ ├── controllers │ │ │ ├── ping.js │ │ │ ├── addAlias.js │ │ │ └── resolveAlias.js │ │ ├── config │ │ │ └── index.js │ │ ├── middlewares │ │ │ ├── disablePoweredBy.js │ │ │ ├── notFound.js │ │ │ ├── errorHandler.js │ │ │ ├── accessLogs.js │ │ │ └── security.js │ │ ├── utils │ │ │ ├── getDatabaseFilePath.js │ │ │ ├── dumpDatabase.js │ │ │ ├── compressFile.js │ │ │ └── monitorProcess.js │ │ ├── modules │ │ │ └── error.js │ │ ├── services │ │ │ └── links.js │ │ └── server.js │ └── client │ │ ├── src │ │ ├── vite-env.d.ts │ │ ├── index.css │ │ ├── main.tsx │ │ └── App.tsx │ │ ├── tsconfig.node.json │ │ ├── vite.config.ts │ │ ├── dist │ │ ├── assets │ │ │ └── index.99fc237d.css │ │ └── index.html │ │ ├── index.html │ │ ├── .gitignore │ │ ├── tsconfig.json │ │ └── package.json ├── part9 │ ├── server │ │ ├── db │ │ │ ├── dumps │ │ │ │ └── .gitkeep │ │ │ ├── links.dev.json │ │ │ └── links.prod.json │ │ ├── README.md │ │ ├── controllers │ │ │ ├── ping.js │ │ │ ├── addAlias.js │ │ │ └── resolveAlias.js │ │ ├── config │ │ │ └── index.js │ │ ├── middlewares │ │ │ ├── disablePoweredBy.js │ │ │ ├── notFound.js │ │ │ ├── errorHandler.js │ │ │ ├── accessLogs.js │ │ │ └── security.js │ │ ├── utils │ │ │ ├── getDatabaseFilePath.js │ │ │ ├── dumpDatabase.js │ │ │ ├── compressFile.js │ │ │ └── monitorProcess.js │ │ ├── modules │ │ │ ├── error.js │ │ │ └── wsClients.js │ │ ├── ws.js │ │ ├── services │ │ │ └── links.js │ │ └── server.js │ └── client │ │ ├── src │ │ ├── vite-env.d.ts │ │ ├── index.css │ │ ├── main.tsx │ │ ├── Online.tsx │ │ └── Home.tsx │ │ ├── tsconfig.node.json │ │ ├── vite.config.ts │ │ ├── dist │ │ ├── assets │ │ │ └── index.99fc237d.css │ │ └── index.html │ │ ├── index.html │ │ ├── .gitignore │ │ ├── tsconfig.json │ │ └── package.json ├── part1 │ ├── README.md │ ├── controllers │ │ ├── ping.js │ │ └── resolveAlias.js │ ├── config │ │ └── index.js │ ├── db │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── middlewares │ │ ├── urlLogger.js │ │ └── notFound.js │ ├── services │ │ └── links.js │ └── server.js ├── part4 │ ├── README.md │ ├── controllers │ │ ├── ping.js │ │ ├── addAlias.js │ │ └── resolveAlias.js │ ├── config │ │ └── index.js │ ├── middlewares │ │ ├── notFound.js │ │ ├── errorHandler.js │ │ └── accessLogs.js │ ├── db │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── modules │ │ └── error.js │ ├── server.js │ └── services │ │ └── links.js ├── part2 │ ├── controllers │ │ ├── ping.js │ │ ├── addAlias.js │ │ └── resolveAlias.js │ ├── README.md │ ├── config │ │ └── index.js │ ├── middlewares │ │ ├── urlLogger.js │ │ └── notFound.js │ ├── db │ │ ├── links.dev.json │ │ └── links.prod.json │ ├── server.js │ └── services │ │ └── links.js └── part3 │ ├── controllers │ ├── ping.js │ ├── addAlias.js │ └── resolveAlias.js │ ├── README.md │ ├── config │ └── index.js │ ├── middlewares │ ├── urlLogger.js │ ├── notFound.js │ └── errorHandler.js │ ├── db │ ├── links.dev.json │ └── links.prod.json │ ├── modules │ └── error.js │ ├── server.js │ └── services │ └── links.js ├── ch1 ├── part1 │ ├── README.md │ └── script.js ├── part3 │ ├── README.md │ └── script.js ├── part4 │ ├── README.md │ ├── links.dev.txt │ ├── script.js │ └── links.prod.txt ├── part5 │ ├── README.md │ ├── links.dev.txt │ ├── script.js │ └── links.prod.txt └── part2 │ ├── README.md │ └── script.js ├── .gitignore └── package.json /ch2/part5/db/dumps/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch2/part6/db/dumps/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch2/part7/db/dumps/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch2/part8/server/db/dumps/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch2/part9/server/db/dumps/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ch1/part1/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node script.js 3 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | *.logs 4 | **/db/dumps/*.gz 5 | .DS_Store -------------------------------------------------------------------------------- /ch2/part8/client/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch2/part9/client/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ch2/part1/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node server.js 3 | 4 | NODE_ENV=production node server.js 5 | ``` -------------------------------------------------------------------------------- /ch1/part3/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node script.js map 3 | 4 | LINKS_TYPE=prod node script.js map 5 | ``` -------------------------------------------------------------------------------- /ch1/part4/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node script.js map 3 | 4 | LINKS_TYPE=prod node script.js map 5 | ``` -------------------------------------------------------------------------------- /ch1/part5/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node script.js map 3 | 4 | NODE_ENV=production node script.js map 5 | ``` -------------------------------------------------------------------------------- /ch2/part7/README.md: -------------------------------------------------------------------------------- 1 | Security 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch2/part8/server/README.md: -------------------------------------------------------------------------------- 1 | Interface 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch2/part9/server/README.md: -------------------------------------------------------------------------------- 1 | Interface 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch1/part4/links.dev.txt: -------------------------------------------------------------------------------- 1 | music https://music.yandex.ru 2 | map https://yandex.ru/maps 3 | tr https://translate.yandex.ru -------------------------------------------------------------------------------- /ch1/part5/links.dev.txt: -------------------------------------------------------------------------------- 1 | music https://music.yandex.ru 2 | map https://yandex.ru/maps 3 | tr https://translate.yandex.ru -------------------------------------------------------------------------------- /ch2/part4/README.md: -------------------------------------------------------------------------------- 1 | Добавить логирование 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch2/part5/README.md: -------------------------------------------------------------------------------- 1 | Добавить логирование 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch1/part2/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | node script.js 3 | 4 | LINKS_TYPE=dev node script.js 5 | 6 | LINKS_TYPE=prod node script.js 7 | ``` -------------------------------------------------------------------------------- /ch2/part1/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part2/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part3/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part4/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part5/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part6/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part7/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part2/README.md: -------------------------------------------------------------------------------- 1 | Добавить POST запрос на добавление нового URL в БД 2 | 3 | ``` 4 | node server.js 5 | 6 | NODE_ENV=production node server.js 7 | ``` -------------------------------------------------------------------------------- /ch2/part3/README.md: -------------------------------------------------------------------------------- 1 | Добавить POST запрос на добавление нового URL в БД 2 | 3 | ``` 4 | node server.js 5 | 6 | NODE_ENV=production node server.js 7 | ``` -------------------------------------------------------------------------------- /ch2/part6/README.md: -------------------------------------------------------------------------------- 1 | Мониторинг нагрузки на процессор и потребляемой памяти 2 | 3 | ``` 4 | node server 5 | 6 | NODE_ENV=production node server 7 | ``` -------------------------------------------------------------------------------- /ch2/part8/server/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part9/server/controllers/ping.js: -------------------------------------------------------------------------------- 1 | function ping(request, response) { 2 | return response.send('pong'); 3 | } 4 | 5 | module.exports = { ping }; -------------------------------------------------------------------------------- /ch2/part1/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part1/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru" 5 | } 6 | -------------------------------------------------------------------------------- /ch2/part2/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part3/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part4/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part5/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part6/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part7/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part8/server/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part9/server/config/index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const dbPath = path.resolve(__dirname, '../db'); 4 | 5 | module.exports = { 6 | dbPath, 7 | }; -------------------------------------------------------------------------------- /ch2/part1/middlewares/urlLogger.js: -------------------------------------------------------------------------------- 1 | function urlLogger(request, response, next) { 2 | console.log(request.originalUrl); 3 | 4 | next(); 5 | } 6 | 7 | module.exports = { urlLogger }; 8 | -------------------------------------------------------------------------------- /ch2/part2/middlewares/urlLogger.js: -------------------------------------------------------------------------------- 1 | function urlLogger(request, response, next) { 2 | console.log(request.originalUrl); 3 | 4 | next(); 5 | } 6 | 7 | module.exports = { urlLogger }; 8 | -------------------------------------------------------------------------------- /ch2/part3/middlewares/urlLogger.js: -------------------------------------------------------------------------------- 1 | function urlLogger(request, response, next) { 2 | console.log(request.originalUrl); 3 | 4 | next(); 5 | } 6 | 7 | module.exports = { urlLogger }; 8 | -------------------------------------------------------------------------------- /ch2/part7/middlewares/disablePoweredBy.js: -------------------------------------------------------------------------------- 1 | function disablePoweredBy(request, response, next) { 2 | response.removeHeader("X-Powered-By"); 3 | 4 | next(); 5 | }; 6 | 7 | module.exports = { disablePoweredBy }; -------------------------------------------------------------------------------- /ch2/part2/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat" 6 | } -------------------------------------------------------------------------------- /ch2/part3/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat" 6 | } -------------------------------------------------------------------------------- /ch2/part1/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part2/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part3/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part4/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part5/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part6/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part7/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part8/server/middlewares/disablePoweredBy.js: -------------------------------------------------------------------------------- 1 | function disablePoweredBy(request, response, next) { 2 | response.removeHeader("X-Powered-By"); 3 | 4 | next(); 5 | }; 6 | 7 | module.exports = { disablePoweredBy }; -------------------------------------------------------------------------------- /ch2/part9/server/middlewares/disablePoweredBy.js: -------------------------------------------------------------------------------- 1 | function disablePoweredBy(request, response, next) { 2 | response.removeHeader("X-Powered-By"); 3 | 4 | next(); 5 | }; 6 | 7 | module.exports = { disablePoweredBy }; -------------------------------------------------------------------------------- /ch2/part8/server/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part9/server/middlewares/notFound.js: -------------------------------------------------------------------------------- 1 | async function notFound(request, response) { 2 | response.status(404); 3 | 4 | return response.send({ messageId: "page-not-found" }); 5 | } 6 | 7 | module.exports = { notFound }; 8 | -------------------------------------------------------------------------------- /ch2/part8/client/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /ch2/part9/client/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /ch2/part8/client/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 3001 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /ch2/part9/client/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | server: { 8 | port: 3001 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /ch2/part3/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part4/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part5/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part6/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part7/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part8/server/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part9/server/middlewares/errorHandler.js: -------------------------------------------------------------------------------- 1 | async function errorHandler(error, request, response, next) { 2 | console.log(error); 3 | 4 | response.status(error.status || 500).send({ 5 | status: "error", 6 | message: error.message, 7 | }); 8 | } 9 | 10 | module.exports = { errorHandler }; 11 | -------------------------------------------------------------------------------- /ch2/part8/client/dist/assets/index.99fc237d.css: -------------------------------------------------------------------------------- 1 | :root{font-family:Inter,Avenir,Helvetica,Arial,sans-serif;font-size:16px;line-height:24px;font-weight:400;color-scheme:light;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%} 2 | -------------------------------------------------------------------------------- /ch2/part9/client/dist/assets/index.99fc237d.css: -------------------------------------------------------------------------------- 1 | :root{font-family:Inter,Avenir,Helvetica,Arial,sans-serif;font-size:16px;line-height:24px;font-weight:400;color-scheme:light;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%} 2 | -------------------------------------------------------------------------------- /ch2/part2/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response) { 4 | const { alias, link } = request.body; 5 | 6 | await linksService.addAlias(alias, link); 7 | 8 | return response.send({ status: 'success' }); 9 | } 10 | 11 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part8/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shortener 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch2/part9/client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shortener 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ch2/part8/client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist-ssr 12 | *.local 13 | 14 | # Editor directories and files 15 | .vscode/* 16 | !.vscode/extensions.json 17 | .idea 18 | .DS_Store 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /ch2/part9/client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist-ssr 12 | *.local 13 | 14 | # Editor directories and files 15 | .vscode/* 16 | !.vscode/extensions.json 17 | .idea 18 | .DS_Store 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /ch2/part8/client/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light; 8 | 9 | font-synthesis: none; 10 | text-rendering: optimizeLegibility; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | -webkit-text-size-adjust: 100%; 14 | } 15 | -------------------------------------------------------------------------------- /ch2/part9/client/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, Avenir, Helvetica, Arial, sans-serif; 3 | font-size: 16px; 4 | line-height: 24px; 5 | font-weight: 400; 6 | 7 | color-scheme: light; 8 | 9 | font-synthesis: none; 10 | text-rendering: optimizeLegibility; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | -webkit-text-size-adjust: 100%; 14 | } 15 | -------------------------------------------------------------------------------- /ch2/part8/client/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import { ChakraProvider } from '@chakra-ui/react' 4 | import App from './App' 5 | import './index.css' 6 | 7 | ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render( 8 | 9 | 10 | 11 | 12 | 13 | ) 14 | -------------------------------------------------------------------------------- /ch2/part3/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part4/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part5/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part6/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part7/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part8/server/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part9/server/controllers/addAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function addAlias(request, response, next) { 4 | try { 5 | const { alias, link } = request.body; 6 | 7 | await linksService.addAlias(alias, link); 8 | 9 | return response.send({ status: 'success' }); 10 | } catch (err) { 11 | next(err); 12 | } 13 | } 14 | 15 | module.exports = { addAlias }; -------------------------------------------------------------------------------- /ch2/part4/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.logs"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part5/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.logs"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part6/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.log"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part7/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.log"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part8/server/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.log"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part9/server/middlewares/accessLogs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const morgan = require("morgan"); 4 | 5 | function accessLogs(toFile = false) { 6 | return morgan(":method :url - :status :response-time ms", { 7 | stream: toFile 8 | ? fs.createWriteStream(path.resolve(__dirname, "../access.log"), { flags: 'a' }) 9 | : undefined, 10 | }); 11 | } 12 | 13 | module.exports = { accessLogs }; 14 | -------------------------------------------------------------------------------- /ch2/part5/utils/getDatabaseFilePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | function getDatabaseFilePath() { 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | return process.env.LINKS_TYPE === "prod" 10 | ? linksProdFilePath 11 | : linksDevFilePath; 12 | } 13 | 14 | module.exports = { getDatabaseFilePath }; -------------------------------------------------------------------------------- /ch2/part6/utils/getDatabaseFilePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | function getDatabaseFilePath() { 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | return process.env.LINKS_TYPE === "prod" 10 | ? linksProdFilePath 11 | : linksDevFilePath; 12 | } 13 | 14 | module.exports = { getDatabaseFilePath }; -------------------------------------------------------------------------------- /ch2/part7/utils/getDatabaseFilePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | function getDatabaseFilePath() { 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | return process.env.LINKS_TYPE === "prod" 10 | ? linksProdFilePath 11 | : linksDevFilePath; 12 | } 13 | 14 | module.exports = { getDatabaseFilePath }; -------------------------------------------------------------------------------- /ch2/part8/client/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shortener 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch2/part8/server/utils/getDatabaseFilePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | function getDatabaseFilePath() { 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | return process.env.LINKS_TYPE === "prod" 10 | ? linksProdFilePath 11 | : linksDevFilePath; 12 | } 13 | 14 | module.exports = { getDatabaseFilePath }; -------------------------------------------------------------------------------- /ch2/part9/client/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Shortener 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ch2/part9/server/utils/getDatabaseFilePath.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | function getDatabaseFilePath() { 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | return process.env.LINKS_TYPE === "prod" 10 | ? linksProdFilePath 11 | : linksDevFilePath; 12 | } 13 | 14 | module.exports = { getDatabaseFilePath }; -------------------------------------------------------------------------------- /ch2/part4/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat" 11 | } -------------------------------------------------------------------------------- /ch2/part5/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat" 11 | } -------------------------------------------------------------------------------- /ch2/part6/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat" 11 | } -------------------------------------------------------------------------------- /ch2/part7/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat" 11 | } -------------------------------------------------------------------------------- /ch2/part3/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | this.status = status; 4 | this.message = message; 5 | } 6 | } 7 | 8 | class BadRequestError extends BaseError { 9 | constructor(message) { 10 | super(400, message); 11 | } 12 | } 13 | 14 | class NotFoundError extends BaseError { 15 | constructor(message) { 16 | super(404, message); 17 | } 18 | } 19 | 20 | module.exports = { 21 | BadRequestError, 22 | NotFoundError 23 | }; -------------------------------------------------------------------------------- /ch2/part4/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part5/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part6/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part7/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part8/server/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part9/server/modules/error.js: -------------------------------------------------------------------------------- 1 | class BaseError extends Error { 2 | constructor(status, message) { 3 | super(message); 4 | 5 | this.status = status; 6 | } 7 | } 8 | 9 | class BadRequestError extends BaseError { 10 | constructor(message) { 11 | super(400, message); 12 | } 13 | } 14 | 15 | class NotFoundError extends BaseError { 16 | constructor(message) { 17 | super(404, message); 18 | } 19 | } 20 | 21 | module.exports = { 22 | BadRequestError, 23 | NotFoundError 24 | }; -------------------------------------------------------------------------------- /ch2/part1/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { getByAlias } = require("../services/links"); 2 | 3 | async function resolveAlias(request, response, next) { 4 | const { alias } = request.params; 5 | 6 | const longLink = await getByAlias(alias); 7 | 8 | if (!longLink) { 9 | return next(); 10 | } 11 | 12 | if (process.env.NODE_ENV === 'production') { 13 | response.redirect(302, longLink); 14 | } else { 15 | response.send(longLink); 16 | } 17 | } 18 | 19 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part2/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const linksService = require("../services/links"); 2 | 3 | async function resolveAlias(request, response, next) { 4 | const { alias } = request.params; 5 | 6 | const longLink = await linksService.getByAlias(alias); 7 | 8 | if (!longLink) { 9 | return next(); 10 | } 11 | 12 | if (process.env.NODE_ENV === 'production') { 13 | response.redirect(302, longLink); 14 | } else { 15 | response.send(longLink); 16 | } 17 | } 18 | 19 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part1/services/links.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const { dbPath } = require("../config"); 4 | 5 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 6 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 7 | 8 | const linksFilePath = 9 | process.env.LINKS_TYPE === "prod" ? linksProdFilePath : linksDevFilePath; 10 | 11 | async function getByAlias(alias) { 12 | const links = require(linksFilePath); 13 | 14 | return links[alias]; 15 | } 16 | 17 | module.exports = { 18 | getByAlias, 19 | }; 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parts", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "express": "^4.18.1", 15 | "express-rate-limit": "^6.5.1", 16 | "express-slow-down": "^1.4.0", 17 | "helmet": "^5.1.1", 18 | "http-proxy-middleware": "^2.0.6", 19 | "morgan": "^1.10.0", 20 | "ws": "^8.8.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ch2/part1/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { ping } = require("./controllers/ping"); 5 | const { notFound } = require("./middlewares/notFound"); 6 | const { urlLogger } = require("./middlewares/urlLogger"); 7 | 8 | const app = express(); 9 | 10 | app.use(urlLogger); 11 | 12 | app.get("/ping", ping); 13 | app.get("/:alias", resolveAlias); 14 | 15 | app.use(notFound); 16 | 17 | const PORT = 3000; 18 | 19 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 20 | -------------------------------------------------------------------------------- /ch2/part9/server/ws.js: -------------------------------------------------------------------------------- 1 | const WebSocket = require('ws'); 2 | const { wsClients } = require('./modules/wsClients'); 3 | 4 | function upgradeWithWs(server) { 5 | const wsServer = new WebSocket.Server({ server }); 6 | 7 | wsServer.on('connection', async (ws, req) => { 8 | if (req.url === '/online-alias') { 9 | wsClients.add(ws); 10 | 11 | ws.on('error', () => { 12 | ws.close(); 13 | }); 14 | 15 | ws.on('close', () => { 16 | wsClients.remove(ws); 17 | }); 18 | } 19 | }); 20 | }; 21 | 22 | module.exports = { upgradeWithWs } -------------------------------------------------------------------------------- /ch2/part5/utils/dumpDatabase.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { dbPath } = require("../config"); 3 | const { compressFile } = require("../utils/compressFile"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | function dumpDatabase() { 9 | // better use https://www.npmjs.com/package/cron 10 | setInterval(() => { 11 | compressFile(linksFilePath, path.resolve(dbPath, "dumps"), "db-dump.json"); 12 | 13 | console.log('Database dump was created.'); 14 | }, 10000); 15 | } 16 | 17 | module.exports = { dumpDatabase }; 18 | -------------------------------------------------------------------------------- /ch2/part6/utils/dumpDatabase.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { dbPath } = require("../config"); 3 | const { compressFile } = require("../utils/compressFile"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | function dumpDatabase() { 9 | // better use https://www.npmjs.com/package/cron 10 | setInterval(() => { 11 | compressFile(linksFilePath, path.resolve(dbPath, "dumps"), "db-dump.json"); 12 | 13 | console.log('Database dump was created.'); 14 | }, 10000); 15 | } 16 | 17 | module.exports = { dumpDatabase }; 18 | -------------------------------------------------------------------------------- /ch2/part7/utils/dumpDatabase.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { dbPath } = require("../config"); 3 | const { compressFile } = require("../utils/compressFile"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | function dumpDatabase() { 9 | // better use https://www.npmjs.com/package/cron 10 | setInterval(() => { 11 | compressFile(linksFilePath, path.resolve(dbPath, "dumps"), "db-dump.json"); 12 | 13 | console.log('Database dump was created.'); 14 | }, 10000); 15 | } 16 | 17 | module.exports = { dumpDatabase }; 18 | -------------------------------------------------------------------------------- /ch2/part8/server/utils/dumpDatabase.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { dbPath } = require("../config"); 3 | const { compressFile } = require("../utils/compressFile"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | function dumpDatabase() { 9 | // better use https://www.npmjs.com/package/cron 10 | setInterval(() => { 11 | compressFile(linksFilePath, path.resolve(dbPath, "dumps"), "db-dump.json"); 12 | 13 | console.log('Database dump was created.'); 14 | }, 10000); 15 | } 16 | 17 | module.exports = { dumpDatabase }; 18 | -------------------------------------------------------------------------------- /ch2/part9/server/utils/dumpDatabase.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const { dbPath } = require("../config"); 3 | const { compressFile } = require("../utils/compressFile"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | function dumpDatabase() { 9 | // better use https://www.npmjs.com/package/cron 10 | setInterval(() => { 11 | compressFile(linksFilePath, path.resolve(dbPath, "dumps"), "db-dump.json"); 12 | 13 | console.log('Database dump was created.'); 14 | }, 60000); 15 | } 16 | 17 | module.exports = { dumpDatabase }; 18 | -------------------------------------------------------------------------------- /ch2/part9/server/modules/wsClients.js: -------------------------------------------------------------------------------- 1 | class WsClients { 2 | constructor() { 3 | this.clients = []; 4 | } 5 | 6 | add(ws) { 7 | this.clients.push(ws); 8 | 9 | this.logClientsCount(); 10 | } 11 | 12 | remove(ws) { 13 | this.clients = this.clients.filter((client) => client !== ws); 14 | 15 | this.logClientsCount(); 16 | } 17 | 18 | forEach(callback) { 19 | this.logClientsCount(); 20 | 21 | this.clients.forEach((client) => callback(client)); 22 | } 23 | 24 | logClientsCount() { 25 | console.log(`ws clients count: ${this.clients.length}`); 26 | } 27 | } 28 | 29 | module.exports = { wsClients: new WsClients() }; 30 | -------------------------------------------------------------------------------- /ch2/part8/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /ch2/part9/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /ch2/part5/utils/compressFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const zlib = require("zlib"); 4 | 5 | function compressFile( 6 | inputFilePath, 7 | outputFolder, 8 | resultFilename 9 | ) { 10 | return new Promise((resolve, reject) => { 11 | const stream = fs.createReadStream(inputFilePath); 12 | 13 | stream 14 | .pipe(zlib.createGzip()) 15 | .pipe( 16 | fs.createWriteStream(path.resolve(outputFolder, `${Date.now()}_${resultFilename}.gz`), { 17 | flags: "a", 18 | }) 19 | ) 20 | .on("error", reject) 21 | .on("finish", resolve); 22 | }); 23 | } 24 | 25 | module.exports = { compressFile }; 26 | -------------------------------------------------------------------------------- /ch2/part6/utils/compressFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const zlib = require("zlib"); 4 | 5 | function compressFile( 6 | inputFilePath, 7 | outputFolder, 8 | resultFilename 9 | ) { 10 | return new Promise((resolve, reject) => { 11 | const stream = fs.createReadStream(inputFilePath); 12 | 13 | stream 14 | .pipe(zlib.createGzip()) 15 | .pipe( 16 | fs.createWriteStream(path.resolve(outputFolder, `${Date.now()}_${resultFilename}.gz`), { 17 | flags: "a", 18 | }) 19 | ) 20 | .on("error", reject) 21 | .on("finish", resolve); 22 | }); 23 | } 24 | 25 | module.exports = { compressFile }; 26 | -------------------------------------------------------------------------------- /ch2/part7/utils/compressFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const zlib = require("zlib"); 4 | 5 | function compressFile( 6 | inputFilePath, 7 | outputFolder, 8 | resultFilename 9 | ) { 10 | return new Promise((resolve, reject) => { 11 | const stream = fs.createReadStream(inputFilePath); 12 | 13 | stream 14 | .pipe(zlib.createGzip()) 15 | .pipe( 16 | fs.createWriteStream(path.resolve(outputFolder, `${Date.now()}_${resultFilename}.gz`), { 17 | flags: "a", 18 | }) 19 | ) 20 | .on("error", reject) 21 | .on("finish", resolve); 22 | }); 23 | } 24 | 25 | module.exports = { compressFile }; 26 | -------------------------------------------------------------------------------- /ch2/part8/server/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat", 11 | "random": "https://yandex.ru/dwadawdaw", 12 | "random1": "https://yandex.ru/dwadawdaw", 13 | "random2": "https://yandex.ru/dwadawdaw", 14 | "random6": "https://yandex.ru/dwadawdaw" 15 | } -------------------------------------------------------------------------------- /ch2/part9/server/db/links.dev.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru", 3 | "map": "https://yandex.ru/maps/", 4 | "tr": "https://translate.yandex.ru", 5 | "cats": "https://yandex.ru/images/search?text=cat", 6 | "carr": "https://yandex.ru/images/search?text=cat", 7 | "cat": "https://yandex.ru/images/search?text=cat", 8 | "var": "https://yandex.ru/images/search?text=cat", 9 | "c": "https://yandex.ru/images/search?text=cat", 10 | "catt": "https://yandex.ru/images/search?text=cat", 11 | "random": "https://yandex.ru/dwadawdaw", 12 | "random1": "https://yandex.ru/dwadawdaw", 13 | "random2": "https://yandex.ru/dwadawdaw", 14 | "random6": "https://yandex.ru/dwadawdaw" 15 | } -------------------------------------------------------------------------------- /ch2/part8/server/utils/compressFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const zlib = require("zlib"); 4 | 5 | function compressFile( 6 | inputFilePath, 7 | outputFolder, 8 | resultFilename 9 | ) { 10 | return new Promise((resolve, reject) => { 11 | const stream = fs.createReadStream(inputFilePath); 12 | 13 | stream 14 | .pipe(zlib.createGzip()) 15 | .pipe( 16 | fs.createWriteStream(path.resolve(outputFolder, `${Date.now()}_${resultFilename}.gz`), { 17 | flags: "a", 18 | }) 19 | ) 20 | .on("error", reject) 21 | .on("finish", resolve); 22 | }); 23 | } 24 | 25 | module.exports = { compressFile }; 26 | -------------------------------------------------------------------------------- /ch2/part9/server/utils/compressFile.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const path = require("path"); 3 | const zlib = require("zlib"); 4 | 5 | function compressFile( 6 | inputFilePath, 7 | outputFolder, 8 | resultFilename 9 | ) { 10 | return new Promise((resolve, reject) => { 11 | const stream = fs.createReadStream(inputFilePath); 12 | 13 | stream 14 | .pipe(zlib.createGzip()) 15 | .pipe( 16 | fs.createWriteStream(path.resolve(outputFolder, `${Date.now()}_${resultFilename}.gz`), { 17 | flags: "a", 18 | }) 19 | ) 20 | .on("error", reject) 21 | .on("finish", resolve); 22 | }); 23 | } 24 | 25 | module.exports = { compressFile }; 26 | -------------------------------------------------------------------------------- /ch2/part2/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { urlLogger } = require("./middlewares/urlLogger"); 8 | 9 | const app = express(); 10 | 11 | app.use(express.json()); 12 | 13 | app.use(urlLogger); 14 | 15 | app.get("/ping", ping); 16 | app.get("/:alias", resolveAlias); 17 | app.post("/alias", addAlias); 18 | 19 | app.use(notFound); 20 | 21 | const PORT = 3000; 22 | 23 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 24 | -------------------------------------------------------------------------------- /ch2/part6/utils/monitorProcess.js: -------------------------------------------------------------------------------- 1 | const { exec: execOnCallbacks } = require("child_process"); 2 | const util = require("util"); 3 | const fs = require("fs/promises"); 4 | const path = require("path"); 5 | 6 | const exec = util.promisify(execOnCallbacks); 7 | 8 | async function monitorProcess() { 9 | setInterval(async () => { 10 | const { pid } = process; 11 | 12 | const { stdout } = await exec( 13 | `ps -p ${pid} -o pid,vsz=MEMORY,pcpu -o comm,args=ARGS` 14 | ); 15 | 16 | const log = `${new Date()}\n${stdout}`; 17 | 18 | await fs.writeFile(path.resolve(__dirname, "../cpu-memory.log"), log, { 19 | flag: "a", 20 | }); 21 | }, 2000); 22 | } 23 | 24 | module.exports = { monitorProcess }; 25 | -------------------------------------------------------------------------------- /ch2/part7/utils/monitorProcess.js: -------------------------------------------------------------------------------- 1 | const { exec: execOnCallbacks } = require("child_process"); 2 | const util = require("util"); 3 | const fs = require("fs/promises"); 4 | const path = require("path"); 5 | 6 | const exec = util.promisify(execOnCallbacks); 7 | 8 | async function monitorProcess() { 9 | setInterval(async () => { 10 | const { pid } = process; 11 | 12 | const { stdout } = await exec( 13 | `ps -p ${pid} -o pid,vsz=MEMORY,pcpu -o comm,args=ARGS` 14 | ); 15 | 16 | const log = `${new Date()}\n${stdout}`; 17 | 18 | await fs.writeFile(path.resolve(__dirname, "../cpu-memory.log"), log, { 19 | flag: "a", 20 | }); 21 | }, 2000); 22 | } 23 | 24 | module.exports = { monitorProcess }; 25 | -------------------------------------------------------------------------------- /ch2/part8/server/utils/monitorProcess.js: -------------------------------------------------------------------------------- 1 | const { exec: execOnCallbacks } = require("child_process"); 2 | const util = require("util"); 3 | const fs = require("fs/promises"); 4 | const path = require("path"); 5 | 6 | const exec = util.promisify(execOnCallbacks); 7 | 8 | async function monitorProcess() { 9 | setInterval(async () => { 10 | const { pid } = process; 11 | 12 | const { stdout } = await exec( 13 | `ps -p ${pid} -o pid,vsz=MEMORY,pcpu -o comm,args=ARGS` 14 | ); 15 | 16 | const log = `${new Date()}\n${stdout}`; 17 | 18 | await fs.writeFile(path.resolve(__dirname, "../cpu-memory.log"), log, { 19 | flag: "a", 20 | }); 21 | }, 2000); 22 | } 23 | 24 | module.exports = { monitorProcess }; 25 | -------------------------------------------------------------------------------- /ch2/part9/client/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { BrowserRouter, Route, Routes } from "react-router-dom"; 3 | import ReactDOM from "react-dom/client"; 4 | import { ChakraProvider } from "@chakra-ui/react"; 5 | import { Home } from "./Home"; 6 | import { Online } from "./Online"; 7 | import "./index.css"; 8 | 9 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( 10 | 11 | 12 | 13 | 14 | } /> 15 | } /> 16 | 17 | 18 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /ch2/part9/server/utils/monitorProcess.js: -------------------------------------------------------------------------------- 1 | const { exec: execOnCallbacks } = require("child_process"); 2 | const util = require("util"); 3 | const fs = require("fs/promises"); 4 | const path = require("path"); 5 | 6 | const exec = util.promisify(execOnCallbacks); 7 | 8 | async function monitorProcess() { 9 | setInterval(async () => { 10 | const { pid } = process; 11 | 12 | const { stdout } = await exec( 13 | `ps -p ${pid} -o pid,vsz=MEMORY,pcpu -o comm,args=ARGS` 14 | ); 15 | 16 | const log = `${new Date()}\n${stdout}`; 17 | 18 | await fs.writeFile(path.resolve(__dirname, "../cpu-memory.log"), log, { 19 | flag: "a", 20 | }); 21 | }, 2000); 22 | } 23 | 24 | module.exports = { monitorProcess }; 25 | -------------------------------------------------------------------------------- /ch2/part8/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@chakra-ui/react": "^2.2.4", 17 | "@emotion/react": "^11.9.3", 18 | "@emotion/styled": "^11.9.3", 19 | "@types/react": "^18.0.15", 20 | "@types/react-dom": "^18.0.6", 21 | "@vitejs/plugin-react": "^2.0.0", 22 | "framer-motion": "^6.5.1", 23 | "react-hook-form": "^7.33.1", 24 | "typescript": "^4.6.4", 25 | "vite": "^3.0.0" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ch2/part9/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@chakra-ui/react": "^2.2.4", 17 | "@emotion/react": "^11.9.3", 18 | "@emotion/styled": "^11.9.3", 19 | "@types/react": "^18.0.15", 20 | "@types/react-dom": "^18.0.6", 21 | "@vitejs/plugin-react": "^2.0.0", 22 | "framer-motion": "^6.5.1", 23 | "react-hook-form": "^7.33.1", 24 | "react-router-dom": "^6.3.0", 25 | "typescript": "^4.6.4", 26 | "vite": "^3.0.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ch2/part3/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { urlLogger } = require("./middlewares/urlLogger"); 8 | const { errorHandler } = require("./middlewares/errorHandler"); 9 | 10 | const app = express(); 11 | 12 | app.use(express.json()); 13 | 14 | app.use(urlLogger); 15 | 16 | app.get("/ping", ping); 17 | app.get("/:alias", resolveAlias); 18 | app.post("/alias", addAlias); 19 | 20 | app.use(notFound); 21 | 22 | app.use(errorHandler); 23 | 24 | const PORT = 3000; 25 | 26 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 27 | -------------------------------------------------------------------------------- /ch2/part5/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const { BadRequestError } = require("../modules/error"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | async function getByAlias(alias) { 9 | const links = require(linksFilePath); 10 | 11 | return links[alias]; 12 | } 13 | 14 | async function addAlias(alias, link) { 15 | const links = require(linksFilePath); 16 | 17 | if (links[alias]) { 18 | throw new BadRequestError('alias-already-exists'); 19 | } 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part6/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const { BadRequestError } = require("../modules/error"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | async function getByAlias(alias) { 9 | const links = require(linksFilePath); 10 | 11 | return links[alias]; 12 | } 13 | 14 | async function addAlias(alias, link) { 15 | const links = require(linksFilePath); 16 | 17 | if (links[alias]) { 18 | throw new BadRequestError('alias-already-exists'); 19 | } 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part7/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const { BadRequestError } = require("../modules/error"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | async function getByAlias(alias) { 9 | const links = require(linksFilePath); 10 | 11 | return links[alias]; 12 | } 13 | 14 | async function addAlias(alias, link) { 15 | const links = require(linksFilePath); 16 | 17 | if (links[alias]) { 18 | throw new BadRequestError('alias-already-exists'); 19 | } 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part8/server/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const { BadRequestError } = require("../modules/error"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | async function getByAlias(alias) { 9 | const links = require(linksFilePath); 10 | 11 | return links[alias]; 12 | } 13 | 14 | async function addAlias(alias, link) { 15 | const links = require(linksFilePath); 16 | 17 | if (links[alias]) { 18 | throw new BadRequestError('alias-already-exists'); 19 | } 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part9/server/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | 3 | const { BadRequestError } = require("../modules/error"); 4 | const { getDatabaseFilePath } = require("../utils/getDatabaseFilePath"); 5 | 6 | const linksFilePath = getDatabaseFilePath(); 7 | 8 | async function getByAlias(alias) { 9 | const links = require(linksFilePath); 10 | 11 | return links[alias]; 12 | } 13 | 14 | async function addAlias(alias, link) { 15 | const links = require(linksFilePath); 16 | 17 | if (links[alias]) { 18 | throw new BadRequestError('alias-already-exists'); 19 | } 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part4/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { errorHandler } = require("./middlewares/errorHandler"); 8 | const { accessLogs } = require("./middlewares/accessLogs"); 9 | 10 | const app = express(); 11 | 12 | app.use(express.json()); 13 | 14 | app.use(accessLogs()); 15 | app.use(accessLogs(true)); 16 | 17 | app.get("/ping", ping); 18 | app.get("/:alias", resolveAlias); 19 | app.post("/alias", addAlias); 20 | 21 | app.use(notFound); 22 | 23 | app.use(errorHandler); 24 | 25 | const PORT = 3000; 26 | 27 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 28 | -------------------------------------------------------------------------------- /ch2/part2/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const { dbPath } = require("../config"); 5 | 6 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 7 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 8 | 9 | const linksFilePath = 10 | process.env.LINKS_TYPE === "prod" ? linksProdFilePath : linksDevFilePath; 11 | 12 | async function getByAlias(alias) { 13 | const links = require(linksFilePath); 14 | 15 | return links[alias]; 16 | } 17 | 18 | async function addAlias(alias, link) { 19 | const links = require(linksFilePath); 20 | 21 | links[alias] = link; 22 | 23 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 24 | 25 | return links[alias]; 26 | } 27 | 28 | module.exports = { 29 | getByAlias, 30 | addAlias 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part3/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (/^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch1/part4/script.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs").promises; 2 | const path = require("path"); 3 | 4 | const linksDevFilePath = path.resolve(__dirname, "./links.dev.txt"); 5 | const linksProdFilePath = path.resolve(__dirname, "./links.prod.txt"); 6 | 7 | const linksFilePath = 8 | process.env.LINKS_TYPE === "prod" ? linksProdFilePath : linksDevFilePath; 9 | 10 | async function printLinkByAlias(alias) { 11 | const linksFileContent = await fs.readFile(linksFilePath, "utf-8"); 12 | 13 | const links = linksFileContent 14 | .split("\n") // get rows 15 | .filter((str) => !!str) // or just .filter(Boolean); 16 | .map((row) => row.split(" ")) // split alias from full link 17 | .reduce((acc, curr) => ({ ...acc, [curr[0]]: curr[1] }), {}); // construct links object 18 | 19 | console.log(links[alias]); 20 | } 21 | 22 | const alias = process.argv[2]; 23 | 24 | printLinkByAlias(alias); 25 | -------------------------------------------------------------------------------- /ch2/part4/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part5/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part6/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part7/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part8/server/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const linksService = require("../services/links"); 3 | 4 | async function resolveAlias(request, response, next) { 5 | try { 6 | const { alias } = request.params; 7 | 8 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 9 | return next(); 10 | } 11 | 12 | const longLink = await linksService.getByAlias(alias); 13 | 14 | if (!longLink) { 15 | throw new NotFoundError(`Alias "${alias}" was not found...`); 16 | } 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | response.redirect(302, longLink); 20 | } else { 21 | response.send(longLink); 22 | } 23 | } catch (err) { 24 | next(err); 25 | } 26 | } 27 | 28 | module.exports = { resolveAlias }; -------------------------------------------------------------------------------- /ch2/part9/client/src/Online.tsx: -------------------------------------------------------------------------------- 1 | import { Container, Stat, StatLabel, StatNumber } from "@chakra-ui/react"; 2 | import { useEffect, useState } from "react"; 3 | import { useParams } from "react-router-dom"; 4 | 5 | export const Online = () => { 6 | const params = useParams<{ alias: string }>(); 7 | const [count, setCount] = useState(0); 8 | 9 | useEffect(() => { 10 | const ws = new WebSocket('ws://localhost:3000/online-alias'); 11 | 12 | ws.onmessage = (event) => { 13 | if (event.data === params.alias) { 14 | setCount(count => count + 1); 15 | } 16 | }; 17 | 18 | return () => { 19 | ws.close(); 20 | }; 21 | }, []); 22 | 23 | return ( 24 | 25 | 26 | Opened "{params.alias}" 27 | {count} 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /ch2/part5/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { errorHandler } = require("./middlewares/errorHandler"); 8 | const { accessLogs } = require("./middlewares/accessLogs"); 9 | const { dumpDatabase } = require("./utils/dumpDatabase"); 10 | 11 | const app = express(); 12 | 13 | app.use(express.json()); 14 | 15 | app.use(accessLogs()); 16 | app.use(accessLogs(true)); 17 | 18 | app.get("/ping", ping); 19 | app.get("/:alias", resolveAlias); 20 | app.post("/alias", addAlias); 21 | 22 | app.use(notFound); 23 | 24 | app.use(errorHandler); 25 | 26 | const PORT = 3000; 27 | 28 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 29 | 30 | dumpDatabase(); 31 | -------------------------------------------------------------------------------- /ch2/part6/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { errorHandler } = require("./middlewares/errorHandler"); 8 | const { accessLogs } = require("./middlewares/accessLogs"); 9 | const { dumpDatabase } = require("./utils/dumpDatabase"); 10 | const { monitorProcess } = require("./utils/monitorProcess"); 11 | 12 | const app = express(); 13 | 14 | app.use(express.json()); 15 | 16 | app.use(accessLogs()); 17 | app.use(accessLogs(true)); 18 | 19 | app.get("/ping", ping); 20 | app.get("/:alias", resolveAlias); 21 | app.post("/alias", addAlias); 22 | 23 | app.use(notFound); 24 | 25 | app.use(errorHandler); 26 | 27 | const PORT = 3000; 28 | 29 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 30 | 31 | dumpDatabase(); 32 | monitorProcess(); -------------------------------------------------------------------------------- /ch2/part3/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const { dbPath } = require("../config"); 5 | const { BadRequestError } = require("../modules/error"); 6 | 7 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 8 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 9 | 10 | const linksFilePath = 11 | process.env.LINKS_TYPE === "prod" ? linksProdFilePath : linksDevFilePath; 12 | 13 | async function getByAlias(alias) { 14 | const links = require(linksFilePath); 15 | 16 | return links[alias]; 17 | } 18 | 19 | async function addAlias(alias, link) { 20 | const links = require(linksFilePath); 21 | 22 | if (links[alias]) { 23 | throw new BadRequestError('alias-already-exists'); 24 | } 25 | 26 | links[alias] = link; 27 | 28 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 29 | 30 | return links[alias]; 31 | } 32 | 33 | module.exports = { 34 | getByAlias, 35 | addAlias 36 | }; 37 | -------------------------------------------------------------------------------- /ch2/part4/services/links.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | 4 | const { dbPath } = require("../config"); 5 | const { BadRequestError } = require("../modules/error"); 6 | 7 | const linksDevFilePath = path.resolve(dbPath, "./links.dev.json"); 8 | const linksProdFilePath = path.resolve(dbPath, "./links.prod.json"); 9 | 10 | const linksFilePath = 11 | process.env.LINKS_TYPE === "prod" ? linksProdFilePath : linksDevFilePath; 12 | 13 | async function getByAlias(alias) { 14 | const links = require(linksFilePath); 15 | 16 | return links[alias]; 17 | } 18 | 19 | async function addAlias(alias, link) { 20 | const links = require(linksFilePath); 21 | 22 | if (links[alias]) { 23 | throw new BadRequestError('alias-already-exists'); 24 | } 25 | 26 | links[alias] = link; 27 | 28 | await fs.writeFile(linksFilePath, JSON.stringify(links, null, 2), "utf-8"); 29 | 30 | return links[alias]; 31 | } 32 | 33 | module.exports = { 34 | getByAlias, 35 | addAlias 36 | }; 37 | -------------------------------------------------------------------------------- /ch2/part9/server/controllers/resolveAlias.js: -------------------------------------------------------------------------------- 1 | const { NotFoundError } = require("../modules/error"); 2 | const { wsClients } = require("../modules/wsClients"); 3 | const linksService = require("../services/links"); 4 | 5 | async function resolveAlias(request, response, next) { 6 | try { 7 | const { alias } = request.params; 8 | 9 | if (alias.length === 0 || /^[a-zA-Z0-9]+$/.test(alias) === false) { 10 | return next(); 11 | } 12 | 13 | const longLink = await linksService.getByAlias(alias); 14 | 15 | if (!longLink) { 16 | throw new NotFoundError(`Alias "${alias}" was not found...`); 17 | } 18 | 19 | wsClients.forEach((wsClient) => { 20 | if (wsClient.readyState === 1) { 21 | wsClient.send(alias); 22 | } 23 | }); 24 | 25 | if (process.env.NODE_ENV === "production") { 26 | response.redirect(302, longLink); 27 | } else { 28 | response.send(longLink); 29 | } 30 | } catch (err) { 31 | next(err); 32 | } 33 | } 34 | 35 | module.exports = { resolveAlias }; 36 | -------------------------------------------------------------------------------- /ch2/part7/server.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | 3 | const { resolveAlias } = require("./controllers/resolveAlias"); 4 | const { addAlias } = require("./controllers/addAlias"); 5 | const { ping } = require("./controllers/ping"); 6 | const { notFound } = require("./middlewares/notFound"); 7 | const { errorHandler } = require("./middlewares/errorHandler"); 8 | const { accessLogs } = require("./middlewares/accessLogs"); 9 | const { dumpDatabase } = require("./utils/dumpDatabase"); 10 | const { monitorProcess } = require("./utils/monitorProcess"); 11 | const { secure } = require("./middlewares/security"); 12 | 13 | const app = express(); 14 | 15 | secure(app); 16 | 17 | app.use(express.json()); 18 | 19 | app.use(accessLogs()); 20 | app.use(accessLogs(true)); 21 | 22 | app.get("/ping", ping); 23 | app.get("/:alias", resolveAlias); 24 | app.post("/alias", addAlias); 25 | 26 | app.use(notFound); 27 | 28 | app.use(errorHandler); 29 | 30 | const PORT = 3000; 31 | 32 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 33 | 34 | dumpDatabase(); 35 | monitorProcess(); -------------------------------------------------------------------------------- /ch2/part8/server/server.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const express = require("express"); 4 | const { createProxyMiddleware } = require("http-proxy-middleware"); 5 | 6 | const { resolveAlias } = require("./controllers/resolveAlias"); 7 | const { addAlias } = require("./controllers/addAlias"); 8 | const { ping } = require("./controllers/ping"); 9 | const { notFound } = require("./middlewares/notFound"); 10 | const { errorHandler } = require("./middlewares/errorHandler"); 11 | const { accessLogs } = require("./middlewares/accessLogs"); 12 | const { dumpDatabase } = require("./utils/dumpDatabase"); 13 | const { monitorProcess } = require("./utils/monitorProcess"); 14 | const { secure } = require("./middlewares/security"); 15 | 16 | const app = express(); 17 | 18 | secure(app); 19 | 20 | app.use(express.json()); 21 | 22 | app.use(accessLogs()); 23 | app.use(accessLogs(true)); 24 | 25 | app.get("/ping", ping); 26 | app.get("/:alias", resolveAlias); 27 | app.post("/alias", addAlias); 28 | 29 | app.use( 30 | process.env.NODE_ENV === "production" 31 | ? express.static(path.resolve(__dirname, "../client/dist")) 32 | : createProxyMiddleware({ 33 | target: "http://localhost:3001", 34 | changeOrigin: true, 35 | }) 36 | ); 37 | 38 | app.use(notFound); 39 | 40 | app.use(errorHandler); 41 | 42 | const PORT = 3000; 43 | 44 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 45 | 46 | dumpDatabase(); 47 | monitorProcess(); 48 | -------------------------------------------------------------------------------- /ch1/part5/script.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs/promises"); 2 | const path = require("path"); 3 | const http = require("http"); 4 | 5 | const linksDevFilePath = path.resolve(__dirname, "./links.dev.txt"); 6 | const linksProdFilePath = path.resolve(__dirname, "./links.prod.txt"); 7 | 8 | const linksFilePath = 9 | process.env.NODE_ENV === "production" ? linksProdFilePath : linksDevFilePath; 10 | 11 | async function printLinkByAlias(alias) { 12 | const linksFileContent = await fs.readFile(linksFilePath, "utf-8"); 13 | 14 | const links = linksFileContent 15 | .split("\n") // get rows 16 | .filter((str) => !!str) // or just .filter(Boolean); 17 | .map((row) => row.split(" ")) // split alias from full link 18 | .reduce((acc, curr) => ({ ...acc, [curr[0]]: curr[1] }), {}); // construct links object 19 | 20 | return links[alias]; 21 | } 22 | 23 | const server = http.createServer((request, response) => { 24 | console.log(request.url); 25 | 26 | const alias = request.url.slice(1); 27 | 28 | printLinkByAlias(alias).then((longLink) => { 29 | if (!longLink) { 30 | response.statusCode = 404; 31 | return response.end('not-found'); 32 | } 33 | 34 | if (process.env.NODE_ENV === 'production') { 35 | response.setHeader('location', longLink); 36 | response.statusCode = 302; 37 | 38 | response.end(); 39 | } else { 40 | response.end(longLink); 41 | } 42 | }); 43 | }); 44 | 45 | server.listen(3000, () => console.log("Server started on port 3000")); 46 | -------------------------------------------------------------------------------- /ch1/part4/links.prod.txt: -------------------------------------------------------------------------------- 1 | music https://music.yandex.ru/album/7375892/track/52396212 2 | map https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13 3 | tr https://translate.yandex.ru/?lang=en-ru&text=hello%20world 4 | video1 https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8 5 | video2 https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw 6 | -------------------------------------------------------------------------------- /ch1/part5/links.prod.txt: -------------------------------------------------------------------------------- 1 | music https://music.yandex.ru/album/7375892/track/52396212 2 | map https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13 3 | tr https://translate.yandex.ru/?lang=en-ru&text=hello%20world 4 | video1 https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8 5 | video2 https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw 6 | -------------------------------------------------------------------------------- /ch2/part9/server/server.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const http = require('http'); 3 | 4 | const express = require("express"); 5 | 6 | const { resolveAlias } = require("./controllers/resolveAlias"); 7 | const { addAlias } = require("./controllers/addAlias"); 8 | const { ping } = require("./controllers/ping"); 9 | const { notFound } = require("./middlewares/notFound"); 10 | const { errorHandler } = require("./middlewares/errorHandler"); 11 | const { accessLogs } = require("./middlewares/accessLogs"); 12 | const { dumpDatabase } = require("./utils/dumpDatabase"); 13 | const { monitorProcess } = require("./utils/monitorProcess"); 14 | const { secure } = require("./middlewares/security"); 15 | const { upgradeWithWs } = require("./ws"); 16 | 17 | const app = express(); 18 | 19 | secure(app); 20 | 21 | app.use(express.json()); 22 | 23 | app.use(accessLogs()); 24 | app.use(accessLogs(true)); 25 | 26 | app.get("/ping", ping); 27 | app.get("/:alias", resolveAlias); 28 | app.post("/alias", addAlias); 29 | 30 | app.use(express.static(path.resolve(__dirname, "../client/dist"))); 31 | 32 | app.use((request, response) => { 33 | response.sendFile(path.resolve(__dirname, "../client/dist/index.html")); 34 | }); 35 | 36 | app.use(notFound); 37 | 38 | app.use(errorHandler); 39 | 40 | const server = http.createServer(app); 41 | 42 | upgradeWithWs(server); 43 | 44 | const PORT = 3000; 45 | 46 | server.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 47 | 48 | if (process.env.NODE_ENV === 'production') { 49 | dumpDatabase(); 50 | monitorProcess(); 51 | } 52 | -------------------------------------------------------------------------------- /ch2/part1/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part2/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part3/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part4/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part5/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part6/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part7/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part8/server/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch2/part9/server/db/links.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "music": "https://music.yandex.ru/album/7375892/track/52396212", 3 | "map": "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | "tr": "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | "video1": "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | "video2": "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw" 7 | } 8 | -------------------------------------------------------------------------------- /ch1/part1/script.js: -------------------------------------------------------------------------------- 1 | const links = { 2 | music: "https://music.yandex.ru/album/7375892/track/52396212", 3 | map: "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 4 | tr: "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 5 | video1: "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 6 | video2: "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw", 7 | }; 8 | 9 | const alias = 'map'; 10 | 11 | console.log(links[alias]); 12 | -------------------------------------------------------------------------------- /ch1/part2/script.js: -------------------------------------------------------------------------------- 1 | const links = 2 | process.env.LINKS_TYPE === "prod" 3 | ? { 4 | music: "https://music.yandex.ru/album/7375892/track/52396212", 5 | map: "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 6 | tr: "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 7 | video1: 8 | "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 9 | video2: 10 | "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw", 11 | } 12 | : { 13 | music: "https://music.yandex.ru", 14 | map: "https://yandex.ru/maps/", 15 | tr: "https://translate.yandex.ru", 16 | }; 17 | 18 | const alias = 'map'; 19 | 20 | console.log(process.env.LINKS_TYPE); 21 | console.log(links[alias]); 22 | -------------------------------------------------------------------------------- /ch1/part3/script.js: -------------------------------------------------------------------------------- 1 | const links = 2 | process.env.LINKS_TYPE === "prod" 3 | ? { 4 | music: "https://music.yandex.ru/album/7375892/track/52396212", 5 | map: "https://yandex.ru/maps/org/yandeks/1124715036/?ll=37.570552%2C55.738210&mode=search&sctx=ZAAAAAgBEAAaKAoSCeUn1T4dz0JAEYNqgxPR4UtAEhIJU%2BdR8X9H%2Bj8RjbeVXpsN4z8iBgABAgMEBSgKOABAAUgBYiZyZWxldl9pcnJlbF9maWx0ZXI9aXJyZWxfZm1sODYxODE3X2V4cGIrcmVhcnI9c2NoZW1lX0xvY2FsL0dlby9FbmFibGVCZWF1dHlGaWx0ZXI9MWI2cmVhcnI9c2NoZW1lX0xvY2FsL0dlby9Qb3N0ZmlsdGVyL05ld1JlbGV2QmVydFRocj0wLjAwagJydZ0BzcxMPaABAKgBAL0BqtRcd8IBkAGclKeYBLPFr7HYA4jV%2BZkEw%2FbJhS3Hi7ia7wKdnNru0QKqz8e7sQLDpObjlwO65oOD0wTPiObJqwWnsdS9oAHH5%2B7K7wP4lKvl3QSinfCJwwGgkOqk%2FgS80af07ATMstfRPZbN2%2FGmBvvk6KWDBu2H3JsrjMvo87sC%2F4Pjma4B%2F5nv3bcG4Jruk6cDrPXfoHHqAQDyAQD4AQCCAgzRj9C90LTQtdC60YGKAgCSAgCaAgxkZXNrdG9wLW1hcHM%3D&sll=37.570552%2C55.738210&sspn=0.124641%2C0.045214&text=%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81&z=13", 6 | tr: "https://translate.yandex.ru/?lang=en-ru&text=hello%20world", 7 | video1: 8 | "https://yandex.ru/video/preview/?filmId=198484335193438218&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8", 9 | video2: 10 | "https://yandex.ru/video/preview/?filmId=2479178741132479613&reqid=1658097906196960-7557307180056272063-sas3-0732-e22-sas-l7-balancer-8080-BAL-7048&suggest_reqid=202606689162876927279060549798666&text=%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE+%D1%8F%D0%BD%D0%B4%D0%B5%D0%BA%D1%81+%D1%88%D1%80%D0%B8&url=http%3A%2F%2Ffrontend.vh.yandex.ru%2Fplayer%2Fvi1tqpQxcVAw", 11 | } 12 | : { 13 | music: "https://music.yandex.ru", 14 | map: "https://yandex.ru/maps/", 15 | tr: "https://translate.yandex.ru", 16 | }; 17 | 18 | console.log(process.argv); 19 | 20 | const alias = process.argv[2]; 21 | 22 | console.log(links[alias]); 23 | -------------------------------------------------------------------------------- /ch2/part7/middlewares/security.js: -------------------------------------------------------------------------------- 1 | const { disablePoweredBy } = require("./disablePoweredBy"); 2 | 3 | const cors = require("cors"); 4 | const helmet = require("helmet"); 5 | const rateLimiter = require("express-rate-limit"); 6 | const slowDown = require("express-slow-down"); 7 | 8 | function secure(app) { 9 | app.use(disablePoweredBy); 10 | 11 | app.use( 12 | cors({ 13 | origin: ["https://example.ru", "http://localhost:3000"], 14 | }) 15 | ); 16 | 17 | app.use( 18 | helmet({ 19 | contentSecurityPolicy: { 20 | useDefaults: true, 21 | directives: { 22 | scriptSrc: [ 23 | "'self'", 24 | "'unsafe-inline'", 25 | "https://cdn.jsdelivr.net", 26 | "https://code.jquery.com", 27 | ], 28 | }, 29 | }, 30 | }) 31 | ); 32 | 33 | // app.use(helmet.contentSecurityPolicy()); 34 | // app.use(helmet.crossOriginEmbedderPolicy()); 35 | // app.use(helmet.crossOriginOpenerPolicy()); 36 | // app.use(helmet.crossOriginResourcePolicy()); 37 | // app.use(helmet.dnsPrefetchControl()); 38 | // app.use(helmet.expectCt()); 39 | // app.use(helmet.frameguard()); 40 | // app.use(helmet.hidePoweredBy()); 41 | // app.use(helmet.hsts()); 42 | // app.use(helmet.ieNoOpen()); 43 | // app.use(helmet.noSniff()); 44 | // app.use(helmet.originAgentCluster()); 45 | // app.use(helmet.permittedCrossDomainPolicies()); 46 | // app.use(helmet.referrerPolicy()); 47 | // app.use(helmet.xssFilter()); 48 | 49 | const limiter = rateLimiter({ 50 | windowMs: 1 * 60 * 1000, 51 | max: 120, // limit each IP to 120 requests per minute 52 | }); 53 | 54 | const speedLimiter = slowDown({ 55 | windowMs: 1 * 60 * 1000, 56 | delayAfter: 100, // allow 100 requests per minute, 57 | delayMs: 1000, // adding 1000ms of delay per request above 100 58 | // request # 101 is delayed by 1000ms 59 | // request # 102 is delayed by 2000ms 60 | }); 61 | 62 | app.use(speedLimiter); 63 | app.use(limiter); 64 | } 65 | 66 | module.exports = { secure }; 67 | -------------------------------------------------------------------------------- /ch2/part8/server/middlewares/security.js: -------------------------------------------------------------------------------- 1 | const { disablePoweredBy } = require("./disablePoweredBy"); 2 | 3 | const cors = require("cors"); 4 | const helmet = require("helmet"); 5 | const rateLimiter = require("express-rate-limit"); 6 | const slowDown = require("express-slow-down"); 7 | 8 | function secure(app) { 9 | app.use(disablePoweredBy); 10 | 11 | app.use( 12 | cors({ 13 | origin: ["https://example.ru", "http://localhost:3001"], 14 | }) 15 | ); 16 | 17 | app.use( 18 | helmet({ 19 | contentSecurityPolicy: { 20 | useDefaults: true, 21 | directives: { 22 | scriptSrc: [ 23 | "'self'", 24 | "'unsafe-inline'", 25 | "https://cdn.jsdelivr.net", 26 | "https://code.jquery.com", 27 | ], 28 | }, 29 | }, 30 | }) 31 | ); 32 | 33 | // app.use(helmet.contentSecurityPolicy()); 34 | // app.use(helmet.crossOriginEmbedderPolicy()); 35 | // app.use(helmet.crossOriginOpenerPolicy()); 36 | // app.use(helmet.crossOriginResourcePolicy()); 37 | // app.use(helmet.dnsPrefetchControl()); 38 | // app.use(helmet.expectCt()); 39 | // app.use(helmet.frameguard()); 40 | // app.use(helmet.hidePoweredBy()); 41 | // app.use(helmet.hsts()); 42 | // app.use(helmet.ieNoOpen()); 43 | // app.use(helmet.noSniff()); 44 | // app.use(helmet.originAgentCluster()); 45 | // app.use(helmet.permittedCrossDomainPolicies()); 46 | // app.use(helmet.referrerPolicy()); 47 | // app.use(helmet.xssFilter()); 48 | 49 | const limiter = rateLimiter({ 50 | windowMs: 1 * 60 * 1000, 51 | max: 120, // limit each IP to 120 requests per minute 52 | }); 53 | 54 | const speedLimiter = slowDown({ 55 | windowMs: 1 * 60 * 1000, 56 | delayAfter: 100, // allow 100 requests per minute, 57 | delayMs: 1000, // adding 1000ms of delay per request above 100 58 | // request # 101 is delayed by 1000ms 59 | // request # 102 is delayed by 2000ms 60 | }); 61 | 62 | app.use(speedLimiter); 63 | app.use(limiter); 64 | } 65 | 66 | module.exports = { secure }; 67 | -------------------------------------------------------------------------------- /ch2/part9/server/middlewares/security.js: -------------------------------------------------------------------------------- 1 | const { disablePoweredBy } = require("./disablePoweredBy"); 2 | 3 | const cors = require("cors"); 4 | const helmet = require("helmet"); 5 | const rateLimiter = require("express-rate-limit"); 6 | const slowDown = require("express-slow-down"); 7 | 8 | function secure(app) { 9 | app.use(disablePoweredBy); 10 | 11 | app.use( 12 | cors({ 13 | origin: ["https://example.ru", "http://localhost:3001"], 14 | }) 15 | ); 16 | 17 | app.use( 18 | helmet({ 19 | contentSecurityPolicy: { 20 | useDefaults: true, 21 | directives: { 22 | scriptSrc: [ 23 | "'self'", 24 | "'unsafe-inline'", 25 | "https://cdn.jsdelivr.net", 26 | "https://code.jquery.com", 27 | ], 28 | }, 29 | }, 30 | }) 31 | ); 32 | 33 | // app.use(helmet.contentSecurityPolicy()); 34 | // app.use(helmet.crossOriginEmbedderPolicy()); 35 | // app.use(helmet.crossOriginOpenerPolicy()); 36 | // app.use(helmet.crossOriginResourcePolicy()); 37 | // app.use(helmet.dnsPrefetchControl()); 38 | // app.use(helmet.expectCt()); 39 | // app.use(helmet.frameguard()); 40 | // app.use(helmet.hidePoweredBy()); 41 | // app.use(helmet.hsts()); 42 | // app.use(helmet.ieNoOpen()); 43 | // app.use(helmet.noSniff()); 44 | // app.use(helmet.originAgentCluster()); 45 | // app.use(helmet.permittedCrossDomainPolicies()); 46 | // app.use(helmet.referrerPolicy()); 47 | // app.use(helmet.xssFilter()); 48 | 49 | const limiter = rateLimiter({ 50 | windowMs: 1 * 60 * 1000, 51 | max: 120, // limit each IP to 120 requests per minute 52 | }); 53 | 54 | const speedLimiter = slowDown({ 55 | windowMs: 1 * 60 * 1000, 56 | delayAfter: 100, // allow 100 requests per minute, 57 | delayMs: 1000, // adding 1000ms of delay per request above 100 58 | // request # 101 is delayed by 1000ms 59 | // request # 102 is delayed by 2000ms 60 | }); 61 | 62 | app.use(speedLimiter); 63 | app.use(limiter); 64 | } 65 | 66 | module.exports = { secure }; 67 | -------------------------------------------------------------------------------- /ch2/part9/client/src/Home.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Button, 3 | Container, 4 | FormControl, 5 | FormErrorMessage, 6 | FormLabel, 7 | Heading, 8 | Input, 9 | Stack, 10 | useToast, 11 | } from "@chakra-ui/react"; 12 | import { useCallback } from "react"; 13 | import { useForm } from "react-hook-form"; 14 | 15 | interface ShortenerInfo { 16 | alias: string; 17 | link: string; 18 | } 19 | 20 | export function Home() { 21 | const { 22 | handleSubmit, 23 | register, 24 | reset, 25 | formState: { errors, isSubmitting }, 26 | } = useForm(); 27 | const toast = useToast(); 28 | 29 | const onSubmit = useCallback(async (values: ShortenerInfo) => { 30 | const response = await fetch("http://localhost:3000/alias", { 31 | method: "POST", 32 | headers: { 33 | Accept: "application/json", 34 | "Content-Type": "application/json", 35 | }, 36 | body: JSON.stringify({ alias: values.alias, link: values.link }), 37 | }); 38 | 39 | if (response.ok) { 40 | reset(); 41 | 42 | toast({ 43 | title: "Alias created!", 44 | description: `Alias "${values.alias}" now redirects to ${values.link}`, 45 | status: "success", 46 | duration: 3000, 47 | isClosable: true, 48 | }); 49 | } else { 50 | toast({ 51 | title: "Error", 52 | description: await response.text() || 'Unknown error...', 53 | status: "error", 54 | duration: 3000, 55 | isClosable: true, 56 | }); 57 | } 58 | }, []); 59 | 60 | return ( 61 | 62 |
63 | 64 | 65 | Add new alias 66 | 67 | 68 | 69 | Alias 70 | 77 | 78 | {errors.alias && errors.alias.message} 79 | 80 | 81 | 82 | 83 | Full link 84 | 92 | 93 | {errors.link && errors.link.message} 94 | 95 | 96 | 104 | 105 |
106 |
107 | ); 108 | } 109 | -------------------------------------------------------------------------------- /ch2/part8/client/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Button, 3 | Container, 4 | FormControl, 5 | FormErrorMessage, 6 | FormLabel, 7 | Heading, 8 | Input, 9 | Stack, 10 | useToast, 11 | } from "@chakra-ui/react"; 12 | import { useCallback } from "react"; 13 | import { useForm } from "react-hook-form"; 14 | 15 | interface ShortenerInfo { 16 | alias: string; 17 | link: string; 18 | } 19 | 20 | function App() { 21 | const { 22 | handleSubmit, 23 | register, 24 | reset, 25 | formState: { errors, isSubmitting }, 26 | } = useForm(); 27 | const toast = useToast(); 28 | 29 | const onSubmit = useCallback(async (values: ShortenerInfo) => { 30 | const response = await fetch("http://localhost:3000/alias", { 31 | method: "POST", 32 | headers: { 33 | Accept: "application/json", 34 | "Content-Type": "application/json", 35 | }, 36 | body: JSON.stringify({ alias: values.alias, link: values.link }), 37 | }); 38 | 39 | if (response.ok) { 40 | reset(); 41 | 42 | toast({ 43 | title: "Alias created!", 44 | description: `Alias "${values.alias}" now redirects to ${values.link}`, 45 | status: "success", 46 | duration: 3000, 47 | isClosable: true, 48 | }); 49 | } else { 50 | toast({ 51 | title: "Error", 52 | description: await response.text() || 'Unknown error...', 53 | status: "error", 54 | duration: 3000, 55 | isClosable: true, 56 | }); 57 | } 58 | }, []); 59 | 60 | return ( 61 | 62 |
63 | 64 | 65 | Add new alias 66 | 67 | 68 | 69 | Alias 70 | 77 | 78 | {errors.alias && errors.alias.message} 79 | 80 | 81 | 82 | 83 | Full link 84 | 92 | 93 | {errors.link && errors.link.message} 94 | 95 | 96 | 104 | 105 |
106 |
107 | ); 108 | } 109 | 110 | export default App; 111 | --------------------------------------------------------------------------------