基于XMPP的Gtalk机器人

Preview:

DESCRIPTION

 

Citation preview

基于 XMPP 的 Gtalk 机器人zhoo.xuan@gmail.com

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

zhoo.xuan@ngosoft.com/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('bot@gmail.com/python')

message = xmpp.Message('say something')

presence = xmpp.Presence('I'm at NGOsoft.com ')

iq = xmpp.Iq()

对象简单明了,开工 ~

问题一,该如何让我的 bot 登录呢?jid = 'bot@gmail.com'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='xx@xx.xx', typ='subscribe'))cl.send(xmpp.Presence(to='xx@xx.xx', 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

END 

Thanks  ;)

@roamin9zhoo.xuan@ngosoft.com

Recommended