суббота, 21 июля 2012 г.

Обзор веб-фреймворка Nitrogen

Nitrogen - веб-фреймворк написанный на Erlang. Главное достоинство этого фреймворка - возможность легко и быстро создавать интерактивные приложения взаимодействующие с сервером с помощью Ajax. Создание comet соединения требует буквально нескольких строк кода. Пример простейшего чата на основе Nitrogen занимает менее страницы кода.

Основной язык для Nitorgen это Erlang. Javascript явно не используется, хотя jQuery и используется для клиентской части. Специфика Erlang позволяет обойтись без зависимости от внешней базы данных для поддержки функционала сессий. Впрочем Erlang значительно упрощает предоставление общего доступа для всего кластера к данным находящимся на одном узле. Так же благодаря Erlang есть возможность использовать различные встроенные веб-сервера - встроенный inets, давно известный Yaws, недавно появившийся Cowboy. Руководство, документация.

Маршрутизация в Nitrogen динамическая. Она строится на основании имен модулей. Корень сайта это index.erl. Подчеркивания преобразуются в слеши, например: http://localhost:8000/routes/to/a/module будет обработан модулем routes_to_a_module.erl. Модуль выбирается по наиболее длинному совпадению: http://localhost:8000/routes/to/a/module/foo/bar будет обработан модулем routes_to_a_module.erl. Путь для которого не найден модуль обрабатывается модулем web_404.erl если он существует. Подробности

Страница рендерится из шаблона. Шаблон - это HTML файл с вставками вызовов функций Erlang [[[module:function(Args)]]]. Специальное имя модуля page ссылается на текущую страницу. Хотя вызов функции выглядит похожим на обычный код Erlang - это не так. Вызов функции должен обязательно быть в форме module:function(Args). Так же возможно задавать вызовы для Javascript в виде [[[script]]]. Подробности

Система шаблонов подходит для описания статичной раскладки страницы. Для динамических частей предназначены Элементы (Nitrogen Elements). Элемент это HTML или запись (Erlang record) с данными, которая рендерится в HTML. Пример простейшего элемента это #p{text="Text."} который будет отрендерен в <p class="wfid_temp790097 p">Text.</p>. Элементы могут быть вложенными и Элементы могут быть связаны с Действиями. Подробности

Действия (Nitrogen Actions) это Javascript код или запись (Erlang record) которая рендерится в Javascript. Действия могут быть включены в Элемент с использованием свойства action или связаны с Элементом с помощью функции wf:wire/N. Действие может быть простым визуальным эффектом или сложным взаимодействием с сервером. Действие иницируются объктами заданными в свойстве Триггер и изменяют объекты указанные в свойстве Цель. Действия работают на клиенте. Подробности

Передача контроля от клиента к серверу производится с помощью События (Nitrogen Event) у которого заполнено свойство postback=term. На сервере Событие обрабатывается функцией event/1. Используя wf:update/2, wf:insert_top/2, wf:insert_bottom/2, wf:replace/2, wf:remove/1 в функции event/1 можно изменять Элементы на клиенте. Подробности

События обычно инициируются клиентом. Когда нужно обновлять данные на клиенте постоянно используют технологию Comet. Comet инициируется клиентом как обычный запрос, но соединение не закрывается. Когда сервер имеет данные для клиента - сущестующее соединение используется для передачи данных. Nitrogen значительно упрощает использование Comet. Функции wf:comet/N запускают заданную функцию как независимый процесс. Этот процесс может сам собирать данные для клиента или ожидать данные от других процессов. Функция wf:send/2 позволяет отправить сообщение существующему процессу Comet. Подробности

Пример простейшего чата из Руководства:
body() -> 
    wf:comet_global(fun() -> repeater() end, repeater_pool),
    [
        #textbox { id=msg, text="Your message...", next=submit },
        #button { id=submit, text="Submit", postback=submit },
        #panel { id=placeholder }
    ].

event(submit) ->
    ?PRINT(wf:q(msg)),
    wf:send_global(repeater_pool, {msg, wf:q(msg)}).

repeater() ->
    receive 
        {msg, Msg} -> wf:insert_top(placeholder, [Msg, "<br>"])
    end,
    wf:flush(),
    repeater().

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

пятница, 15 апреля 2011 г.

Простейший способ открыть доступ к директории по http

Когда-то мне понадобилось перебросить данные между удаленными машинами.
Условия не то что бы особо сложные, но узкие места возникли сразу - данные надо
было залить на машины: с свежеустановленной Windows XP подключенной в
корпоративную сеть, на которую можно было зайти только через "Удаленный рабочий
стол" с весьма ограниченными правами; Mac Mini в том же сегменте что и машина с
Windows. Данные расположены на сервере в другом сегменте сети. Связь между
сегментами - только через http-прокси. Сервер с данными тоже не внушал вдохновения -
блейд с read-only корневой файловой системой смонтированной по НФС и без прав
редактирования образа. Веб-сервер на блейде естественно не установлен. Но на
выручку пришел Python - простая команда позволила запустить примитивный
http-сервер, с которого уже можно скачать данные используя Internet Explorer из
комплекта Windows и Safari из MacOS. Команда действительно проста:
python -m SimpleHTTPServer 9090
Эта команда запускает веб сервер с корнем в текущей директории на порту 9090
(впрочем порт можно использовать любой).

вторник, 30 ноября 2010 г.

Памятка для virtualevn, virtualenvwrapper and pip

Установка пакетов с помощью easy_install:

$ sudo easy_install virtualenv
$ sudo easy_install pip
$ sudo easy_install virtualenvwrapper


Добавить в ~/.bashrc:
# Путь к корневой директории виртульных окружений
export WORKON_HOME=$HOME/py_virtual_envs

# Для Arch этот путь отличается от стандартного
# /usr/local/bin/virtualenvwrapper_bashrc
source /usr/bin/virtualenvwrapper_bashrc


Теперь надо чтобы настройки вступили в действие:
$ source ~/.bashrc


Создание нового окружения - команда mkvirtualenv <имя окружения> или mkvirtualenv --no-site-packages <имя окружения>

Проверка:
$ workon
*
$ mkvirtualenv temp
New python executable in temp/bin/python
Installing setuptools............done.
$ workon
temp
$ mkvirtualenv temp2
New python executable in temp2/bin/python
Installing setuptools............done.
$ workon
temp
temp2
$ workon temp


Переход в директорию текущего виртуального окружения:
$ cd $VIRTUAL_ENV
$ pwd
/home/beast/py_virtual_envs/temp

$ workon temp2
$ cd $VIRTUAL_ENV
$ pwd
/home/beast/py_virtual_envs/temp2


Или можно использовать команду cdvirtualenv
$ workon temp
$ cdvirtualenv
$ pwd
/home/beast/py_virtual_envs/temp2

$ cdvirtualenv include/python2.6/
$ pwd
/home/beast/py_virtual_envs/temp/include/python2.6


отключение виртульного окружения
$ deactivate


Удаление виртуального окружения
$ rmvirtualenv temp
$ rmvirtualenv temp2


Опции mkvirtualenv передаются напрямую в virtualenv
$ mkvirtualenv --no-site-packages temp3


есть быстрый переход к текущей директории site-packages
$ cdsitepackages
$ pwd
/home/beast/py_virtual_envs/temp3/lib/python2.6/site-packages
$ ls -l
итого 352
drwxr-xr-x 3 beast beast   4096 Мар 13 21:13 .
drwxr-xr-x 4 beast beast   4096 Мар 13 21:13 ..
-rw-r--r-- 1 beast beast    237 Мар 13 21:13 easy-install.pth
drwxr-xr-x 4 beast beast   4096 Мар 13 21:13 pip-0.6.3-py2.6.egg
-rw-r--r-- 1 beast beast 333447 Мар 13 12:53 setuptools-0.6c11-py2.6.egg
-rw-r--r-- 1 beast beast     30 Мар 13 21:13 setuptools.pth


Есть команда для добавления директорий с пакетами - add2virtualenv <директория>
$ add2virtualenv ~/py_virtual_envs/temp3/temp/
Warning: Converting "/home/beast/py_virtual_envs/temp3/temp/" to "/home/beast/py_virtual_envs/temp3/temp"
$ python
Python 2.6.4 (r264:75706, Jan 25 2010, 09:01:01)
[GCC 4.4.2 20091208 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import additional_package
>>> additional_package.NAME
'Additional package'
^D
$ cat ./temp/additional_package/__init__.py
NAME="Additional package"
$ add2virtualenv ~/py_virtual_envs/temp3/temp/
$ add2virtualenv
Usage: add2virtualenv dir [dir ...]

Existing paths:
/home/beast/py_virtual_envs/temp3/temp


Просмотр установленных пакетов:
$ lssitepackages
easy-install.pth  pip-0.6.3-py2.6.egg  setuptools-0.6c11-py2.6.egg
setuptools.pth  virtualenv_path_extensions.pth

virtualenv_path_extensions.pth:
/home/beast/py_virtual_envs/temp3/temp

В ~/.bashrc можно так же добавить:
export PIP_VIRTUALENV_BASE=$WORKON_HOME
export PIP_RESPECT_VIRTUALENV=true
# Это позволит pip определить текущее виртуальное окружение
# и устанавливать в него без использования параметра -E

Maven Erlang plugin rewrite

Я уже писал про установку и настройку Maven для сборки Erlang проектов. Link. Maven Erlang Plugin упомянутый в той статье не обновлялся больше года.

Недавно я обнаружил новый проект на SourceForge: maven-erlang-plugin который является развитием проекта Maven Erlang Plugin Сейчас проект активно развивается - последний коммит в транк был три часа назад.

четверг, 25 ноября 2010 г.

Включение изображений в html

Памятка:
Небольшие изображения зачастую имеет смысл влючать в html-код страницы с помощью схемы data:URL. Это позволяет не беспокоится о хостинге статичных файлов, например для элементов дизайна Blogger.

Подробности, достоинства и недостатки этого метода можно найти на Wikipedia

Пример:
Embedded Image

Так же можно вкладывать изображения в css-стили:
div.image {
  width:100px;
  height:100px;
  background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...);
}


Скрипт для подготовки изображений к вставке в html:
import base64
import os
import sys

from optparse import OptionParser


if __name__ == '__main__':
    optp = OptionParser()
    optp.add_option('-i', '--input', action='store', dest='input',
            help='File to be encoded')
    optp.add_option('-o', '--output', action='store', dest='output',
            help='File to write output in.')

    (options, args) = optp.parse_args()
    if options.output is not None:
        outfile = open(options.output, 'wb')
    else:
        outfile = sys.stdout

    if options.input is None:
        optp.print_help()
        exit(1)
    infile = open(options.input, 'rb')
    ext = os.path.splitext(options.input)[1][1:]
    outfile.write('')
    infile.close()
    outfile.close()

среда, 24 марта 2010 г.

Импорт стороннего проекта в хранилище артефактов Maven

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

Изготовление одиночного артефакта вполне можно выполнить и вручную, равно как и задеплоить его в хранилище используя mvn deploy:deploy-file.

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

Для примера могу привести проект который создает артефакт - архив tar.gz, используя последнюю версию кода доступную на github.com и деплоит его в хранилище в локальной сети.

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
local.test.import
githubtest
pom
1.0
githubtest


scm:git:git://github.com/<путь к проекту>.git
http://github.com/<адрес>





org.apache.maven.plugins
maven-scm-plugin
1.3


checkout

generate-sources


checkout








org.apache.maven.plugins
maven-assembly-plugin
2.2-beta-5



assembly.xml



${project.build.directory}/checkout




make-assembly
package

single






maven-deploy-plugin


true



deploy-assembly

deploy


deploy-file



releases
http://beast-server/nexus/content/repositories/releases


${project.build.directory}/${project.artifactId}-${project.version}.tar.gz


tar.gz
${project.groupId}
${project.artifactId}
${project.version}








releases
http://beast-server/nexus/content/repositories/releases


snapshots
http://beast-server/nexus/content/repositories/snapshots





assembly.xml содержить простой набор правил - cоздать архив tar.gz в который включить все что находится в текущей директории.

xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0
http://maven.apache.org/xsd/assembly-1.1.0.xsd">


tar.gz

false


./





Итог - Пример проекта который создает артефакт из исходников и деплоит его в хранилище.

понедельник, 22 марта 2010 г.

Дистрибутив Erlang в хранилище Maven

Для начала необходимо получить дистрибутив Erlang для целевой системы в виде артефакта. Erlang уже присутствует в хранилищах пакетов для многих дистрибутивов Linux, но может содержать патчи значительно усложняющие мобильность дистрибутива. Для этого примера я собрал "чистый" экземпляр основанный на исходных кода с офф. сайта http://www.erlang.org/download.html


$ ./configure --prefix=/tmp/erlang
$ make install
$ cd /tmp/erlang/lib/erlang/

Архиватор используемый Maven по умолчанию некорректно распаковывает ссылки из tar.gz. Для распаковки можно воспользоваться Exec Maven Plugin или не включать их в архив. Ссылка будет создана при вызове скрипта Install, так что я ее просто удаляю.

$ rm ./bin/epmd

Потом архивирую всю директорию и деплою получившийся архив в свое хранилище.

$ tar -czf ../erlang-R13B4-linux_x86_64.tar.gz ./
$ mvn deploy:deploy-file -DartifactId=erlang-otp -Dpackaging=tar.gz \
-DgroupId=local.test.erlang.linux-x86-64 -Dversion=R13B4 \
-Dfile=../erlang-R13B4-linux_x86_64.tar.gz \
-Durl=http://beast-server/nexus/content/repositories/releases \
-DrepositoryId=releases


Подключение не составляет проблемы, но развертывание дистрибутива Erlang будет производиться каждый раз при прохождении фазы обработки ресурсов. Что бы дистрибутив разворачивался только один раз, операции относящиеся к развертыванию можно вынести в профиль, который активируется основываясь на отсутствии файлов. Подробности о профилях Maven можно узнать из Introduction to Build Profiles.



4.0.0
local.erlang.test
test-erlang-maven
erlang-otp
1.0-SNAPSHOT
A custom Erlang project
http://www.myorganization.org



local.test.erlang.linux-x86-64
erlang-otp
R13B4
tar.gz
compile






net.sf.maven-erlang
erlang-plugin
true



${project.build.directory}/erlang



true



true



false







true





true














net.sf.maven-erlang
erlang-plugin










maven-surefire-report-plugin





setup_erlang_dist


target/erlang/Install





org.apache.maven.plugins
maven-dependency-plugin


unpack-erlang-dist
process-resources

unpack




local.test.erlang.linux-x86-64
erlang-otp
R13B4
tar.gz
false

${project.build.directory}/erlang








org.codehaus.mojo
exec-maven-plugin
1.1


configure-erlang-dist
process-resources

exec


${project.build.directory}/erlang/Install

-sasl
${project.build.directory}/erlang












Теперь можно проверить работу:

$ mvn package

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

Итог: Дистрибутив Erlang добавлен в хранилище артефактов как артефакт и доступен любому хосту использующему это хранилище. Дистрибутив Erlang может быть подключен к проекту и развернут при необходимости. Кроме распаковки можно так же произвести дополнительную настройку используя, к примеру, Exec Maven Plugin.