GithubHelp home page GithubHelp logo

descript's Introduction

descript

Прокся и агрегатор данных, являющаяся в (каком-то смысле) аналогом xscript, но работающая с данными в формате json.

Подробнее в вики.

quick start

npm install
./descript --config test/config.js
# Open http://localhost:2000/hello.jsx in your favorite browser.

descript's People

Contributors

alexeyten avatar basvasilich avatar edoroshenko avatar i2r avatar pasaran avatar vitkarpov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

descript's Issues

de.file возвращает содержимое файла как json строку

При использовании options.template содержимое файла из de.file передается в шаблон обернутым в кавычки.

my.jsx:

de.object({
    script: de.file('my.js')
}, {
    template: 'my.tpl.js'
})

my.tpl.js:

function(object) {
    return '<script>' + object.script + '</script>';
}

my.js:

alert(1);

result:

<script>"alert(1);"</script>

Разные сигнатуры у guard и no.jpath.expr

Сейчас в options.guard можно задать либо строку, которая скомпилируется в jpath-выражение, либо просто функцию.
Предполагалось, что функция должна иметь сигнатуру (params, context), но, кажется, у скомпилированного jpath'а сигнатура другая: (params, params, context).

Ну и в других местах, где принимается функция или что-то jpath-образное, тоже нужно поправить.

Неправильно выставляется `options.dirname` у блоков, созданных через `de.*()`

Если в .jsx-файлах использовать функции de.file, de.http, ..., то поскольку в них никаких options не передается, используются дефолтные. Т.е. options.dirname совпадает с rootdir.

В частности, неправильно резолвятся файлы с шаблонами для таких блоков.

Block specific log method

Предложение:
добавить в базовый класс de.Block метод de.Block.prototype.log(context)
и дальше в каждом отдельном классе блоков (de.Block.Http, de.Block.Function и т.д.) переопределить его под нужды блока.

Это даст возможность в том числе переопределить формат лога у себя на проекте.
Могу это закодить, если это кому-то ещё интересно.
/cc @pasaran @alexeyten @edoroshenko

Убрать параметр options.params

Сейчас он странным образом интерферирует с кэшированием.
Концепция блока такова, что он только описывает откуда и как брать, но параметры всегда приходят в момент запуска блока (в метод run()).

В том единственном известном мне случае, когда используются params, можно обойтись чем-то другим.
Например, чтобы Block.Array принимал в качестве параметра массив параметров.

Переписать все на stream2

Кажется, что класс Result должен быть подклассов какого-то stream'а. Duplex или Transform, видимо.

Бонус не шибко большой, но будет красивше и вообще.
Скажем, для

{
    foo: 'http://foo.com',
    bar: 'http://bar.com
}

ответ от первого запроса (к http://foo.com) можно начинать стриммить сразу же, второй стрим стоит на паузе, пока не закончится первый.
Сам объект тоже возвращает стрим, скомбинированный из двух этих.
Если у блока нет опции result (которая модифицирует результат), то стриммить можно всегда сразу.
Подумать, что с опцией select* и т.д. Кажется, текущий интерфейс stream'ов не сохраняет результат.

Do not log block if guard is not met

Сейчас, даже если блок не выполняется (потому что не выполняется guard) - мы всё равно пишем в лог про этот блок ended (0ms).
Не понятно, есть ли от этого польза.
Разве что, guard может долго выполнятся и мы увидим время вычисления guard-а.
Может быть, лучше не логировать вообще такие блоки?
Или логировать guard failed?

Возможность задавать параметры вызова в рантайме

Сейчас у блоков есть метод params (который лучше было бы назвать bindParams), но им невозможно пользоваться из .jsx-файлов. Точнее, его можно вызвать и там, но это позволяет задать только статические параметры.

Видимо, таки нужно вернуть options.params, но.
Там может быть:

  • Функция с сигнатурой (params, context), возвращающая объект с новыми параметрами.

  • jresult-выражение (аналогичное тому, что в options.result):

    {
        'photo-id': '.id',
        'per-page': 20,
        'version': '"v0.2.24"' // вложенные кавычки!
    }
    

    Т.е. строки в правой части трактуются как jpath-выражения.
    При этом, если нужно передать статическую строку (кажется, что это не очень часто бывает), то ее нужно записывать в виде '"hello"'.

В предыдущем варианте options.params содержали просто статический объект с параметрами, что не позволяло нормально кэшировать такие блоки (т.к. они не должны зависеть от параметров).

/cc @chestozo

Раскрывать путь к сокету

https://github.com/pasaran/descript/blob/master/lib/de.script.js#L157

Вместо de.config.socket надо его раскрыть до полного пути на файловой системе.
Иначе в списке сокетов остаётся этот дефолтный огрызок ../server.sock и совсершенно непонятно как найти владельца. Команда lsof не срабатывает.

Ответ на fixme в следущей строке: сокету выставляется 0777, что бы в него мог писать и читать любой процесс, иначе nginx запущенный от www-data не сможет записать ничего в descript запущенный от тебя. В принципе надо бы сделать это настраиваемым, потому как в продакшне оба этих сервиса должны быть запущены от имени www-data.

Как правильно расширять de.server?

Мы сейчас переопределяем методы de.server.route и de.server.onrequest. И почему-то мне кажется, что второй метод мы переопределяем зря.

А как всё-таки правильно?

Передавать params в after/result

Сейчас params приходят первым параметром в before/beforeSelect/guard/....
А в after и result -- приходит result.

Как вариант, передавать всегда объект вида:

{
    params: params
}

или (в зависимости от наличия result):

{
    params: params,
    result: result
}

/cc @mmoo

Сделать возможность для указания таймаута к http запросам

Может случиться такой случай.

Делаем запрос в ручку, где nginx возвращает 504 через 5 секунд.
Nginx на машине, на которой крутится descript возвращает 504 через 3 сек.

В этом случае долгий запрос к бекнду может положить все клиентское приложение. А мы можем вывести пользователю, мол, что-то не работает, попробуйте попозже.

Да мы можем выводить крисивую страницу для 504 с описанием, что делать. Но если бекендов много и какой-то не критичный из них не отвечает, то весь интерфейс блокировать не хочется.

Переименовать selectAfter, selectBefore, after, before

Такое ощущение, что selectBefore не нужен вообще.
Ему сейчас на вход приходит объект params.
Может быть, нужно просто в state положить сразу все params -- т.е. сделать set_state_by_request. Хотя параметры из реквеста не совсем то же самое, что параметры блока.

Если прибить selectBefore, то можно оставить select, after, before.
В тех редких случаях, когда selectBefore нужен, его можно сделать просто в before.

Блок ошибок (de.error)

Хотелось бы иметь отдельный блок ошибок 'de.error'.

// Примеры из жизни
В моем случае у меня есть зарегистрированные модели. И если я пытаюсь вызвать модель, о которой сервер не знает, хотелось бы вернуть error через общий интерфейс блоков.

Или еще пример, когда доступ к модели ограничен правами пользователя.

Определять content-type ответа

В каждом de.Result.* нужно уметь определять его content-type и в ответе выставлять именно его, а не прибитый гвоздями.

Неразобранные планы на будущее

Чего нужно делать дальше. В совсем ближайшее время и попозже:

  • Тесты. Очень-очень нужны. Для этого нужно сделать хороший фейковый http-сервер, который будет уметь разное всякое (ошибки, таймауты и т.д.).
  • Пересмотреть de.script --- возможно, лучше сделать, чтобы был класс de.Script, который можно будет инстанцировать и запустить. А не синглтон, как сейчас. Как минимум, сделать так, чтобы модуль descript можно было бы использовать в других нодовских программах (например, из express).
  • Сделать предсказуемый кэш. Т.е. нужны ограничения на количество записей в кэше (количество занимаемой памяти?), инвалидация протухших кэшей и т.д.
  • Поддержка популярных шаблонизаторов из коробки.
  • Кастомные блоки? de.Block.Foo?
  • Сделать de.file и de.http приватными, унести их в de.block.js.
  • Какой-нибудь de.expr в .jsx-файлах. Чтобы, например, параметр сдампить в ответ.
  • Нужно уметь ходить по http с кастомными заголовками.
  • Нужно получать ответ http даже если вернулось не 200, опять-таки иметь доступ к заголовкам.
  • Возможность застопорить остальные блоки (незапущенные еще).

worker процесс рестарует после долгого простоя

Может быть это известная фича node.cluster?
У нас по логам получается, worker постоял примерно 3 минуты ничего не делая.
Когда приходит первый запрос после простоя - worker перезапускается.

Добавить в de.Request отдельное поле для IP

Сейчас мне приходится доставать его из request.headers['x-real-ip']. Хочется что бы он был где-нибудь поближе, например в request.ip.

Либо нужно где-то добавить возможность доопределять/переопределять объекты de.Context или de.Request.

Приоритеты нужно выставлять не блоку, а месту, в котором он используется

Например, если есть:

blockA = [ block1 +10, block2 ];
blockB = [ block1, block2 +10 ];

Сейчас первая строка выставит block1.priority = 10, а вторая в 20.
Т.е. получится не то, что хотелось.

Нужно приоритет хранить (в данном случае) в Block.Array.
А у блока своего приоритета нет вообще, видимо.

Сделать --disable-jsx-shortcuts

Нужен флажок, который запрещает интерпретировать обычные строки как блоки.
Т.е. http-блок создается только при помощи de.http(...).

Сделать options.cookies?

Возможно, нужно что-то такое.
Будет вызываться в районе after, описывается хэшиком: имя -> значение.

{
    cookies: {
        'id': '.data.id'
    }
}

jpath'ы вычисляются от result-а? или от params.
В общем не срочно. Нужно подумать.

Логирование в descript

Хотелось бы иметь логирование подобное в xscript'e.

Смортеть какой блок с какимим параметрами выполнился и длину контента которую он вернул.

В случае возникновения ошибок, хотелось бы иметь полный стректрейс ошибки.

Сейчас, если ломается js, то процесс глушится и nginx кидает 502.
Кажется, что дескрипт должен вернуть 503 и подробности.

Порядок отработки фаз run'а блока.

Сейчас в блок можно передать в options разные параметры, которые влияют на его выполнение:

  • params -- функция, вычисляющая новые параметры.
  • guard -- функция, которая говорит, нужно ли выполнять блок или нет.
  • before -- некий препроцессинг (непонятно, что именно она может сделать).
  • result -- функция, возвращающая новый результат (часть старого через jpointer, совсем что-то новое, ...).
  • select -- набор jpath-ов, которые добавляют в стейт что-то из результата.
  • after -- некий постпроцессинг, например, может положить в стейт что-то.

Все эти функции либо задаются собссно функцией с сигнатурой function(params, context), либо же компилируются из строки как jpath (в функцию с такой сигнатурой).

Если предположим у блока есть полный набор этих свойств, в каком порядке их нужно выполнять?

Вопросы в процессе рассказа про descript

  • Нужно уметь ходить по http с кастомными заголовками.
  • Нужно получать ответ http даже если вернулось не 200, опять-таки иметь доступ к заголовкам.
  • Возможность застопорить остальные блоки (незапущенные еще).

Проверки в jsx ручках

  1. Ручки, которые может вызывать только авторизованный пользователь (метод проверки авторизации при этом нужно писать уже на стороне сервиса, видимо).
  2. Ручки с проверкой типа запроса: нужно иметь возможность указывать для ручки разрешённые типы запроса: GET / POST / PUT.

При кэшировании результатов file-блоков, кэшировать raw-буферы

Сейчас кэшируются объекты de.Result.Raw, внутри которых лежит буфер.
Все более-менее хорошо, но при этом кэшируется и datatype, который берется из вызывающего блока. Например:

de.file('hello.txt', { datatype: 'text' })
de.file('hello.txt', { datatype: 'json' })

Для обоих блоков результат будет один и тот же (тот, который первым вызовется).

Видимо, кэшировать нужно raw-буферы, а обертку из de.Result.* создавать при запросе.

Починить JS API

Хочется чего-то такого:

var de = require('descript');

de.Block.compile('http://www.data.com?')
    .run({ id: 42 })
        .then(function(result) {
            console.log(result.object());
        });

Т.е. нужно определиться с местом хранения конфига.
Плюс что-то сделать с контекстом. Сейчас он сильно завязан на входящий request и response.

Data filtering

Есть de.Block.Http и он умеет получать данные по http.
Допустим, мой backend присылает во всех ручках какую-то системную информацию, которую я хочу фильтровать на стороне frontend.

Сейчас это можно сделать через options.result, но писать для всех ручек один и тот же метод фильтрации - не очень красиво.
Хочется унаследоваться от de.Block.Http и переопределить метод run, добавив туда фильтрацию.
Но конструктор у de.Block.Http содержит кучу логики - такие конструкторы сложно наследовать (надо изголяться с вызовом базового конструктора).

Пожелание: давайте максимально использовать пустые конструкторы :)

Добавить options.headers для de.Block.Http

Добавить options.headers для de.Block.Http что бы можно было указывать кастомные заголовки.

Пример использования:

de.http('URL', {
    proxy: false,
    headers: {
        'x-real-ip': 'request.headers.x-real-ip'
    }
})

Тип результата для текстовых файлов

Например, есть такой jsx-файл:

"hello.txt"

и вот такой:

{
    hello: "hello.txt"
}

Внутри hello.txt ну какой-то текст лежит. Скажем, Hello, World.
Что должен descript возвращать?

Hello, World

и

{
    "hello": "Hello, World"
}

?

Или же в первом случае должно быть:

"Hello, World"

?

Т.е. должен ли descript уметь отдавать не json контент?
Текстовые файлы, html, бинарные файлы и т.д.?

de.Block.abort()

Нужно научиться дропать выполнение блоков.
Это нужно для событий Connection aborted, к примеру - когда клиент не дождался и ушёл.

А сейчас поведение такое, что к нам пришло N запросов, мы создали N блоков и они выполняются. И даже, если клиент ушёл - выполнение продолжается.

Хочется как-то так:

req.connection.on('close',function(){    
    rootBlock.abort();
});

Content-Type: text/xml for xml templates

There's yate-template for xml and file.jsx that needs to be served for request, inside that one I have:

de.object({
       // some other data to collect
        ...
}, {
        after: function(params, context) {
             context.response.setHeader('Content-Type', 'text/xml');
        },
        template: 'template.{state.some}.js'
})

Response is supposed to have text/xml value of Content-Type header, but there is text/html anyway.

Поддержка options.template

Перблочное и перстраничное преобразование.
Должно быть можно указать имя js-ного файла, вида:

(function() {
    ...

    return function(data) {
        ...
        return html_string;
    };
})();

Вариант со стандартными нодовскими модулями мне не нравится. Их без хаков невозможно перегружать, если там что-то изменилось.
Проще эвалить.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.