Jabber 机器人 - 如何获取联系人的在线状态?

4 投票
3 回答
4161 浏览
提问于 2025-04-16 05:12

我想用Python设置一个Jabber机器人,这个机器人可以根据几个联系人的在线或离线状态发送消息。

我查了一下pyxmpp和xmpppy这两个库,但没找到简单的方法来检查某个联系人的状态。

有没有什么建议可以帮我实现这个功能?

理想情况下,我希望能有类似于bot.status_of("contact1@gmail.com")这样的代码,返回"online"

3 个回答

0

你需要做的事情是:

  1. 先连接上。
  2. 声明一个状态处理器。这个处理器会保存每个联系人的状态信息(下面会详细说明)。
  3. 把你的初始状态发送到服务器,这样就能收到你所有在线联系人的状态信息,这也会触发处理器的工作。
  4. 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

当然,如果你想要更详细的信息,你可以不仅保存联系人的可用资源列表,还可以保存每个资源的状态、状态消息、优先级等等。

0

你想要的功能可以通过一个叫做 <presence type="probe"/> 的东西来实现。这是由客户端代替完成的,客户端自己不应该去做(这是根据XMPP即时消息的标准规定的)。因为这是一个机器人,你可以实现这个存在探测功能,来获取某个实体的当前状态。记得要把探测请求发送到没有资源的裸JID,因为服务器会代表客户端来回应这些探测请求。这意味着你的工作流程应该是这样的:

<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的相关部分。

2

我觉得你想要的方式可能行不通,因为联系人在线状态的信息是异步接收的,也就是说,机器人并不是实时收到这些信息。

你需要写一个处理在线状态的函数,并把它注册到连接上。每当收到某个联系人的在线状态时,这个函数就会被调用。调用时会传入一个参数,这个参数会告诉你这个联系人是否在线。根据这个信息,你就可以决定是否给这个联系人发送消息。

使用 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)

附注:我没有测试过这段代码,但应该和这个非常相似。

撰写回答