Download - 基于XMPP的Gtalk机器人
基于 XMPP 的 Gtalk 机器人[email protected]
2010.9.4
缘起: 1, 手动更新测试仓库的 SVN 给同事用 2, 在 BlackBerry 上快速访问服务器 给自己用 3, 安排菜谱,讲笑话 给媳妇用 ;)
既然大家都有 Gtalk
那我们就来做个贴心的“小萝莉”机器人吧 ^_&
HOW?
当然是“可爱的 Python” + XMPP 了
Python !!! 你懂的,咱就先说 XMPP 吧 ~~
XMPP :原名 Jabber eXtensible Messaging Presence Protocol 可扩展的消息状态协议 用于Gtalk 就是基于 XMPP 协议,并对协议进行了扩充Google Wave 也是,虽然“出师未捷身先死” Orz
延伸阅读 http://knb.im/67y
XMPP 的架构? 简单来说,就是 Client-Server , Server-Server 一个分散型的通信网络哦 复杂来说, $%^&#*#$
拜托,我们只是想要写一个贴心的 Bot 而已。。。Z.Q 大妈教导过我们, Python 是拿来用的,让我们快乐的朝目标前进就好 ~~~
出发之前的一些基础:
JID : XMPP 的 client 端和 server 端统称为XMPP 实体,用 JID 作为一个全局唯一的标识符。格式为: node@domain/resource
[email protected]/xxxx 就是我了 -_-
出发之前的一些基础:
xmpp 的消息传递系统包括三种内容:
1, 消息( Message ),普通的对话留言
出发之前的一些基础:
xmpp 的消息传递系统包括三种内容:
2, 联机状态( Presence ),用户广播的”在线状态“和可用性
出发之前的一些基础:
xmpp 的消息传递系统包括三种内容:
3, 信息 / 查询请求( Iq ),允许 XMPP 实体发起请求,并接受返回的响应
出发之前的一些基础:
xmpp stanza : xmpp 节。是以 xml 表达的最小的信息项,每个 stanza 都有以下的公共属性:from: 源 xmpp 实体的 JIDto: 目标 xmpp 实体的 JIDid: 这次对话的可选标识符type: stanza 的可选子类型
从之前可以看出, XMPP 是基于 XML 流的。 Fuck~
让我们自己处理的话太繁琐,幸好 python 有众多的功能模块,我们用 xmpppy
import xmpp
jid = xmpp.JID('[email protected]/python')
message = xmpp.Message('say something')
presence = xmpp.Presence('I'm at NGOsoft.com ')
iq = xmpp.Iq()
对象简单明了,开工 ~
问题一,该如何让我的 bot 登录呢?jid = '[email protected]'pwd = 'password'jid_instance = xmpp.JID(jid)cl = xmpp.client(jid_instance.getDomain(), debug[])cl.connect()cl.auth(jid_instance.getNode(), pwd)
问题二,该如何让我的 bot 持续在线?status = xmpp.Presence(status=' 小萝莉 ')cl.sendInitPresence()cl.send(status)while 1: cl.Process(1)
send 函数可以用来发送三种类型的内容
问题三,如何给 bot 注册 handler ?cl.RegisterHandler('message', message_handler)
cl.RegisterHandler('presence', presence_handler)
cl.RegisterHandler('iq', iq_handler)
一旦 bot 收到这三种类型的内容,就交由响应的handler 函数来处理。
问题四,如何让 bot 处理添加好友的请求?所谓的添加好友,其实就是两个实体的互相”订阅“。此信息为 presence 类型:cl.send(xmpp.Presence(to='[email protected]', typ='subscribe'))cl.send(xmpp.Presence(to='[email protected]', typ='subscribed'))
问题五,如何让 bot 处理我们发给她的信息?发给 bot 的信息 ===> 要传递的指令因此要先把这些指令和发送者提取出来def message_handler(self, conn, mess): who = mess.getFrom() content = mess.getBody() 处理 content ,获得 cmd 和 arguments if cmd in commands: cmd_xxx(arguments) #commands 为命令列表 #cmd_xxx 为命令函数
client ==> (message)==>message_handler==>cmd_xxx
对发送信息的处理流程
def cmd_xxx(self, args): # 功能部分 cl.send(xmpp.Message(who, reply))
出现了一个问题:选择执行 cmd_xxx() 函数的时候,由于 xxx 是一个可变化的值,改如何实现? 解决方法:使用 commands[xxx]() 来做函数的选择。 commands={'xxx':func, ...}
可是,如何能动态的生成 commands{ } ?
解决办法:定义一个 register_commands() 的函数,让其在 __init__()中执行,动态的检测 class中存在的cmd_xxx 函数,并给 commands赋值。
def register_commands(self): self.commands={} for name, value in inspect.getmembers(self): if inspect.ismethod(value) and \ getattr(value, '_is_method', Falsa): self.commands[name] = value
并且,我们并不在每个 cmd_ 函数中设置 "_is_command" 属性,而是使用 @修饰符来加工cmd_ 函数,为其设置属性。def botcommands(*args): func = args[0] setattr(func, '_is_command', True) return func
@botcommandsdef cmd_xxx():
def bootcommands(*args): func = args[0] setattr(func, '_is_command', True) return func
使用修饰符函数,来建立我们的 commands system
问题六,怎样知道 bot 的工作情况?
定义一个 log 函数,把每次 handler 的结果记录到文件中去
到目前为止,我们自己的 bot 小框架就算是完成了,粗略回顾一下:client-->connect-->auth-->register_handler verify_request-->presence_handler-->log message-->message_handler-->cmd_xx-->log 添加新的 cmd 功能:@botcommands()def cmd_xx():
Perfect ;)
但杯具的是,我还有一些遗留问题没有处理完:1,log 系统因为编码的原因,暂时只能用英文凑合着2, 这个 bot没有写为 daemon 进程,退出终端后, bot会跟着”死去“。目前的解决办法是跑在 screen里 -_&!
有没有好的建议?
bot 的雏形搞完了,可最初的功能还没实现呢 ~~
目前只写了两个 cmd_ 函数 cmd_help 打印帮助信息cmd_server 基于 xmpp 来控制服务器cmd_work 与 server 类同,都是在 server 端执行命令,只是要用脚本配合罢了但是给媳妇用的 cmd_eat 和 cmd_joy还没想好如何来实现,是从网上抓数据,还是用本地的数据库呢? Orz
问题 &讨论推荐:http://xmpppy.sourceforge.nethttp://code.google.com/p/pygtalkrobot/http://www.ibm.com/developerworks/cn/xml/tutorials/x-realtimeXMPPtut/index.html