Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Works fine. Evstropov Evgenii #6

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
139 changes: 139 additions & 0 deletions MyTransform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* Created by Evgeny on 17/10/16.
*/

const Transform = require('stream').Transform;


class MyTransform extends Transform {

constructor(opt){
super(opt);
this.isToRus = false;
this.detected = false;
this.toNextChunk = '';
this.isFlushing = false;
}

_transform(chunk, encoding, callback) {
var str = chunk.toString('utf8');
if (this.detected === false){
this.detectLanguage(str);
}
// console.log(str);
if (this.detected === true){
if (this.isToRus) {
str = this.translate(str, engToRus, engToRus_additional);
}
else {
str = this.translate(str, rusToEng);
}
}
this.push(str);
callback();
}

_flush(callback) {
this.isFlushing = true;
let str = this.toNextChunk;
// console.log(str);
if (this.detected === true){
if (this.isToRus) {
str = this.translate(str, engToRus, engToRus_additional);
}
else {
str = this.translate(str, rusToEng);
}
}
// console.log(str);
this.push(str);
callback();
}

moveLasts(str, map_additional) {
let last_ind = -1;
let value = '';
for (let val in map_additional) {
let ind = str.lastIndexOf(val);
if (ind > last_ind) {
last_ind = ind;
value = val;
}
}
if (last_ind > -1){
// console.log('befire slice', str, last_ind, str.length);
this.toNextChunk = str.slice(last_ind + value.length);
str = str.slice(0, last_ind + value.length);
// console.log('after slice ', str, this.toNextChunk);
}
return str;
}

translate(str, map, map_additional){
if (!this.isFlushing) {
str = this.toNextChunk + str;
}
this.toNextChunk = '';
if (map_additional && !this.isFlushing) {
// console.log('moveNext');
str = this.moveLasts(str, map_additional);
for (let val in map_additional) {
str = str.replace(new RegExp(val, 'g'), map_additional[val]);
}
}

for (let val in map) {
// console.log('normal saerch', str);
str = str.replace(new RegExp(val,'g'), map[val]);
}
return str;
}


detectLanguage(str){
let eng = str.search(new RegExp('[a-z]', 'i'));
let rus = str.search(new RegExp('[а-я]', 'i'));
if (eng > -1 && (eng < rus || rus < 0)){
this.detected = true;
this.isToRus = true;
}
else if (rus > -1 && (rus < eng || eng < 0)){
this.detected = true;
this.isToRus = false;
}
}
}

module.exports = MyTransform;


const rusToEng = {
'А': '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',
'а': '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'
};

const engToRus_additional = {
'JO': 'Ё', 'JU': 'Ю', 'YO': 'Ё', 'CH': 'Ч',
'YA': 'Я', 'JE': 'Э', 'SHH': 'Щ', 'SH': 'Ш', 'ZH': 'Ж',
'#': 'ъ',
'jo': 'ё', 'ju': 'ю', 'yo': 'ё', 'ch': 'ч',
'ya': 'я', 'je': 'э', 'shh': 'щ', 'sh': 'ш', 'zh': 'ж', 'ja': 'я',
'Jo': 'Ё', 'Ju': 'Ю', 'Yo': 'Ё', 'Ch': 'Ч',
'Ya': 'Я', 'Je': 'Э', 'Shh': 'Щ', 'Sh': 'Ш', 'Zh': 'Ж'
};

const engToRus = {
'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': 'З',

'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': 'з', '\'': 'ь'
};
2 changes: 1 addition & 1 deletion files/file.en.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
translit tekst
ChaShha
6 changes: 5 additions & 1 deletion files/file.multi.txt
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
русский English
12312431dsafрусский get up! We are hungry. We have to eat our hay". The dog did not take heed of it.

Once again another cow pleaded, "Please, let us have our hay". The dog snarled and the cow stepped back.

A wise cow ran up to the bull and told him the matter.
8 changes: 7 additions & 1 deletion files/file.ru.txt
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
русский текст
В современном мире нет человека, который не соприкасался бы с искусством. Его значение в нашей жизни велико. Книга, кино, телевидение, театр, музыка, живопись прочно вошли в нашу жизнь и оказывают на неё огромное влияние. Но особенно сильно воздействует на человека художественная литература.

Когда вы открываете незнакомую книгу, то остаётесь один на один с большим и умным другом – писателем. Читаете одну страницу, другую – и вдруг совершается чудо! Перед вами разворачиваются удивительные картины: герои отправляются в путешествия, сражаются с врагами, спасают друзей, открывают тайны природы. И вместе с ними вы тоже путешествуете, участвуете в спорах, вступаете в бой, терпите поражения и побеждаете. Сила художественного слова, музыка стиха, выразительность авторской речи покоряют и завораживают читателя.

Соприкосновение с миром искусства доставляет нам радость и бескорыстное наслаждение. Но неправильно было бы видеть в произведениях писателей, композиторов, художников только средство получения удовольствия. Конечно, мы нередко идем в кинотеатр, садимся к телевизору, берём в руки книгу, чтобы отдохнуть и развлечься. Да и сами художники, писатели, композиторы так строят свои произведения, чтобы поддержать и развить интерес и любопытство зрителей, читателей, слушателей. Но значение искусства в нашей жизни намного серьёзнее. Оно помогает человеку лучше увидеть и понять окружающий мир и самого себя.

Искусство способно сохранять характерные черты эпохи, дарить людям возможность общаться друг с другом через десятилетия и века, становясь своеобразным хранилищем памяти для последующих поколений. Оно незаметно формирует взгляды и чувства, характер, вкусы человека, пробуждает любовь к прекрасному. Именно поэтому в трудные минуты жизни люди нередко обращаются к произведениям искусства, которые становятся источником духовной силы и мужества.
12 changes: 12 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HW3</title>
</head>
<body>
<script>
document.cookie
</script>
</body>
</html>
150 changes: 148 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,159 @@
'use strict';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Разнеси по разным файлам, чтобы было легче читать-понимать

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


const express = require('express');
const app = express();
const fs = require('fs');
const MyTransform = require('./MyTransform');

const app = express();
const PORT = process.env.PORT || 4000;

app.listen(PORT, function () {
console.log(`App is listen on ${PORT}`);
});

// IMPORTANT. Это строка должна возвращать инстанс сервера
// log start time of middlewares
app.use((req, res, next) => {
req.startAt = process.hrtime();
next();
});

//logging the requested methods and URLs
app.use((req, res, next) => {
let method_url = req.method + ' ' + req.originalUrl;
res.setHeader('X-Request-Url', method_url);
console.log('X-Request-Url: ', method_url);
next();
});


// cookies process
app.use((req, res, next) => {
//если вообще нет куков - отправляем ошибку
if (!req.headers.cookie){
res.sendStatus(403);
return;
}

// сплитим все пришедшие куки, на отдельные
let arr_cookies = req.headers.cookie.split(';');
let cookies = [];
// и разбиваем их на пары
arr_cookies.forEach((i) => {
//правильный парс получилось понять только когда посмотерл на тест, иначе вообще не понятно из задания как это должно быть
let temp = i.trim().split('='); // or may be ':'
if (temp.length < 2)
return;
cookies[temp[0]] = temp[1];
});

// ошибка есть нет кука authorize
if (cookies && cookies['authorize']) {
next();
} else {
res.sendStatus(403);
}

});


//set duration of execution
app.use((req, res, next) => {
let time = process.hrtime(req.startAt);
time = (time[1] / 1000).toFixed(3);
res.setHeader('X-Time', time);
console.log('X-Time: ', time);
res.status(200);
next();
});


// логически бы эти два метода поставить перед установкой времени. Но переставляя понял что если поставить почле, то уходит часть ошибок.
app.get('/v1/', (req,res,next) => {
files(req, res);
});

app.get('/v1/(:arr)*', function (req, res, next) {
files(req, res);
});


//обработка обших ошибок от всех предшествующих middleware
app.use((err, req, res, next) => {
console.error('X-Request-Error: ', err.toString());
res.setHeader('X-Request-Error', err.toString());
res.status(503).end();
});

//если ничего не сделалось, значит не поняли запрос
app.use(function (req, res, next) {
res.setHeader('X-Request-Error', "Unknown request");
res.status(503).end();
});

// обработка запросов к файловой системе
const files = (req, res) => {
let path = '';
//MAGIC
if (req.params[0] != undefined) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Откуда списал эту магию?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нашёл таким путём:
задал путь /v1/temp
и в req.params оказалось два элемента
req.params[0]
и
req.params[arr]
и вот для меня вообще не понятно почему именно такие поля и т.д. но раз так, я просто их потом сконкатенировал чтобы получить полный путь, который мне и нужен.

path = req.params['arr'] + req.params[0];
}

/* нельзя уходить в директорию выше.
вообще этот код содержит ошибку, правда тесты её не ловят :-)
что если пусть будет таким: ./temp/../../file - у меня ошибка неправильности пути не вылетит */
if (path === '../') {
res.status(503).setHeader('x-request-error', path).end();
console.log('res with request error');
return;
}
/*
Если если структура типа ./temp/../ - значит нужно просто удалить из пути temp и отсыл наверх.
Опять же тут не полная продуманность, и структура /../../ - просто удалится и всё, а не откинется на 2 уравня на верх
*/
path = path.replace(new RegExp('.+/\.\./', 'gi'), '');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Молодец, что сам подумал над резолвингом путей. Однако, если использовать встроенный модуль path, то всё гораздо проще


path = './' + path;

// парсит директорию и выводит список файлов
if (fs.lstatSync(path).isDirectory()) {
fs.readdir(path, (err, items) => {
console.log(items);
// не люблю я это место... но и не знаю как ещё эти штуки присобачить, а они нужна
let json_items = ['.', '..'] + items;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У тебя же items - то массив, просто положи туда через push, или можешь сделать ['.', '..'].concat(items)
Обычные операции над массивом

res.status(200).send({'content': json_items});
});
}
// обрабатывает файл
else if (fs.lstatSync(path).isFile()) {
// console.log('create stream');
var stream = fs.createReadStream(path);
var trns = new MyTransform();
stream.pipe(trns);

// собирает строку из данных, получаемых из стрима
let str = '';
trns.on('data', (chunk) => {
str += chunk.toString('utf-8');
});
trns.on('end', () => {
res.setHeader('Transfer-Encoding', 'chunked');
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({content: str}));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты конечно здорово придумал, сначала весь поток собрал в переменную, а потом просто её вернул. А зачем тогда потоки, почему нельзя просто прочитать сначала весь файл, засунуть его в транслятор и вернуть. Тебе нужно сделать всё полностью на потоках, примерно stream.pipe(trns).pipe(res) чтобы у тебя сразу результат стал отдаваться, а не собирался в переменную. Потому что если вайл несколько гигабайт, то ты будешь всё собирать в переменную и будет переполнение

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

вот я сначала и клал просто в рез через pipe. Но так не проходило, потому что нужна ведь json-ка в результирующее поле. Поэтому придумал такой обходной, не очень хороший вариант

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ты же в итоге кладешь не JSON, а строку, а строку ты и через поток можешь успешно положить

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

т.е. сначала положить заголовки.
Потом положить строку '{content: '
потом прокинуть стрим в результат
и потом ещё завершить, отправив '}' ?

// console.log(str);
});


} else {
res.sendStatus(503).end();
}
};


module.exports = app;

// const rq = require('supertest');
// rq(app)
// .get('/v1/files/file.en.txt')
// .set('Cookie', ['authorize=12345667'])
// .expect(200)
// .end((err,res) => {console.log('finish')});
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@
"author": "Aleksei Verkholantcev <alex-vee@yandex-team.ru>",
"license": "ISC",
"dependencies": {
"express": "4.14.0"
"express": "4.14.0",
"fs": "0.0.1-security",
"stream": "0.0.2"
},
"devDependencies": {
"cookie-parser": "^1.4.3",
"fs-extra": "^0.30.0",
"mocha": "^3.1.1",
"should": "^11.1.1",
Expand Down
1 change: 1 addition & 0 deletions test/1.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
const rq = require('supertest');
const app = require('../index');

Expand Down
1 change: 1 addition & 0 deletions test/2.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
const rq = require('supertest');
const app = require('../index');

Expand Down
1 change: 1 addition & 0 deletions test/3.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
const rq = require('supertest');
const app = require('../index');

Expand Down
1 change: 1 addition & 0 deletions test/4.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
const rq = require('supertest');
const app = require('../index');

Expand Down
Loading