ВВЕДЕНИЕ
Данный пост подразумевает хорошее интро в N2O на русском.
Что такое Erlang/OTP Web Framework N2O и в чём его основные черты, можно узнать на странице в github и официальном сайте SynRC. Там всё как вы любите с графиками и презентациями.
А здесь рассмотрим принципы работы фреймворка и поговорим о вечном.
Рассматриваемая версия N2O: 1.1.0
Всегда интереснее видеть результат, нежели говорить о нём, предлагаю сначала установить N2O себе на компьютер а уже потом вникать в его внутренности. Так нагляднее.
Получить ответы на возникшие вопросы и увидеть рекомендации можно на официальном канале IRC #n2o на FreeNode.net.
УСТАНОВКА
Устанавливаем Erlang если он ещё не установлен. Установили.
Скачиваем N2O, компилируем и запускаем:
git clone git://github.com/5HT/n2o.git cd n2o/samples make && make console
Смотрим: http://127.0.0.1:8000/

Открыв несколько окон можно початиться самому с собой.
МНОГО ТЕОРИИ
НИША
Предназначен в первую очередь для разработки горизонтально масштабируемых решений с низкой задержкой на обработку клиентских запросов.
Онлайн-игры, чаты, инстаграммы, твиторы — это не совсем то, для чего создавался Erlang, но то, где нужно воспользоваться N2O.
ПОД КАПОТОМ
N2O это переработанный проект Nitrogen который немного загрустил. В N2O мы имеем быстрейший вэб сервер Cowboy, работу через WebSockets, обмен бинарными данными везде где только возможно, HTML и DTL шаблоны, минимальное количество JavaScript без использования сторонних библиотек.
Сравнение веб-фреймворков на Erlang можно увидеть по ссылке.
Возможность использования:
- NoSQL решений, таких как Mnesia, RIAK, KAI через простую абстрактную модель в виде приложения KVS.
- Библиотеки авторизации AVZ (Facebook, Google, Twitter, Github, Microsoft).
- Библиотеки MQ-очередей MQS для RabbitMQ.
- Интерпретатора Erlang кода в JavaScript с возможностью проверки во время компиляции — Shen.
- Любых других Erlang решений, просто добавив в приложение.
В N2O реализована компиляция исходников на лету, даже без порчи открытых сессий, на основе Sync. Разработка становится всё человечнее.
С Sync ты можешь кодить без дрочилова (перев.)
Обмен данными сервера с клиентами реализуется посредством WebSockets и имеет минимальный оверхед. Возможные форматы передаваемых данных:
- BLOB (RAW Binary), идеально для изображений
- Bert Encoded, для Erlang-термов
- Pickled, закодированные данные в Base64, либо AES/RIPEMD160
Кластеризация и отказоустойчивость для Веба стала доступна как никогда прежде, с максимальной простотой разработки.
_5HT: Чтобы ты не е___cя. Твое дело клац-клац и в продакшен
МОДЕЛЬ ПОВЕДЕНИЯ
N2O построен как и сам Erlang на передаче сообщений, но только не от процесса к процессу, а от клиента к серверу. Назову это событийной моделью.
Опишем таймлайн работы встроенного в N2O примера n2o_sample.
- При запросе страницы
/indexбраузеру передаётся HTML разметка, описанная в функцииindex:body(). - На странице выполняется JavaScript, инициализирующий подключение через WebSocket.
- Затем по WebSocket передаётся полезная нагрузка в виде JavaScript кода, и инициализации элементов страницы данными через
index:event(init). Здесь одна из ролей JavaScript — например, создать для кнопки на клиенте событие в виде JS-функции, которая отправит на сервер информацию о нажатии. - После клацанья по кнопке, на сервер приезжает Bert-Encoded сообщение под
грибамиBase64 и выполняется функцияindex:event(Term)гдеTerm— это терм, описанный в поле рекорда кнопки:#button.postback. Например, кнопка#button{postback=sasay}после нажатия принудит выполниться функциюindex:event(sasay). - Сервер, в свою очередь, также в любое время может отсылать данные браузеру. Если данные шлются из другого процесса
Х, то должны быть соблюдены условия: вindex:event(init)главный процесс, обслуживающий клиента (вкладку браузера), должен быть зарегистрирован под неким именем вызовомwf:reg/1, а в процессеХпосле окончания генерации кода для обновления страницы (wf:insert/2,wf:wire/1и т.п.) должна быть вызвана функцияwf:flush/1для отправки кода обновления браузеру, где он затем будет выполнен JS-машиной.
Первое что приходит на ум — страница динамически изменяется не на основе вызовов функций из файла с JavaScript, а основываясь на полученном JavaScript от сервера в реальном времени.
И это нативный интерактивный режим для вэб-приложения без использования костылей вроде AJAX и LongPooling Comet. Будущее уже здесь, котята. Название ему — WebSockets.
Таблицу поддержки WS браузерами можно увидеть здесь, а проверить свой браузер здесь.
ПОДРОБНЕЕ О СТРУКТУРЕ ПРИЛОЖЕНИЙ
Если знакомство с Erlang произошло недавно или только что, скорее всего возникнут вопросы: что где лежит и в каком месте проявлять свой креатив.

Выделены те папки и файлы, которые могут быть подвержены редактированию. Рассмотрим ключевые части.
n2o_sample
N2O уже содержит в себе пример пользовательского приложения — n2o_sample. n2o_sample — это отдельное Erlang приложение, которое работает на N2O. Как видно на картинке выше, оно находится в директории apps/ — это коллекция пользовательских приложений, можем довавлять туда свои, если потребуется разделить n2o_sample на два или более независимых приложения.
Также n2o_sample, конечно же, можно переименовать или заменить чем-нибудь другим. Но для начала я бы не советовал этим заниматься, а пользоваться имеющимся кодом как отправной точкой в разработке своего приложения.
Application list
При запуске n2o_sample, он, как и полагается Erlang приложению, запускает все приложения от которых зависит (зависимости из deps/, и пользовательские, при их наличии, из apps/ ). Этот код находится в n2o_sample/src/web_app.erl:
-module(web_app). -behaviour(application). -export([start/2, stop/1]). start(_StartType, _StartArgs) -> application:start(crypto), application:start(sasl), application:start(ranch), application:start(cowboy), application:start(gproc), application:start(mimetypes), application:start(syntax_tools), application:start(compiler), application:start(erlydtl), application:start(rest), application:start(n2o) web_sup:start_link(). stop(_State) -> ok.
Функция web_sup:start_link() запускает сам n2o_sample.
Но если мы захотим расширить этот список зависимостей — надо знать, что это не единственное место с перечислением приложений. Также надо пофиксить ещё два файа: reltool.config и .applist, последний создаётся после первой команды make в консоли. Держать в трёх местах одно и то же — временный костыль от @darkproger, но он обещал всё пофиксить (обещанного три года ждут).
sys.config
Сюда сохраняются параметры для всех приложений. В один файл. Удобно. Потом из кода звоним в application:get_env(App,Key) и всё.
vm.args
Здесь можно указать ключи для виртуальной машины а также переменные окружения (вместо $ export SOME_PARAM=value).
priv/static/
Директория, переданная веб-серверу Cowboy как файлопомойка “статики”. Здесь можно размещать JavaScript код, закидывать пикчи и хентай. n2o_sample/src/web_sup.erl:
dispatch_rules() -> cowboy_router:compile( [{'_', [ {"/static/[...]", cowboy_static, {priv_dir, ?APP, <<"static">>, [{mimetypes,cow_mimetypes,all}]}}, ****
СТРАНИЦЫ
Для создания динамических страниц N2O даёт возможность включения HTML файлов в проект как DTL шаблоны. В директории deps/erlydtl/ находится приложение ErlyDTL которое предназначено для компиляции DTL шаблонов в Erlang байт-код.
Сами шаблоны располагаются в директории n2o_sample/priv/templates/ и выглядят как HTML файлы с объявлениями внешних источников данных через слова, заключённых в двойные фигурные скобки {{ }}.
Таким образом мы можем “накидать” HTML макет со статической информацией, а динамическую вынести в Erlang код через подключение {{ }}.
Для примера рассмотрим тело функции login:main/0, которая отдаёт браузеру первоначальное состояние страницы при переходе по адресу http://127.0.0.1/login/:
#dtl{ file = "login", app=n2o_sample, bindings=[ {title,title()}, {body,body()} ]}.
- Здесь
login— это имя шаблона: /priv/static/template/index.html; titleиbody— именованные включения в HTML шаблоне {{title}} и {{body}};title()иbody()— функции, результат которых будет подставлен в HTML шаблон.
СОБЫТИЯ
Обмен данными в N2O на клиенте реализован через JavaScript, с помощью подгружаемых на страницы файлов /deps/n2o_scripts/n2o/bullet.js (инициализация WebSocket подключения) и n2o.js (обработка полученных данных).
Со стороны сервера эндпоинтами служат: /n2o/src/endpoints/cowboy/bullet_handler.erl (инициализация WebSocket подключения) и n2o_bullet.erl (обмен данными).
API
Разберём основные API-функции, с которыми возникает больше всего вопросов при знакомстве с N2O.
wf:comet/1, wf:async/1, wf:async/2
Регистрируют процесс под уникальным именем (“comet” для comet/1 и async/1) в рамках ноды через global:register_name/2. Если уже зарегистрирован, возвращают его Pid.
wf:flush/1
Изымает через wf_context:actions/0 сохранённые в стейте текущего процесса изменения для страницы и отсылает их через wf:send/2 процессу (в рамках ноды), имя которого передано в параметре.
wf:reg/1, wf:reg/2 (?REGISTRATOR = n2o_mq)
Регистрируют процесс как Property под неуникальным именем в рамках ноды через GProc. Повторно зарегистрировать процесс через GProc под тем же именем не получится, состояние регистрации хранится в стейте процесса (get/1, put/1) и будет возвращён терм skip (n2o_mq.erl). Дополнительная инфа на русском по Gproc тут.
Регистратором по умолчанию является модуль n2o_mq но его можно переопределить, например для возможности регистрировать процессы в рамках кластера.
wf:send/2 (?REGISTRATOR = n2o_mq)
Отсылает сообщение, переданное в функцию вторым аргументом, процессу, зарегистрированному через wf:reg/1 или wf:reg/2.
wf:q/1
Извлекает данные, переданные от клиента через, так называемые, элементы обратной передачи, например:
body() -> [ #textbox{ id=message }, #button{ postback={button_pressed}, source=[message] } ]. event({button_pressed}) -> wf:info("Message: ~p",[wf:q(message)]);
В консоль будет напечатан текст, содержащийся на момент нажатия кнопки в текстбоксе.
wf:qs/1
Извлекает параметры из HTTP форм, например:
wf:qs(<<"x">>) извлечет <<"ABC">> если URL был бы http://localhost:8000/index?x=ABC.
wf:wire/1
Может принимать аргументом как JavaScript текст, так и рекоды событий, объявленные в секции “Actions” файла /n2o/include/wf.hrl, например: wf:wire(#alert{text="Привет!"}). JavaScript будет также обёрнут в #wire{actions=JS}, что приведет к конструкции wf:wire(#wire{sctions=JS}).
wf:update/2, wf:insert_top/2, wf:remove/1 и другие
Это частные случаи wf:wire/1, включающие готовый JavaScript код для изменения DOM в браузере клиента.
wf:info, wf:warning, wf:error
Это функции, которыми рекомендуется пользоваться, вместо error_logger:info_msg/1 и остальных соответственно.
wf:f, wf:to_list, wf:to_binary, wf:html_encode, wf:url_encode, wf:hex_encode и другие
Распологаются в секции “Convert and Utils API” файла /n2o/src/wf.erl. Все они являются надстройками над стандартными функциями Erlang, но более умные и не такие деревянные. wf:f — аналог io_lib:format, далее по списку функции-конвертеры принимающие на вход любой терм, затем более специфичные для веба функции. Нет смысла их все подробно здесь описывать, была цель только показать, что они существуют.
wf:pickle/1, wf:depickle/1 (?PICKLER = n2o_pickle)
Кодер и декодер термов для передачи системных вызовов между клиентом и сервером. n2o_pickle кодирует в Base64, а n2o_secret использующий AES/RIPEMD160 шифрование с произвольным ключом.
На этом по API всё, дополнительную информацию можно почерпнуть из официальной доки по N2O API.
СТОИТ ОБРАТИТЬ ВНИМАНИЕ
Ниже перечислены свободные программные продукты SynRC, способные ускорить в десятки раз вывод в продакшн Вашего проекта на Erlang.
KVS
KVS — абстрактная модель K-V noSQL базы данных, умеющая в подмножества (feeds) таблицы через двусвязные списки и вторичные индексы (kvs:index/3). На текущий момент возможно использование с Mnesia, RIAK и KAI.
AVZ
AVZ — система авторизации через Twitter, Google, Facebook, Github и Microsoft.
Shen
Shen — интерпретатор Erlang кода в JavaScript. Позволяет использовать компилятор Erlang для проверки JavaScript.
MQS
MQS — MQ библиотека для RabbitMQ.
Feeds
Feeds — обработчик пула команд поддержания согласованности данных на всех нодах кластера, также кэш сервер.
SkyLine
SkyLine — пример интернет-магазина на N2O.
COUNTACH
Countach — социальная система и расширенный магазин приложений. Production-ready. Использует KVS, AVZ и Feeds. Основан на VOXOZ.
VOXOZ
VOXOZ — Открытая Erlang облачная платформа (PaaS). Использует Docker, ErlangOnXen. Больше информации на blog.docker.io.
ЗАКЛЮЧЕНИЕ
Чтобы информация усваивалась равномерно, на этом пока всё. Отдельное спасибо @mtreskin за советы в выборе архитектуры и наводкой на nitrogen и n2o; а также @5HT за бесконечные консультации 24/7 в IRC.
ссылка на оригинал статьи http://habrahabr.ru/post/220841/
Добавить комментарий