суббота, 8 декабря 2012 г.

Отчет о доставке сообщений в jabber (XEP-0184: Message Delivery Receipts)

Сегодня коллега пожаловался на проблему с потерей сообщений в jabber. Часть наших пользователей подключены к корпоративной сети через OpenVPN, работающий через интернет каналы разного качества. Если у клиента нарушилась нормальная работа OpenVPN подключения, то jabber сервер (мы используем ejabberd) порядка двух минут может отправлять сообщения в "пустоту". Мне непонятна логика потери сообщений, т.к. для передачи сообщений используется TCP. В этом случае сервер должен знать, что сообщение было недоставлено, но при этом оно не помещается в offline storage, а просто удаляется.

Когда я впервые столкнулся с этой проблемой, то первым порывом было крутить настройки OpenVPN и ejabberd, но после пары запросов гуглу нашелся более другой способ.

Он заключается в показе уведомлений о доставленных сообщениях в jabber клиенте. Эта фича была реализована как расширение XMPP протокола XEP-0184. На данный момент XEP-0184 заявлен как draft standard, но его поддержка есть во многих клиентах. Печально то, что Psi, который использует большинство пользователей, не поддерживает это расширение протокола.

Дальнейшее гугление привело на страницу проекта Psi+, который развивается как набор патчей для Psi и уже содержит поддержку отчетов о доставке сообщений (XEP-0184: Message Delivery Receipts). Psi+ поддерживает импорт конфигурации из Psi, поэтому история сообщений и ростер из Psi будут доступны и в новом клиенте.

В отличии от большинства своих коллег, я использую pidgin в качестве jabber клиента (помимо jabber мне приходится использовать icq и yahoo) вдобавок мне нравится pidgin за хранение истории сообщений в виде простого текста (луч поноса создателям skype и миранды), которую я к тому же синхронизирую на всех компьютерах, где мне приходится работать.

Пока искал замену для Psi, нагуглил в багтрекере pidgin тикет, в котором Ferdinand Stehle (noonien) дал ссылку на плагин pidgin-xmpp-receipts, реализующий поддержку XEP-0184 в pidgin. Пары минут хватило, чтобы скомпилировать плагин под Debian Squeeze (для компиляции достаточно установить пакет pidgin-dev) и активировать его в месенджере.

Для тестирования поддержки уведомлений я установил последний доступный релиз Psi+ в Wine (свежую версию Wine для Debian Squeeze/Wheezy можно найти в моем репозитарии) и завел на сервере отдельного пользователя. При отправке сообщения из pidgin в psi+ в окне чата pidgin появляется отметка о доставке , но если отправлять сообщение клиенту без поддержки xep-0184, то отметка отсутствует. Все замечательно, но есть нюанс - если симулировать "поломку сети" у psi+ и отправить несколько сообщений разом, то после восстановления работоспособности сети у psi+ в pidgin появляются отметки, но не напротив сообщений, а скопом после последней строчки.

Далее перешел к отправке сообщений из psi+ в pidgin и тут меня ждало разочарование - из истории сообщений никак не понятно где сообщение доставлено, а где нет. В качестве последней меры отравил сообщение из psi+ в другой psi+ и тут появилась разница - если сообщение доставлено, то цвет стрелочки в чате psi+ меняется с розового на зеленый. Выходит при отправке сообщений из psi+ в pidgin, первый считает, что все сообщения были потеряны, а в обратную сторону все работает.

Похоже нашел баг, но у кого из них пока неясно. Для просветления головы пошел заварил себе кофейку, открыл документ в котором описан XEP-0184, активировал консоли отладки в pidgin и psi+ и стал смотреть разницу при посылке сообщения из psi+ в pidgin и в обратную сторону.

После пары тестовых сообщений стала заметна разница в отчете о доставке, которую генерят psi+ и pidgin. Psi+ отвечает

<message from='user1@example.com' to='user2@example.com' id='xxxx'>
<received xmlns='urn:xmpp:receipts' />
</message>

А pidgin отвечает

<message from='user2@example.com' to='user1@example.com'>
<received xmlns='urn:xmpp:receipts' id='xxxx' />
</message>

Получается, что они по указывают верный id, на который шлется подтверждение, но указывают его в разных местах. Снова открываю описание XEP-0184 и вижу, что правильное подтверждение генерит именно pidgin. Странно, в psi+ поддержка этого расширения появилась сравнительно давно и если это баг, то его уже должны были исправить. Далее размышления приводят меня к тому, что раз поддержка XEP-0184 появилась в psi+ раньше, чем в pidgin, то возможно они просто реализуют различные ревизии стандарта (ведь он до сих пор находится в стадии разработки).

Иду смотреть более ранние ревизии описания расширения и вижу что я был прав. Psi+ отвечает согласно ревизии v1.0, а ответ pidgin соответсвует последней ревизии v1.2. Причем pidgin переваривает более ранний вариант подтверждения.

Лезу в код плагина pidgin-xmpp-reciepts смотреть можно ли поменять его формат подтверждения на тот, который будет понятен для psi+. Как оказалось сделать это несложно, достаточно в одной строке поменять место, где указывается id.

diff -urNp pidgin-xmpp-reciepts-0.3.orig/xmpp-receipts.c pidgin-xmpp-reciepts-0.3/xmpp-receipts.c
--- pidgin-xmpp-reciepts-0.3.orig/xmpp-receipts.c 2012-12-08 00:31:41.074967000 +0300
+++ pidgin-xmpp-reciepts-0.3/xmpp-receipts.c 2012-12-08 00:32:18.142966997 +0300
@@ -128,7 +128,7 @@ xmlnode_received_cb(PurpleConnection *gc
     if(strcmp(strNS, "urn:xmpp:receipts") == 0)
     {
      GString* sendpacket  = g_string_new("");
-     g_string_printf(sendpacket, "<message from='%s' to='%s'>\n<received xmlns='urn:xmpp:receipts' id='%s'/></message>",
+     g_string_printf(sendpacket, "<message from='%s' to='%s' id='%s'>\n<received xmlns='urn:xmpp:receipts' /></message>",
      strTo, strFrom, strId);
 
      #ifdef DEBUG

После компиляции плагина с этим патчем уведомления стали работать в оба направления. Последним штрихом стала "гибридизация" версий стандарта - я немного модифицировал свой патч, чтобы клиенты, которые могут полагаться на новую версию могли ее правильно воспринимать.

diff -urNp pidgin-xmpp-reciepts-0.3.orig/xmpp-receipts.c pidgin-xmpp-reciepts-0.3/xmpp-receipts.c
--- pidgin-xmpp-reciepts-0.3.orig/xmpp-receipts.c 2012-12-08 00:31:41.074967000 +0300
+++ pidgin-xmpp-reciepts-0.3/xmpp-receipts.c 2012-12-08 00:39:00.494967000 +0300
@@ -128,8 +128,8 @@ xmlnode_received_cb(PurpleConnection *gc
     if(strcmp(strNS, "urn:xmpp:receipts") == 0)
     {
      GString* sendpacket  = g_string_new("");
-     g_string_printf(sendpacket, "<message from='%s' to='%s'>\n<received xmlns='urn:xmpp:receipts' id='%s'/></message>",
-     strTo, strFrom, strId);
+     g_string_printf(sendpacket, "<message from='%s' to='%s' id='%s'>\n<received xmlns='urn:xmpp:receipts' id='%s' /></message>",
+     strTo, strFrom, strId, strId);
 
      #ifdef DEBUG
      printf("\n%s\n", strNS);

С этим патчем ничего не отвалилось, хотя патч является костылем. Чтобы окончательно оформить решение проблемы с поддержкой XEP-0184 в pidgin, я собрал пакет для Debian. Его можно установить из моего репозитария.

wget -q -O- http://www.tataranovich.com/tataranovich.asc | apt-key add -
echo 'deb http://www.tataranovich.com/debian squeeze main' >> /etc/apt/sources.list
apt-get update
apt-get install pidgin-xmpp-reciepts

2 комментария:

  1. Отправил бы патч разработчикам плагина

    ОтветитьУдалить
    Ответы
    1. Апстрим ушел далеко вперед - сейчас актуальна версия 0.6, а мой патч для версии 0.3. Я уже и не помню почему я его не отправил, или отправил... давно это было в общем )

      Удалить