Прицел на eJabberd
Поговорим о выборе системы сообщений для пользователей некоего проекта или компании. Притом исходим из следующих требований:
В настоящий момент, все перечисленные условия (и не только) могут быть реализованы с помощью XMPP-протокола. HTTP доступ предоставляют все современные jabber-сервера с помощью технологии HTTP binding (примечание: нужно пробросить директорию /http-bind/ портала на порт jabber-сервера). Среди некоторого многообразия jabber-серверов есть и один весьма неплохой - ejabberd. Почему именно он, история долгая, но на этом варианте я остановился два года назад и с тех пор не было причин изменить свое мнение (тестировал его, мелкие баги были, но сейчас они уже поправлены). В силу того, что в дебиане сейчас присутствует работоспособная версия ejabberd, пришло время запускать его в продакшен (мне хватает забот со своим деб-репозиторием и мантейнить лишний пакет без необходимости не стану).
Как всегда, быстрее всего ознакомиться с возможностями выбранного продукта можно, посмотрев существующие расширения к нему: Contributions
И, конечно, смотрим Official ejabberd documentation А также страницу вики Делаем Jabber-сервер
Что касается логирования, меня больше интересует отдельная система, нежели встроенный модуль. Например, это Bandersnatch:
Guide to Install Bandersnatch
Install Bandersnatch to log Messages
или фронт-энд Jorge (мне плевать, что оно на пхп, поскольку рассматриваю перечисленные варианты как образцы для написания своего решения).
Впрочем, есть и встраиваемые модули для логирования:
mod_logdb - Log User Messages to DB
Сохранение логов muc-конференций в виде html
Теперь поговорим об AJAX-интерфейсе. как один из вариантов интерфейса (есть в дебиане): A web based Jabber/XMPP client Умеет многое, смотрим здесь в подробностях: Features
Немного об установке интерфейса с джаббер-сервером:
EJabberd + JWChat + Apache2
А тут рассказано, как можно потыкать пальцем протокол для разной мелкой автоматизации: Джаббер чат на веб-странице
И немного о публичных сервисах, для ознакомления:
http://www.olark.com/portal/?rid=hab.la
http://www.meebo.com/
Create a Google Talk chatback badge
Upd.
За пример работающего конфига и некоторые подсказки спасибо Anton Kovalenko.
Пользователь admin существует сразу после установки, надо лишь назначить ему нужный пароль. Например, вот так:
В веб-интерфейсе выбираем наш виртуальный хост, и для него можно создавать shared rosters ("группы общих контактов"), управлять пользователями и прочее. Впрочем, вот именно "управление" вызывает разумные сомнения, так что оставим только возможность просмотра настроек - пусть значения из конфиг-файла перезаписывают все изменения, вносимые через веб-интерфейс:
Что касается авторизации, то все достаточно просто, см. 4 Authentication
Примеры скриптов вполне наглядны, вот один из них: Postgresql external auth script (Perl)
Вот такой тиклевый скрипт умеет авторизовывать пользователей:
ejabberd_auth
Для основного домена "домен" я желаю встроенную авторизацию, а для всех прочих - внешним скриптом. В конфиге это будет записано так:
Раз у нас есть авторизация, самое время поиграться с ростерами. Пробуем:
Конструкция @all@ для внешней авторизации работать не будет, т.к. ejabberd не может предоставить список всех зарегистрированных пользователей. И тем не менее, использование @all@ не приводит к каким-либо ошибкам, @all@ просто игнорируется.
Рассматриваемый подход имеет как свои плюсы, так и минусы. Хорошо то, что информация о пользователях может забираться из внешнего источника, а плохо то, что нужен постоянный доступ к этому источнику, фиксированный его формат, высокая скорость отклика и минимальные накладные расходы даже при множестве обращений. Еще вспомним про невозможность поиска по стандартным атрибутам - конечно, свой коннектор позволит искать в ldap и других внешних хранилищах, но создаст заведомо узкое место в системе. Так что теперь посмотрим, как может быть выполнена репликация нашей БД с пользователями и пользовательской информации в ejabberd. Что ж, я исхожу из принципа "мухи отдельно, котлеты отдельно", а вариант с доступом к внешнему хранилищу уже подробно рассмотрен выше. Вот что касается вариантов онлайн-синхронизации пользовательской информации:
Есть и сторонние сервисы/утилиты для переноса контактов, в том числе между разными серверами. Например, Jabber roster utility или ее клон Утилита для Jabber Ростера на PHP
Продолжаем установкой пакета jwchat (копируем или симлинкаем к себе файлы *.ru, создаем конфиг, правим симлинк на XMPP javascript-библиотеку). Выясняется, что при включенном SSL для веб-интерфейса не работает http-bind, так что пока отключаем SSL (возвращаем к дефолтовым настройкам секцию конфига). Плюс в разделе модулей вписываем в конфиг модуль {mod_http_bind, []} без которого http binding не работает (понятно, почему не работает, но непонятно, с чего бы это в дефолтовом конфиге его нет, раз уж предлагается http binding). Теперь
Довольно интересной для пользователей возможностью является icq-гейт. Что ж, попробуем:
Гейт прикручивается к указанному виртуальному домену, хотя при желании его можно использовать для любого домена, если знать адрес гейта или адрес его домена. В общем, работает. Настроить клиента Миранда можно вот так: Подключение ICQ в Miranda - только учтем, что в новых версиях это меню располагается слева внизу главного окна Миранды (впрочем, там вариантов немного, так что я быстро нашел).
Теперь на AJAX-программирование подробнее посмотрим. jwchat работает "из коробки" (см. выше, как его ставить). Отображаемые поля vCard меня не устроили, например, нет номера телефона, но это решается добавлением нужной строчки в соответствующий html-файл (яваскрипт видит все значения в карточке, а заполняет, что логично, только существующие на странице поля, так что настройка отображения vCard заключается в добавлении строчек в html-таблицу).
Расширение Strophe: Programming with XMPP and JavaScript
jQuery and Strophe: Made for Each Other
jquery-bosh
XMPP LIBRARY
Professional XMPP Programming with JavaScript and jQuery Jan 2010 eBook-BBL
Upd.
А вот и способ автоматизировать отправку сообщений из консоли:
- пользовательский интерфейс системы сообщений должен встраиваться в интернет/интранет портал, работающий на строго фиксированном ip с доступом исключительно по https. Почему такое ограничение, обсуждать особенно ни к чему, поскольку это бизнес-требование, добавлю лишь, что для некоторых пользователей есть и техническое ограничение - например, скайлинк на тарифных планах для корпоративщиков (по крайней мере, на некоторых) предоставляет лишь доступ по https.
- собственная авторизация (любым способом, без ограничений), так что зарегистрированные в основной БД пользователи имеют доступ к системе сообщений (притом из соображений безопасности в основной БД хранится лишь хэш пароля)
- всеобъемлющий API для интеграции с системой сообщений - в частности, для подключения AJAX-интерфейса пользователя (никаких web sockets, см. первое требование) и логирования всех сообщений (логирование может быть реализовано от варианта с ведением простого лог-файла до записи в БД с онлайн-индексированием, рассылкой уведомлений по email и созданием отчетов и проч.)
В настоящий момент, все перечисленные условия (и не только) могут быть реализованы с помощью XMPP-протокола. HTTP доступ предоставляют все современные jabber-сервера с помощью технологии HTTP binding (примечание: нужно пробросить директорию /http-bind/ портала на порт jabber-сервера). Среди некоторого многообразия jabber-серверов есть и один весьма неплохой - ejabberd. Почему именно он, история долгая, но на этом варианте я остановился два года назад и с тех пор не было причин изменить свое мнение (тестировал его, мелкие баги были, но сейчас они уже поправлены). В силу того, что в дебиане сейчас присутствует работоспособная версия ejabberd, пришло время запускать его в продакшен (мне хватает забот со своим деб-репозиторием и мантейнить лишний пакет без необходимости не стану).
Как всегда, быстрее всего ознакомиться с возможностями выбранного продукта можно, посмотрев существующие расширения к нему: Contributions
И, конечно, смотрим Official ejabberd documentation А также страницу вики Делаем Jabber-сервер
Что касается логирования, меня больше интересует отдельная система, нежели встроенный модуль. Например, это Bandersnatch:
Guide to Install Bandersnatch
Install Bandersnatch to log Messages
или фронт-энд Jorge (мне плевать, что оно на пхп, поскольку рассматриваю перечисленные варианты как образцы для написания своего решения).
Впрочем, есть и встраиваемые модули для логирования:
mod_logdb - Log User Messages to DB
Сохранение логов muc-конференций в виде html
Теперь поговорим об AJAX-интерфейсе. как один из вариантов интерфейса (есть в дебиане): A web based Jabber/XMPP client Умеет многое, смотрим здесь в подробностях: Features
Немного об установке интерфейса с джаббер-сервером:
EJabberd + JWChat + Apache2
А тут рассказано, как можно потыкать пальцем протокол для разной мелкой автоматизации: Джаббер чат на веб-странице
И немного о публичных сервисах, для ознакомления:
http://www.olark.com/portal/?rid=hab.la
http://www.meebo.com/
Create a Google Talk chatback badge
Upd.
За пример работающего конфига и некоторые подсказки спасибо Anton Kovalenko.
Пользователь admin существует сразу после установки, надо лишь назначить ему нужный пароль. Например, вот так:
sudo ejabberdctl change_password admin хост парольТеперь от имени пользователя admin с указанным паролем заходим в веб-интерфейс http://хост:5280/admin/ Хм, почему же здесь доступ по открытому HTTP? Непорядок, правим в конфиге
-web_admin +web_admin, tls, {certfile, "/etc/ejabberd/ejabberd.pem"}Далее создаем свой сертификат - установленный по умолчанию мне не интересен, лучше свой выписать, или получить здесь ICA XMPP Foundation (бесплатно). После перезапуска еджаббера входим уже по защищенному соединению https://хост:5280/admin/
В веб-интерфейсе выбираем наш виртуальный хост, и для него можно создавать shared rosters ("группы общих контактов"), управлять пользователями и прочее. Впрочем, вот именно "управление" вызывает разумные сомнения, так что оставим только возможность просмотра настроек - пусть значения из конфиг-файла перезаписывают все изменения, вносимые через веб-интерфейс:
override_global. override_local. override_acls.
Что касается авторизации, то все достаточно просто, см. 4 Authentication
Примеры скриптов вполне наглядны, вот один из них: Postgresql external auth script (Perl)
Вот такой тиклевый скрипт умеет авторизовывать пользователей:
ejabberd_auth
#!/usr/bin/tclsh8.5 # https://git.process-one.net/ejabberd/mainline/blobs/raw/2.1.x/doc/dev.html#htoc8 fconfigure stdin -translation binary -buffering none fconfigure stdout -translation binary -buffering none # the result code (coded as a short), should be 1 for success/valid, or 0 for failure/invalid proc auth_ok {} { puts -nonewline [binary format Su2 {2 1}] } proc auth_no {} { puts -nonewline [binary format Su2 {2 0}] } # check user or user/password proc auth {server user {password {}}} { auth_ok } while {1} { if {[binary scan [read stdin 2] Su len] == 1} { lassign [split [read stdin $len] :] type user server password exec logger "ejabberd external auth script: $type $user $server $password" switch $type { auth { # check if a username/password pair is correct auth $server $user $password } isuser { # check if it’s a valid user auth $server $user } default { auth_no } } } if {[eof stdin]} { break } }На самом деле скрипт у меня обращается к БД для проверки авторизации, здесь же я упростил для наглядности.
Для основного домена "домен" я желаю встроенную авторизацию, а для всех прочих - внешним скриптом. В конфиге это будет записано так:
%%% ============== %%% AUTHENTICATION %% %% Authentication using external script %% Make sure the script is executable by ejabberd. %% {auth_method, external}. {host_config, "домен", [{auth_method, internal}]}. {extauth_program, "/usr/local/bin/ejabberd_auth"}.Проверил, указанная конфигурация успешно работает. С той оговоркой, что скрипты в цикле поедают ресурсы и при перезапуске ejabberd продолжают работать (при каждом старте ejabberd запускается еще 4 скрипта). Проблемы решаемые, но ничего хорошего в этом нет.
Раз у нас есть авторизация, самое время поиграться с ростерами. Пробуем:
sudo ejabberdctl srg_create groupadm хост1 "Администраторы" "Группа администраторов" groupadm\\ngroupall sudo ejabberdctl srg_create groupall хост1 "МР ЮГ" "Все пользователи МР ЮГ" "groupadm" sudo ejabberdctl srg_user_add admin хост groupadm хост1 sudo ejabberdctl srg_user_add veter хост1 groupadm хост1 sudo ejabberdctl srg_user_add @all@ хост groupall хост1 sudo ejabberdctl srg_user_del test хост groupall хост1 sudo ejabberdctl srg_delete groupadm хост1Здесь в команде srg_create последний аргумент содержит список всех групп, которые будут видеть участники создаваемой группы; обычно туда включают и саму создаваемую группу, чтобы ее участники видели друг друга. В документации этот момент разъясняется как-то странно, сразу и не понять, что саму группу туда тоже нужно включить:
Displayed groups
A list of groups that will be in the rosters of this group’s members.
Конструкция @all@ для внешней авторизации работать не будет, т.к. ejabberd не может предоставить список всех зарегистрированных пользователей. И тем не менее, использование @all@ не приводит к каким-либо ошибкам, @all@ просто игнорируется.
Рассматриваемый подход имеет как свои плюсы, так и минусы. Хорошо то, что информация о пользователях может забираться из внешнего источника, а плохо то, что нужен постоянный доступ к этому источнику, фиксированный его формат, высокая скорость отклика и минимальные накладные расходы даже при множестве обращений. Еще вспомним про невозможность поиска по стандартным атрибутам - конечно, свой коннектор позволит искать в ldap и других внешних хранилищах, но создаст заведомо узкое место в системе. Так что теперь посмотрим, как может быть выполнена репликация нашей БД с пользователями и пользовательской информации в ejabberd. Что ж, я исхожу из принципа "мухи отдельно, котлеты отдельно", а вариант с доступом к внешнему хранилищу уже подробно рассмотрен выше. Вот что касается вариантов онлайн-синхронизации пользовательской информации:
ejabberdctl that may be useful for you, like push_roster_all or srg_user_add
This way you can implement the logic of adding/deleting contacts in your
prefered language, and then call the script ejabberdctl to perform the changes.
If you later notice that calling a shell script for each change is too
slow for you,
you can install also ejabberd_xmlrpc, which provides an XML-RPC server where
you can send your command queries (instead of the shell script ejabberdctl).
Есть и сторонние сервисы/утилиты для переноса контактов, в том числе между разными серверами. Например, Jabber roster utility или ее клон Утилита для Jabber Ростера на PHP
Продолжаем установкой пакета jwchat (копируем или симлинкаем к себе файлы *.ru, создаем конфиг, правим симлинк на XMPP javascript-библиотеку). Выясняется, что при включенном SSL для веб-интерфейса не работает http-bind, так что пока отключаем SSL (возвращаем к дефолтовым настройкам секцию конфига). Плюс в разделе модулей вписываем в конфиг модуль {mod_http_bind, []} без которого http binding не работает (понятно, почему не работает, но непонятно, с чего бы это в дефолтовом конфиге его нет, раз уж предлагается http binding). Теперь
links http://localhost:5280/http-bind/работает и показывает страничку с информацией. Идем в jwchart -все верно, получаем желанный AJAX-интерфейс. Для корпоративного портала стоит предусмотреть подстановку имени и пароля пользователя, дабы не напрягать последнего лишними деталями.
Довольно интересной для пользователей возможностью является icq-гейт. Что ж, попробуем:
sudo aptitude install -R pyicq sudo mcedit /etc/pyicqt.conf.xml sudo mkdir /var/lib/pyicqt/JabberID/ sudo chown pyicqt:pyicqt /var/lib/pyicqt/JabberID/ sudo /etc/init.d/pyicqt restartЗдесь JabberID это icq.что-то-там согласно определенному в конфиге.
Гейт прикручивается к указанному виртуальному домену, хотя при желании его можно использовать для любого домена, если знать адрес гейта или адрес его домена. В общем, работает. Настроить клиента Миранда можно вот так: Подключение ICQ в Miranda - только учтем, что в новых версиях это меню располагается слева внизу главного окна Миранды (впрочем, там вариантов немного, так что я быстро нашел).
Теперь на AJAX-программирование подробнее посмотрим. jwchat работает "из коробки" (см. выше, как его ставить). Отображаемые поля vCard меня не устроили, например, нет номера телефона, но это решается добавлением нужной строчки в соответствующий html-файл (яваскрипт видит все значения в карточке, а заполняет, что логично, только существующие на странице поля, так что настройка отображения vCard заключается в добавлении строчек в html-таблицу).
Расширение Strophe: Programming with XMPP and JavaScript
jQuery and Strophe: Made for Each Other
jquery-bosh
XMPP LIBRARY
Professional XMPP Programming with JavaScript and jQuery Jan 2010 eBook-BBL
Upd.
А вот и способ автоматизировать отправку сообщений из консоли:
sudo aptitude install sendxmpp echo "admin@myhost password" > ~/.sendxmpprc chmod a-rw,u+rw ~/.sendxmpprc # сообщение пользователю echo "автоматическая рассылка"|sendxmpp veter@nnov # рассылка всем онлайн-пользователям echo "автоматическая рассылка"|sendxmpp nnov/announce/online # сообщение в чат от несуществующего пользователя robot echo -e "сообщение\n"|sendxmpp -r robot --chatroom talks@conference.nnov # просто строка с форматированием echo "строка"|sendxmpp conference.nnovОтправка сообщения занимает порядка 1 с времени, этого во многих случаях вполне достаточно; заметим, что отправка через ejabberdctl ничуть не быстрее.
Comments