Уже достаточно давно существует всем известная связка Nginx + Lua, в том числе здесь был ряд статей. Но время не стоит на месте. Примерно год назад появилась первая версия модуля, интегрирующего Ruby в Nginx.
MRuby
Для интеграции был выбран не полноценный Ruby, а его подмножество, которое предназначено для встраивания в другие приложения, устройства и тд. Имеет некоторые ограничения, но в остальном полноценный Ruby. Проект называется MRuby. На текущий момент имеет уже версию 1.0.0, т.е. считается стабильным.
MRuby не позволяет подключать другие файлы во время выполнения, поэтому вся программа должна быть в одном файле. При этом есть возможность преобразовать программу в байткод и выполнять уже его, что положительно сказывается на производительности.
Т.к. нет возможности подгружать другие файлы, то и существующие gem-ы не подходят для него. Для расширения функционала используется свой формат, который представляет из себя как C код, так и Ruby местами. Данные модули собираются вместе с самой библиотекой во время компиляции и являются ее неотъемлемой частью. Имеются биндинги к различным базам данных, для работы с файлами, сетью и так далее. Полный список доступен на сайте.
Также там имеется модуль, позволяющий интегрировать данный движок в Nginx, который особенно заинтересовал.
ngx_mruby
Итак, знакомьтесь: ngx_mruby. Модуль для подключения ruby скриптов к nginx. Имеет схожий функционал с Lua версией. Позволяет выполнять операции на различных этапах обработки запроса.
Модуль собирается довольно просто, на сайте есть подробная инструкция. Кто не хочет заморачиваться со сборкой, могут скачать готовый пакет:
http://ift.tt/1oepIgK
MRuby в данной сборке содержит следующие дополнительные модули:
Как видите, есть почти все необходимое для работы. Единственное, что не обнаружил в API данного модуля, это возможности делать запрос наружу. Скорее всего, его нужно будет реализовать как расширение и сделать обвязку вокруг nginx API.
Автор показывает красивый график с тестами, но конфигурации окружения так и не нашел. Поэтому просто приложу его для красоты:
Попробуем использовать
Итак, сервер у нас уже установлен. Все функционирует, статика отдается. Добавим немного к этому динамики.
В качестве примера я выбрал задачу по парсингу Markdown разметки и отдачи ее в HTML без дополнительного серверного приложения. А также нумерации строк в исходниках на Ruby.
Для этого сделан клон репозитория sinatra и настроен nginx для решения поставленной задачи.
Markdown
Для обработки разметки воспользуемся подключенным в сборку модулем mruby-discount. Он предоставляет простой класс для работы с разметкой. В основе лежит одноименная библиотека на C, потому вопрос производительности, думаю, особо стоять не будет.
Для начала напишем программу, которая будет считывать запрошенный файл с диска, обрабатывать его и отдавать пользователю.
r = Nginx::Request.new
m = Discount.new("/st/style.css", "README")
filename = r.filename
filename = File.join(filename, 'README.md') if filename.end_with?('/')
markdown = File.exists?(filename) ? File.read(filename) : ''
Nginx.rputs m.header
Nginx.rputs m.md2html(markdown)
Nginx.rputs m.footer
Первой строкой получаем экземпляр объекта запроса, содержащий всю необходимую информацию, включая запрошенный файл, заголовки, URL, URI и т.д.
Следующей строкой создаем экземпляр класса Discount, указывая файл стиля и заголовк страницы.
Данный код не делает обработку 404 ошибки, поэтому даже если файла нету, всегда будет 200 код возврата.
Подключаем теперь все это
location ~ \.md$ {
add_header Content-Type text/html;
mruby_content_handler "/opt/app/parse_md.rb" cache;
}
Результат:
http://ift.tt/SwCbjN
http://ift.tt/1oepJRJ
Файлы Ruby
Первоначально планировал сделать не просто нумерацию, а так же раскраску кода, используя когда-то написанный код http://ift.tt/SwCdrH. Однако после всех произведенных адаптаций в его работе возникли проблемы. Код, вроде, работал, но на определенном этапе падал с Segmentation fault. Первоначальное подозрение было на нехватку памяти выделяемой, но даже после уменьшения ее потребление проблема не пропала. После удаления кода, связанного с раскраской, все заработало, но не так красиво, как хотелось.
module CGI
TABLE_FOR_ESCAPE_HTML__ = {"&"=>"&", '"'=>""", "<"=>"<", ">"=>">"}
def self.escapeHTML(string)
string.gsub(/[&\"<>]/) do |ch|
TABLE_FOR_ESCAPE_HTML__[ch]
end
end
end
class String
def ord
self.bytes[0]
end
end
class Chalk
COMMENT_START_CHARS = {
ruby: /#./,
cpp: /\/\*|\/\//,
c: /\/\//
}
COMMENT_END_CHARS = {
cpp: /\*\/|.\n/,
ruby: /.\n/,
c: /.\n/,
}
STRING_SEP = %w(' ")
SEPARATORS = " @(){}[],.:;\"\'`<>=+-*/\t\n\\?|
This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий