Бот Jabber - как получить доступность контактов?
Мне нужно настроить jabber-бот, использующий python, который будет отправлять сообщения, основываясь на доступности онлайн / офлайн нескольких контактов.
Я изучал pyxmpp и xmpppy, но не смог найти никакого способа (по крайней мере, ничего простого), чтобы проверить состояние данного контакта.
Любые указатели о том, как этого добиться?
В идеале я хотел бы что-то вроде, например, bot.status_of("contact1@gmail.com")
возврате "online"
3 ответа
Я не думаю, что это возможно так, как вы этого хотите, потому что присутствие контактов (которые содержат информацию об их доступности) принимается ботом асинхронно.
Вам нужно будет написать функцию обработчика присутствия и зарегистрировать ее в соединении. Эта функция вызывается всякий раз, когда от контакта поступает информация о присутствии. Параметр звонка скажет вам, если контакт в сети или нет. В зависимости от этого вы можете отправить сообщение контакту.
С помощью xmpppy
вы делаете это примерно так:
def connect(jid, password, res, server, proxy, use_srv):
conn = xmpp.Client(jid.getDomain())
if not conn.connect(server=server, proxy=proxy, use_srv=use_srv):
log( 'unable to connect to server.')
return None
if not conn.auth(jid.getNode(), password, res):
log( 'unable to authorize with server.')
return None
conn.RegisterHandler( 'presence', callback_presence)
return conn
conn = connect(...)
def callback_presence(sess, pres):
if pres.getStatus() == "online":
msg = xmpp.Message(pres.getFrom(), "Hi!")
conn.send(msg)
PS: я не проверял код, но это должно быть что-то очень похожее на это.
То, что вы хотите сделать через <presence type="probe"/>
, Это делается от имени клиента и НЕ ДОЛЖНО быть им выполнено (согласно RFC для XMPP IM). Поскольку это бот, вы можете реализовать датчик присутствия и получить текущее присутствие данного объекта. Не забудьте отправить зонд на пустой JID (sans-ресурс), потому что сервер отвечает от имени клиентов за зонды присутствия. Это означает, что ваш рабочий процесс будет выглядеть так:
<presence/> // I'm online! BOT
<presence from="juliet@capulet.org/balcony"/> RESPONSE
<presence from="romeo@montague.net/hallway"/> // and so on... RESPONSE
<presence type="probe" to="benvolio@montague.net"/> BOT
<presence from="benvoio@montague.net/hallway"> RESPONSE
<status>Huzzah!</status>
<priority>3</priority>
</presence>
Посмотрите на эту часть RFC для получения более подробной информации о том, как должен вести себя ваш поток вызовов.
Что вам нужно сделать, это:
- Подключение.
- Объявите обработчик присутствия. Этот обработчик поддерживает кэш-память о присутствии каждого контакта (подробности см. Ниже)
- Отправьте начальное присутствие на сервер, что вызовет получение статусов присутствия от всех ваших онлайн-контактов, что, в свою очередь, вызовет обработчик.
- Метод status_of() считывает кеш и немедленно определяет состояние присутствия контакта.
Теперь это зависит от того, какая информация о присутствии вам нужна. Для простоты давайте представим, что вам просто нужно значение "онлайн"/"оффлайн". Кеш будет представлять собой словарь, ключами которого являются чистые (без ресурсов) JID, а значения - это набор связанных ресурсов для этого JID. Например:
{'foo@bar.com': set(['work', 'notebook']), 'bob@example.net': set(['gtalk'])}
Теперь, когда вы получаете "доступное" присутствие от определенного JID/ ресурса:
if jid not in cache:
cache[jid] = set()
cache[jid].add(resource)
Взаимно, когда вы получаете "недоступное" присутствие:
if jid in cache: # bad people send "unavailable" just to make your app crash
cache[jid].discard(resource)
if 0 == len(cache[jid]):
del cache[jid]
И сейчас:
def is_online(jid):
return jid in cache
Конечно, если вы хотите получить более подробную информацию, вы можете поддерживать не только список доступных ресурсов для контакта, но также статус, сообщение о состоянии, приоритет и т. Д. Каждого ресурса.