diff --git a/.idea/jsLibraryMappings.xml b/.idea/jsLibraryMappings.xml new file mode 100644 index 0000000..a78957c --- /dev/null +++ b/.idea/jsLibraryMappings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..eabe228 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..0a1241c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/part-1-task-3.iml b/.idea/part-1-task-3.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/part-1-task-3.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml new file mode 100644 index 0000000..9338ba6 --- /dev/null +++ b/.idea/watcherTasks.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..0077e1a --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,585 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project + + + + + + + + + + + + + + + + project + + + true + + + + DIRECTORY + + false + + + + + + + + + + + + + + + + + + + + 1476611106297 + + + 1476623988209 + + + 1476624544258 + + + 1476638072104 + + + 1476644622372 + + + 1476651839623 + + + 1476655805685 + + + 1476661035060 + + + 1476661382488 + + + 1476798131584 + + + 1476798680520 + + + 1476798863390 + + + 1477510805212 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.js b/index.js index c79da1a..9d6e2bd 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,11 @@ const express = require('express'); const app = express(); +const fs = require('fs'); +const path = require('path'); +const Transliterator = require('./transliterator'); + +//---------------Server Part------------- const PORT = process.env.PORT || 4000; @@ -9,5 +14,109 @@ app.listen(PORT, function () { console.log(`App is listen on ${PORT}`); }); +//Set timer middleware +app.use(function (req, res, next) { + req.timer = process.hrtime(); + next(); +}); + +//---------Middle-wares---------------- + +//Request url middle-ware +app.use(function (req, res, next) { + let reqUrl = req.method + ' ' + req.url; + res.set('X-Request-Url', reqUrl); + console.log(reqUrl); + next(); +}); + +//Cookie parser middleware +app.use(function (req, res, next) { + req.cookies = {}; + let array = []; + if (req.headers.cookie) { + array = req.headers.cookie.replace('; ', ';').split(';'); + } + for (let i = 0; i < array.length; i++) { + let cookie = array[i].split('='); + req.cookies[cookie[0]] = cookie[1]; + } + next(); +}); + +//Check auth middleware +app.use(function (req, res, next) { + if (!req.cookies.authorize) { + throw { + status: 403, + message: 'User unauthorized' + }; + } + next(); +}); + +app.get('/', function (req, res) { + throw { + status: 503, + message: 'Unknown request' + } +}); + +//------------Log Timer------------- + +//Set timer middleware +app.use(function (req, res, next) { + let time = process.hrtime(req.timer); + let formatTime = Number(time[0] + '.' + time[1]).toFixed(3); + res.set('X-Time', formatTime); + console.log(formatTime); + next(); +}); + +//-----------Routes----------------- + +app.get('/v1/*', function (req, res) { + let rawurl = __dirname + req.url.replace('/v1', ''); + let url = path.normalize(rawurl); + if (url.indexOf(__dirname) === -1) { + throw { + status: 400, + message: 'Wrong path' + } + } + if (fs.lstatSync(url).isDirectory()) { + fs.readdir(url, function (err, files) { + if (err) throw err; + let result = ['.', '..']; + res.status(200).send({content: result.concat(files)}); + }); + } else { + res.set('Content-type', 'application/json'); + let rstream = fs.createReadStream(url); + let tstream = new Transliterator(); + rstream + .pipe(tstream) + .pipe(res); + } +}); + +//-----------Error Handler---------- + +app.use(function (err, req, res, next) { + if (err) { + res.set('X-Request-Error', err.message); + res.status(err.status).send(err.message); + } +}); + +app.use(function (req, res, next) { + let err = { + status: 404, + message: 'Unknown request' + }; + res.set('X-Request-Error', err.message); + res.status(err.status).send(err.message); +}); + // IMPORTANT. Это строка должна возвращать инстанс сервера -module.exports = app; +module.exports = app; \ No newline at end of file diff --git a/tester b/tester new file mode 100644 index 0000000..9daeafb --- /dev/null +++ b/tester @@ -0,0 +1 @@ +test diff --git a/transliterator.js b/transliterator.js new file mode 100644 index 0000000..ae01255 --- /dev/null +++ b/transliterator.js @@ -0,0 +1,110 @@ +const Transform = require('stream').Transform; + +const rus = { + 'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Jo', + 'Ж': 'Zh', 'З': 'Z', 'И': 'I', 'Й': 'J', 'К': 'K', 'Л': 'L', 'М': 'M', + 'Н': 'N', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', + 'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Shh', + 'Ъ': '#', 'Ы': 'Y', 'Ь': '\'', 'Э': 'Je', 'Ю': 'Ju', 'Я': 'Ja' +}; + +(function () { + for (let key in rus) { + rus[key.toLowerCase()] = rus[key].toLowerCase(); + } +})(); + +const en = { + 'A': 'А', 'B': 'Б', 'C': 'Ц', 'D': 'Д', 'E': 'Е', 'F': 'Ф', + 'G': 'Г', 'H': 'Х', 'I': 'И', 'J': 'Й', 'K': 'К', 'L': 'Л', + 'M': 'М', 'N': 'Н', 'O': 'О', 'P': 'П', 'Q': 'Я', 'R': 'Р', + 'S': 'С', 'T': 'Т', 'U': 'У', 'V': 'В', 'W': 'Щ', 'X': 'Х', + 'Y': 'Ы', 'Z': 'З', '\'': 'ь', '#': 'ъ' +}; + +const enSpecial = { + 'Jo': 'Ё', 'Yo': 'Ё', 'Ju': 'Ю', 'Yu': 'Ю', 'Ja': 'Я', 'Ya': 'Я', + 'Je': 'Э', 'Sh': 'Ш', 'Zh': 'Ж', 'Ch': 'Ч' +}; + +const enShh = ['shh', 'Shh', 'SHh', 'SHH', 'ShH']; + +(function () { + for (let key in enSpecial) { + enSpecial[key.toLowerCase()] = enSpecial[key].toLowerCase(); + enSpecial[key.toUpperCase()] = enSpecial[key].toUpperCase(); + } +})(); + +(function () { + for (let key in en) { + en[key.toLowerCase()] = en[key].toLowerCase(); + } +})(); + +class Transliterator extends Transform { + constructor(options, lang) { + super(options); + if (lang === 'en') { + this.dictionary = en; + this.dictionaryName = 'en'; + } else if (lang === 'rus') { + this.dictionary = rus; + this.dictionaryName = 'rus'; + } + this._alreadyBeg = false; + this._alreadyEnd = false; + } + + _transform(chunk, encoding, callback) { + let str = chunk.toString('utf8'); + let formatted = ''; + if (!this._alreadyBeg) { + this.push('{"content": "'); + } + for (let i = 0; i < str.length; i++) { + if (!this.dictionary) { + if (str[i] in rus) { + this.dictionary = rus; + this.dictionaryName = 'rus'; + } else if (str[i] in en) { + this.dictionary = en; + this.dictionaryName = 'en'; + } + } + if (this.dictionaryName === 'en') { + if ((i < str.length - 2) && (enShh.indexOf(str[i] + str[i + 1] + str[i + 2]) !== -1)) { + formatted += (str[i] === 's') ? 'щ' : 'Щ'; + i += 2; + } else { + if ((i < str.length - 1) && ((str[i] + str[i + 1]) in enSpecial)) { + formatted += enSpecial[str[i] + str[i + 1]]; + i += 1; + } else { + if (str[i] in this.dictionary) { + formatted += this.dictionary[str[i]]; + } else { + formatted += str[i]; + } + } + } + } else if (this.dictionary && str[i] in this.dictionary) { + formatted += this.dictionary[str[i]]; + } else { + formatted += str[i]; + } + } + this.push(formatted.replace(/"/g, '\"')); + callback(); + } + + _flush(callback) { + if (! this._alreadyEnd) { + this.push('"}'); + } + + callback(); + } +} + +module.exports = Transliterator; \ No newline at end of file