Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Фреймворк Telepathy

Глава 20 из книги "Архитектура приложений с открытым исходным кодом", том 1.

Оригинал: Telepathy
Автор: Danielle Madeley
Перевод: Н.Ромоданов

20.2.1. Хэндлы ( Handles)

Хэндлы используются в Telepathy для представления идентификаторов (например, контактов или названия чат-комнат). Они являются беззнаковыми целочисленными значениями, назначаемые менеджером соединений так, что кортеж (соединение, тип хэндла, хэндл) уникальным образом определял конкретный контакт или чат-комнату.

Из-за того, что различные протоколы по-разному обращаются с идентификаторами (например, это касается чувствительность к регистру, ресурсам), хэндлы предоставляют клиентам способ определить, являются ли два идентификатора одним и тем же одинаковыми. Можно запросить хэндлы различных идентификаторов, и если номера хэндлов совпадают, то идентификаторы указывают на один и тот же контакт или чат-комнаты.

Правила нормализации идентификаторов для различных протоколов различны, поэтому было бы ошибкой, если бы клиентские программы при их сравнении сравнивали бы их как строки. Например, escher@tuxedo.cat/bed и escher@tuxedo.cat/litterbox являются двумя экземплярами одного и того же контакта (escher@tuxedo.cat) в протоколе XMPP и, следовательно, они имеют одинаковый хэндл. Клиентские программы могут запрашивать каналы либо по идентификатору, либо по хэндлу, но при сравнении они всегда должны использовать хэндлы.

20.2.2. Обнаружение сервисов Telepathy

Некоторые сервисы, такие как менеджер аккаунтов и диспетчер каналов, которые существуют всегда, имеют общеизвестные имена, которые определены в спецификации Telepathy. Однако, имена менеджеров соединений и клиентских программ строго не определяются и их нужно обнаруживать динамически.

В Telepathy нет сервиса, который бы отвечал за регистрацию запущенных менеджеров соединений и клиентских программ. Вместо этого, те, кому это интересно, слушают шину D-Bus с тем, чтобы узнавать о появлении нового сервиса. Демон шины D-Bus посылает сигнал каждый раз, когда на шине появляется новый именованный сервис D-Bus. Имена клиентов и менеджеров соединений начинаются с известных префиксов, определяемых спецификацией, и в именах новых сервисов будут присутствовать эти префиксы.

Преимущество такого подхода в том, что для него абсолютно не нужно запоминать состояния (stateless). Когда запускается компонент Telepathy, он может спросить у демона шины (у которого есть канонический список, составленный на основе открытых соединений) о том, какие сервисы в настоящий момент работают. Например, если происходит сбой в работе менеджера аккаунтов, то он может посмотреть список запущенных соединений и заново создать ассоциации между соединениями и объектами аккаунтов.

Соединения тоже являются сервисами

Как и сами менеджеры соединений, соединения точно также публикуются как сервисы шины D-Bus. Гипотетически менеджеру соединений разрешается выделять каждое соединение в виде отдельного процесса, но до настоящего времени это в менеджере соединений пока реализовано. На практике это позволяет находить все запущенные соединения, запросив у демона шины D-Bus все соединения, которые начинаются с префикса ofdT.Connection.

Диспетчер каналов также использует этот же метод для поиска клиентских программ Telepathy. Они начинаются с имени ofdT.Client, например, ofdT.Client.Logger.

20.2.3. Снижение трафика шины D-Bus

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

Вызовы отдельных методов были заменены свойствами шины D-Bus. В первоначальной спецификации для каждого свойства объекта использовался отдельный вызов метода: GetInterfaces, \code{GetChannelType}, и т.д. Запрос всех свойств объекта требовал вызовов нескольких методов, у каждого из которых имелись свои накладные расходы. Если пользоваться свойствами шины D-Bus, то все это можно получить за один раз с помощью стандартного метода GetAll.

Более того, целый ряд свойств канала остается неизменным в течение всего времени существования канала. К ним относятся такие свойства, как тип канала, те интерфейсы, через которые подключаются к каналу, а также инициатор открытия канала. Например, для канала передачи файлов среди них также будут указаны размер файла и тип содержимого файла.

Был добавлен новый сигнал, с помощью которого объявляется о создании каналов (как входящих, так и в ответ на исходящие запросы) и в котором находится хэш-таблица неизменяемых свойств. Она может быть передана напрямую в прокси конструктор канала (смотрите раздел 20.4), что позволяет заинтересованным в этой информации клиентским программам не запрашивать ее по-отдельности.

Аватары пользователей передаются по шине в виде массивов байтов. Хотя в Telepathy уже используются токены для ссылок на аватары, что позволяет клиентским программам знать, что им нужен новый аватар, и не загружать ненужные аватары, каждая клиентская программа должна была отдельно запрашивать аватар через метод RequestAvatar, который в своем ответе возвращает аватар. Таким образом, когда менеджер соединений посылал сигнал о том, что у контакта обновился аватар, нужно было для получения аватара делать несколько отдельных запросов и из-за этого аватар передавался по шине сообщений несколько раз.

Эта проблема была решена с помощью добавления нового метода, который не возвращает аватар (он ничего не возвращает). А вместо этого он добавляет аватар в очередь запросов. Получение аватара по сети осуществляется по сигналу AvatarRetrieved, который могут слушать все заинтересованные клиентские программы. Это значит, что данные аватара требуется передавать по шине всего один раз, а затем они становятся доступными для всех клиентских программ, которые в нем заинтересованы. Поскольку запрос клиентской программы находился в очереди, все последующие запросы клиентских программ могли игнорироваться до тех пор, пока не будет отправлен сигнал о готовности аватара AvatarRetrieved.

Всякий раз, когда нужно загрузить большое количество контактов (например, при загрузке реестра контактов), нужно запрашивать большое количество информации: алиасы контактов, аватары, функциональные возможности, их принадлежность к группам, а также, возможно, их местоположение, адреса, номера телефонов. Ранее, в Telepathy для этого требовалось бы по одному вызову отдельного метода на каждую группу информации (большинство вызовов API, например, GetAliases уже принимало списки контактов), что приводило более, чем к полудесятку или даже к большему числу вызовом методов.

Чтобы решить эту проблему, был добавлен интерфейс Contacts. Он позволяет с помощью вызова единственного метода возвращать информацию из нескольких интерфейсов. Чтобы можно было добавлять атрибуты контактов (Contact Attributes), была расширена спецификация Telepathy: для получения информации о контакте был использован метод GetContactAttributes, который возвращал свойства, указываемые в виде полных имен из пространства имен, и который заменил вызовы других методов. Клиентская программа вызывает метод GetContactAttributes со списком контактов и интерфейсов, которые ее интересуют, а обратно она получает карту контактов, в которой для всех атрибутов контактов указываются их значения.

Небольшое количество кода сделает это более понятным. Запрос выглядит следующим образом:

connection[CONNECTION_INTERFACE_CONTACTS].GetContactAttributes(
  [ 1, 2, 3 ], # contact handles
  [ "ofdT.Connection.Interface.Aliasing",
    "ofdT.Connection.Interface.Avatars",
    "ofdT.Connection.Interface.ContactGroups",
    "ofdT.Connection.Interface.Location"
  ],
  False # don't hold a reference to these contacts
)

а ответ может выглядеть следующим образом:

{ 1: { 'ofdT.Connection.Interface.Aliasing/alias': 'Harvey Cat',
       'ofdT.Connection.Interface.Avatars/token': hex string,
       'ofdT.Connection.Interface.Location/location': location,
       'ofdT.Connection.Interface.ContactGroups/groups': [ 'Squid House' ],
       'ofdT.Connection/contact-id': 'harvey@nom.cat'
     },
  2: { 'ofdT.Connection.Interface.Aliasing/alias': 'Escher Cat',
       'ofdT.Connection.Interface.Avatars/token': hex string,
       'ofdT.Connection.Interface.Location/location': location,
       'ofdT.Connection.Interface.ContactGroups/groups': [],
       'ofdT.Connection/contact-id': 'escher@tuxedo.cat'
     },
  3: { 'ofdT.Connection.Interface.Aliasing/alias': 'Cami Cat',
        ⋮    ⋮    ⋮
     }
}


Продолжение статьи: Соединения, каналы и клиентские приложения.