为hubot机器人脚本增加python扩展
原文链接 https://liutaihua.github.io/2013/04/27/hubot-nodejs-to-python-script.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
为hubot机器人脚本增加python扩展
昨天顺利把hubot跑起来了, 能回答了. 也通过nodejs的exec命令执行shell的方式, 将消息以参数的形式传给process.py处理, 以形成用py写脚本的形式.
不过上面方式有缺陷:
1, nodejs不是真正的调用py, 同时py执行的返回或直接print或写stdout(print在某种程度上就是stdout), 然后nodejs什么都不用干, 就直接相当于把stdout使用msg.send回复给gtalk了.
2, 整体结构不优美, nojs跟py还得靠exec执行shell的形式, 这种调用方式挺丑陋.
在github上找到一个脚本, 也是为了用python来写hubot的脚本, 实现方式也是用stdout和stdin结合, 达到nodejs收到gtalk消息后, 将消息传给py处理. 拿来后, 又做了一些修改, 具体过程是:
*** 封装一个Python 类, 接收stdin, 输出stdout.
- 在nodejs里启动这个py类的listen监听stdin, robot收到消息时write到stdin,
- py从stdin中读到消息, 交给指定的handler
- handler处理完成后, 输出stdout, 同时触发nodejs的event, 读取stdout通过robot发送回馈信息. **
pyscript.coffee脚本如下: class PythonScript
pyScriptPath = __dirname + '/test.py'
python_script = require('child_process').spawn('python', [pyScriptPath])
python_script.stdout.on 'data', (data) =>
receive_from_python(data.toString())
module.exports = (robot) ->
@robot = robot
#robot.respond /(.*)/i, (msg) ->
# newRegex = new RegExp("^[@]?#{robot.name}[:,]? ?(.*)", 'i')
# match = newRegex.exec msg.message.text
# send_to_python(match[1], msg.message.room, 'respond')
# @robot.msg = msg
robot.hear /(.*)/i, (msg) ->
send_to_python(msg.message.text, msg.message.room, 'hear')
@robot.msg = msg
send_to_python = (message, room, method) ->
dict =
type : method,
message : message,
room : room
python_script.stdin.write(JSON.stringify(dict) + '\n')
console.log JSON.stringify(dict)
receive_from_python = (json) ->
data = JSON.parse(json)
#@robot.messageRoom data.room, data.message # 恶心的问题, data.room在send_to_python调用传的参数msg.message.room是undefined, 导致这里不能这样用
@robot.msg.send data.message # 于是在入口的地方直接把msg对象赋给@robot里的, 在这里就能夸函数调用msg.send了.
PythonScript类封装如下: hubot_script.py
handlers = [ (r'/hubot/sys/(.)', syscmdhandler), (r'/hubot/chat/(.)', chathandler), ]
class HubotScript: def init(self): self.start_listening()
# 创建一个listen, 监听标准输入, 有输入时执行后面逻辑
def start_listening(self):
while True:
line = sys.stdin.readline()
self.receive(line)
def receive(self, json_str):
# 这里一定需要捕获错误, 否则出错会直接跳出 start_listening中的循环, 监听就结束了
try:
json_dict = json.loads(json_str)
json_dict['message'] = '/' + '/'.join(json_dict['message'].split(' ')) # 搞成类似url的形式, 方便handlers里的regex匹配
self.dispatch(json_dict)
except Exception, e:
print e
def send(self, message):
if message:
#print json.dumps(message)
sys.stdout.write(json.dumps(message) + '\n')
sys.stdout.flush()
# Message Dispatch
def dispatch(self, json_dict):
#msg_type = json_dict['type']
#if msg_type == 'hear':
# self.dispatch_generic(json_dict, _hear_handlers)
#elif msg_type == 'respond':
# self.dispatch_generic(json_dict, _resp_handlers)
self.dispatch_generic(json_dict, handlers)
def dispatch_generic(self, message, regexes):
for regex, handler in regexes:
p = re.match(regex, message['message'])
if p:
action = ' '.join(p.groups()[0].split('/'))
response = message
#response_text = handler(self, message)
response_text = handler(self, action)
if response_text:
if len(response_text) > 3000: # nodejs的JSON.parse不能处理太长的str
response_text = response_text[:3000]
response['message'] = response_text
self.send(response)
def hear(regex): # 测试用decorator def decorator(handler): handlers.append((regex, handler)) return decorator
附带一个测试程序, test.py:
#coding=utf8
from hubot_script import *
class TestScript(HubotScript):
@hear('def')
def test_handler(self, message):
return 'hear'
#@respond('abc')
#def test_handlera(self, message):
# return 'respond'
if name == 'main': test = TestScript()
**
至此**
**我已经将hubot, gtalk, python集成到一起了, 我的hubot的fork在
https://github.com/liutaihua/hubot.git
运行方式:
clone之后, 首先进入hubot:
cd hubot && npm install
然后得在进入node_modules/hubot-gtalk/为hubot-gtalk这个adapter安装依赖:
cd node_modules/hubot-gtalk/ && npm install
最后运行
./bin/hubot -a gtalk
完.