脚本编写 – 翻译HUBOT官方文档
本文根据官方文档对照进行的翻译注释,建议阅读官方文档。
开箱急用的Hubot并没有做太多,但它是可扩展可编程的机器人。社区编写并维护了数百个脚本,并且自己编写脚本也很容易。您可以在hubot的scripts
目录中创建自定义的脚本,也可以创建脚本包(库)并且分享到社区。
脚本剖析
当您创建Hubot时,生成器还会创建一个scripts
目录。如果您查看过那个目录里的脚本,那么您将会看到一些脚本的例子。要想编写属于Hubot的脚本,需要实现以下几点:
- 脚本要放置在hubot可识别的加载路径中(默认情况下为 src/scripts 或者 scripts)
- 脚本必须是
.coffee
或者.js
的文件 - 脚本必须要有导出函数
关于导出函数,我们这么定义的:
module.exports = (robot) ->
# your code here
这个robot
参数是您创建的机器人的一个实例。此时,我们就可以开始编写一些高大上的脚本了。
聆听和回应
由于这是一个聊天机器人,因此最常见的交互是基于消息的。Hubot可以hear
(听见)在房间中说的消息或者respond
(回复)直接在该房间发送的消息。这两种方法都使用正则表达式和回到函数作为参数。例如:
module.exports = (robot) ->
robot.hear /badger/i, (res) ->
# your code here
robot.respond /open the pod bay doors/i, (res) ->
# your code here
robot.hear /badger/i
只要消息的文本匹配成功,就会调用该回调。例如:
- Stop badgering the witness
- badger me
- what exactly is a badger anyways
robot.respond /open the pod bay doors/i
回调仅对紧跟在robot名称或别名前面的消息调用。如果robot的名称为HAL,别名为/,则将触发此回调:
- hal open the pod bay doors
- HAL: open the pod bay doors
- @HAL open the pod bay doors
- /open the pod bay doors
它将会是这样:
HAL: please open the pod bay doors
- because its respond is bound to the text immediately following the robot name
has anyone ever mentioned how lovely you are when you open the pod bay doors?
- because it lacks the robot’s name
发送和回复
该res
参数是的Response
的实例(以前,该参数以前是msg
,您可能会看到其他脚本以这种方式使用它)。有了它,你可以send
给发来消息的房间一个消息,emote
一个消息到一个房间(如果给定的适配器支持的话),或reply
发送这个消息的人。例如:
module.exports = (robot) ->
robot.hear /badger/i, (res) ->
res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
robot.respond /open the pod bay doors/i, (res) ->
res.reply "I'm afraid I can't let you do that."
robot.hear /I like pie/i, (res) ->
res.emote "makes a freshly baked pie"
The robot.hear /badgers/
回调会按照指定的方式发送一条消息,不管是谁说的, “Dave: I’m afraid I can’t let you do that.”
发送消息给房间或者用户
可以使用messageRoom函数将消息发送到指定的房间或用户。
module.exports = (robot) ->
robot.hear /green eggs/i, (res) ->
room = "mytestroom"
robot.messageRoom room, "I do not like green eggs and ham. I do not like them sam-I-am."
如果需要,可以明确指定用户名(对于管理员/管理员的抄送),也可以使用响应对象将私人消息发送给原始发件人。
robot.respond /I don’t like Sam-I-am/i, (res) ->
room = 'joemanager'
robot.messageRoom room, "Someone does not like Dr. Seus"
res.reply "That Sam-I-am\nThat Sam-I-am\nI do not like\nthat Sam-I-am"
robot.hear /Sam-I-am/i, (res) ->
room = res.envelope.user.name
robot.messageRoom room, "That Sam-I-am\nThat Sam-I-am\nI do not like\nthat Sam-I-am"
数据捕获
到目前为止,我们的脚本具有静态响应,这些响应虽然很有趣,但在功能方面很无聊。res.match
结果是match
针对正则表达式对传入消息进行处理。这只是一个JavaScript事物,最终是一个数组,索引为与表达式匹配的全文本,索引为0。如果包括捕获组,则将填充这些捕获组res.match
。例如,如果我们更新如下脚本:
robot.respond /open the (.*) doors/i, (res) ->
# your code here
如果Dave说”HAL: open the pod bay doors”,则res.match[0]
是”open the pod bay doors”,而res.match[1]
只是”pod bay”。现在我们可以开始做更多动态的事情:
robot.respond /open the (.*) doors/i, (res) ->
doorType = res.match[1]
if doorType is "pod bay"
res.reply "I'm afraid I can't let you do that."
else
res.reply "Opening #{doorType} doors"
HTTP调用
Hubot可以代表您进行HTTP调用以集成和使用第三方API。这可以通过在以下网址获得的node-scoped-http-client实例进行robot.http
。最简单的情况如下:
robot.http("https://midnight-train")
.get() (err, res, body) ->
# your code here
下面是一个POST请求例子:
data = JSON.stringify({
foo: 'bar'
})
robot.http("https://midnight-train")
.header('Content-Type', 'application/json')
.post(data) (err, res, body) ->
# your code here
err
是发送错误时的描述。通常您要检查该参数并进行相应的处理:
robot.http("https://midnight-train")
.get() (err, res, body) ->
if err
res.send "Encountered an error :( #{err}"
return
# your code here, knowing it was successful
res
是http.ServerResponse对象的一个实例。使用node-scoped-http-client时,除了statusCode
和getHeader
大多数方法无关简要。使用statusCode
来检查HTTP返回的状态码,通常来说非200的时候就意味着有一些错误。用getHeader
做一些检查,例如检查速率的限制:
robot.http("https://midnight-train")
.get() (err, res, body) ->
# pretend there's error checking code here
if res.statusCode isnt 200
res.send "Request didn't come back HTTP 200 :("
return
rateLimitRemaining = parseInt res.getHeader('X-RateLimit-Limit') if res.getHeader('X-RateLimit-Limit')
if rateLimitRemaining and rateLimitRemaining < 1
res.send "Rate Limit hit, stop believing for awhile"
# rest of your code
body
是相应的字符串形式的内容,也可能是您最关心的:
robot.http("https://midnight-train")
.get() (err, res, body) ->
# error checking code here
res.send "Got back #{body}"
JSON
如果您正在使用API,那么最简单的方法就是使用JSON,因为它不需要任何额外的依赖关系。进行robot.http
调用时,通常应设置Accept
标头以为API提供您所期望的提示。获得body
后退后,可以使用以下命令进行解析JSON.parse
:
robot.http("https://midnight-train")
.header('Accept', 'application/json')
.get() (err, res, body) ->
# error checking code here
data = JSON.parse body
res.send "#{data.passenger} taking midnight train going #{data.destination}"
有时候它可能不是一个JSON数据,就像调用的API接口发生了某些错误并试图返回一个带有错误描述的HTML。为了安全起见,你应该检查返回的header里的Content-Type
,来确定返回的内容解析式捕获各种错误。
robot.http("https://midnight-train")
.header('Accept', 'application/json')
.get() (err, res, body) ->
# err & response status checking code here
if response.getHeader('Content-Type') isnt 'application/json'
res.send "Didn't get back JSON :("
return
data = null
try
data = JSON.parse body
catch error
res.send "Ran into an error parsing JSON :("
return
# your code here
XML
XML API更难,因为没有捆绑的XML解析库。详细介绍超出了本文档的范围,但是这里有一些要检查的库:
- xml2json(最简单使用,但有一些限制)
- jsdom(W3C DOM的JavaScript实现)
- xml2js
网页屏幕抓取解析
对于那些没有API的时代,总是存在屏幕抓取解析的可能性。详细介绍超出了本文档的范围,但是这里有一些需要检查的库:
- cheerio(jQuery的熟悉语法和API)
- jsdom(W3C DOM的JavaScript实现)
高级的HTTP和HTTPS设置
如前所述,hubot使用node-scoped-http-client来提供用于发出HTTP和HTTPS请求的简单接口。在它的框架下,它使用了node的内置http和https库,但为最常见的交互提供了简单的DSL。
如果您需要直接控制http和https上的选项,请将第二个参数传递给robot.http
,该参数将传递给node-scoped-http-client
,该客户端将传递给http和https:
options =
# don't verify server certificate against a CA, SCARY!
rejectUnauthorized: false
robot.http("https://midnight-train", options)
另外,如果node-scoped-http-client不适合您,则您可以直接使用http和https或其他任何节点库(例如request)。
随机
一种常见的模式是听或响应命令,并从各种可能性中随机发送有趣的图像或文本行。开箱即用JavaScript和CoffeeScript进行此操作很烦人,因此Hubot提供了一种便捷方法:
lulz = ['lol', 'rofl', 'lmao']
res.send res.random lulz
主题
假设适配器支持,Hubot可以对房间的主题更改做出反应。
module.exports = (robot) ->
robot.topic (res) ->
res.send "#{res.message.text}? That's a Paddlin'"
进出
假设适配器支持,Hubot可以看到用户进入和离开。
enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
leaveReplies = ['Are you still there?', 'Target lost', 'Searching']
module.exports = (robot) ->
robot.enter (res) ->
res.send res.random enterReplies
robot.leave (res) ->
res.send res.random leaveReplies
自定义监听器
尽管以上帮助器涵盖了普通用户所需的大多数功能(听,响应,输入,离开,主题),但有时您希望针对监听器具有非常专业的匹配逻辑。如果是这样,您可以listen
用来指定自定义匹配函数,而不是正则表达式。
如果应执行侦听器回调,则match函数必须返回真实值。然后,将match函数的真实返回值作为response.match
传递给回调。
module.exports = (robot) ->
robot.listen(
(message) -> # Match function
# Occassionally respond to things that Steve says
message.user.name is "Steve" and Math.random() > 0.8
(response) -> # Standard listener callback
# Let Steve know how happy you are that he exists
response.reply "HI STEVE! YOU'RE MY BEST FRIEND! (but only like #{response.match * 100}% of the time)"
)
有关复杂匹配器的示例,请参见设计模式文档。
环境变量
就像其他任何node程序一样,Hubot可以直接使用process.env
访问运行环境的环境变量。这就可以用来配置及哦啊吧的运行方式,惯例是使用HUBOT_
前缀。
answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
module.exports = (robot) ->
robot.respond /what is the answer to the ultimate question of life/, (res) ->
res.send "#{answer}, but what is the question?"
如果没有定义脚本,请注意确保它可以加载,最好能够给Hubot开发人员提供如何定义它的注释,或者默认为某个脚本。这取决于脚本编写者来决定这是否是致命的错误(例如Hubbt退出),或者不需要(依赖于它的脚本)需要配置它。在可能的情况下,最好让脚本在没有任何其他配置的情况下也可以正常工作。
我们给出一个有默认行为的代码:
answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING or 42
module.exports = (robot) ->
robot.respond /what is the answer to the ultimate question of life/, (res) ->
res.send "#{answer}, but what is the question?"
如果未定义,我们设置为退出:
answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
unless answer?
console.log "Missing HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING in environment: please set and try again"
process.exit(1)
module.exports = (robot) ->
robot.respond /what is the answer to the ultimate question of life/, (res) ->
res.send "#{answer}, but what is the question?"
最后,我们更新robot.respond
进行检查:
answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
module.exports = (robot) ->
robot.respond /what is the answer to the ultimate question of life/, (res) ->
unless answer?
res.send "Missing HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING in environment: please set and try again"
return
res.send "#{answer}, but what is the question?"
依赖
Hubot使用npm来管理其依赖项。要添加其他软件包,请将它们添加到dependencies中package.json。例如,添加lolimadeupthispackage 1.2.3,如下:
"dependencies": {
"hubot": "2.5.5",
"lolimadeupthispackage": "1.2.3"
},
如果您使用来自hubot-scripts的脚本,请注意Dependencies
要添加的脚本中的文档。它们以可以复制并粘贴到的格式列出package.json
,只需确保添加必要的逗号以使其成为有效的JSON。
超时和间隔
Hubot可以使用JavaScript内置的setTimeout
让代码稍后运行。它需啊哟有一个回到方法,以及调用它之前要等待的时间:
module.exports = (robot) ->
robot.respond /you are a little slow/, (res) ->
setTimeout () ->
res.send "Who you calling 'slow'?"
, 60 * 1000
此外,Hubot还可以使用setInterval
让代码间隔一个时间运行。它也需要一个回调方法,以及连词调用之间要等待的时间:
module.exports = (robot) ->
robot.respond /annoy me/, (res) ->
res.send "Hey, want to hear the most annoying sound in the world?"
setInterval () ->
res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
, 1000
两者setTimeout
并setInterval
返回其创建的超时或间隔的ID。这可以用于clearTimeout
和clearInterval
。
module.exports = (robot) ->
annoyIntervalId = null
robot.respond /annoy me/, (res) ->
if annoyIntervalId
res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
return
res.send "Hey, want to hear the most annoying sound in the world?"
annoyIntervalId = setInterval () ->
res.send "AAAAAAAAAAAEEEEEEEEEEEEEEEEEEEEEEEEIIIIIIIIHHHHHHHHHH"
, 1000
robot.respond /unannoy me/, (res) ->
if annoyIntervalId
res.send "GUYS, GUYS, GUYS!"
clearInterval(annoyIntervalId)
annoyIntervalId = null
else
res.send "Not annoying you right now, am I?"
HTTP监听器
Hubot包括对express web框架的支持,以处理HTTP请求。它侦听由EXPRESS_PORT
或PORT
环境变量指定的端口(按此顺序优先),默认端口为8080。Express应用程序的实例位于robot.router
。通过指定EXPRESS_USER
和EXPRESS_PASSWORD
,可以使用用户名和密码对其进行保护。可以通过设置自动提供静态文件EXPRESS_STATIC
。
此方法最常见的用途是为带有Web钩子的服务提供HTTP端点,以将其推送并显示在聊天室中。
module.exports = (robot) ->
# the expected value of :room is going to vary by adapter, it might be a numeric id, name, token, or some other value
robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
room = req.params.room
data = if req.body.payload? then JSON.parse req.body.payload else req.body
secret = data.secret
robot.messageRoom room, "I have a secret: #{secret}"
res.send 'OK'
我们用curl
进行测试;另请参见下面有关错误处理的部分。
// raw json, must specify Content-Type: application/json
curl -X POST -H "Content-Type: application/json" -d '{"secret":"C-TECH Astronomy"}' http://127.0.0.1:8080/hubot/chatsecrets/general
// defaults Content-Type: application/x-www-form-urlencoded, must st payload=...
curl -d 'payload=%7B%22secret%22%3A%22C-TECH+Astronomy%22%7D' http://127.0.0.1:8080/hubot/chatsecrets/general
所有端点URL均应以文字字符串开头/hubot
(无论您的机器人名称是什么)。这种一致性使设置Webhooks(可复制粘贴的URL)更加容易,并保证URL有效(并非所有漫游器名称都是URL安全的)。
事件
Hubot还可以响应可用于在脚本之间传递数据的事件。这是通过用和封装node.js的EventEmitter来完成的。使用的是robot.emit
和robot.on
。
一个用例是拥有一个脚本来处理与服务的交互,然后在事件发生时发出事件。例如,我们可以有一个脚本,该脚本从GitHub后提交钩子接收数据,使它们在传入时发出提交,然后让另一个脚本对这些提交进行操作。
# src/scripts/github-commits.coffee
module.exports = (robot) ->
robot.router.post "/hubot/gh-commits", (req, res) ->
robot.emit "commit", {
user : {}, #hubot user object
repo : 'https://github.com/github/hubot',
hash : '2e1951c089bd865839328592ff673d2f08153643'
}
# src/scripts/heroku.coffee
module.exports = (robot) ->
robot.on "commit", (commit) ->
robot.send commit.user, "Will now deploy #{commit.hash} from #{commit.repo}!"
#deploy code goes here
如果您提供事件,则强烈建议在其数据中包含hubot用户或房间对象。这将允许hubot通知用户或聊天室。
错误处理
没有代码是完美的,并且错误和异常是可以预期的。以前,未捕获的异常会使您的hubot实例崩溃。但是现在Hubot包括一个uncaughtException
处理程序,该处理程序为脚本提供了挂钩以对异常执行某些操作。
# src/scripts/does-not-compute.coffee
module.exports = (robot) ->
robot.error (err, res) ->
robot.logger.error "DOES NOT COMPUTE"
if res?
res.reply "DOES NOT COMPUTE"
您可以在此处执行任何操作,但是您将需要特别注意挽救和记录错误,尤其是异步代码。否则,您可能会发现自己遇到了递归错误,并且不知道发生了什么。
在后台,发出了一个“错误”事件,而错误处理程序将消耗该事件。从技术上讲,uncaughtException处理程序使进程处于未知状态。因此,您应该尽可能地挽救自己的异常,并自行发出它们。第一个参数是发出的错误,第二个参数是生成错误的可选消息。
使用前面的示例:
robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
room = req.params.room
data = null
try
data = JSON.parse req.body.payload
catch err
robot.emit 'error', err
# rest of the code here
robot.hear /midnight train/i, (res) ->
robot.http("https://midnight-train")
.get() (err, res, body) ->
if err
res.reply "Had problems taking the midnight train"
robot.emit 'error', err, res
return
# rest of code here
对于第二个示例,值得考虑是用户将看到哪些消息。如果您捕获了一个错误并且要回复这个用户,则可能不需要添加自定义消息并可以发回提供给get()请求的错误消息,当然,这取决于您要在异常测处理要求。
文档描述
Hubot脚本可以在文件顶部使用带有注释的文本作为文档描述,例如:
# Description:
# <description of the scripts functionality>
#
# Dependencies:
# "<module name>": "<module version>"
#
# Configuration:
# LIST_OF_ENV_VARS_TO_SET
#
# Commands:
# hubot <trigger> - <what the respond trigger does>
# <trigger> - <what the hear trigger does>
#
# Notes:
# <optional notes required for the script>
#
# Author:
# <github username of the original script author>
其中最重要的也是面向用户的是命令。在加载时,Hubot会查看Commands
每个脚本的部分,并构建所有命令的列表。包含的内容help.coffee
使用户可以跨所有命令或通过搜索寻求帮助。因此,记录命令可以使用户更容易发现它们。
在编写文档时,一下是一些最佳的做法:
- 停留在一条线上。帮助命令经过排序,因此会将第二行插入一个意想不到的位置,该位置可能没有意义。
- 将Hubot称为Hubot,即使您的Hubot被命名为其他名称也是如此。它将自动替换为正确的名称。这使得共享脚本更容易,而无需更新文档。
- 对于
robot.respond
文档,请始终以开头hubot。Hubot会自动将其替换为您的机器人名称,如果有一个,则为机器人的别名。 - 查看手册页如何记录自己。特别是,括号表示可选部分,“ …”表示任意数量的参数,等等。
其他部分与机器人的开发人员更相关,尤其是依赖项,配置变量和注释。对hubot脚本的所有贡献都应包括与启动和运行脚本有关的所有这些部分。
缓存
Gubot公开了一个内存中的键值存储robot.brain,可用于通过脚本存储和检索数据。
robot.respond /have a soda/i, (res) ->
# Get number of sodas had (coerced to a number).
sodasHad = robot.brain.get('totalSodas') * 1 or 0
if sodasHad > 4
res.reply "I'm too fizzy.."
else
res.reply 'Sure!'
robot.brain.set 'totalSodas', sodasHad+1
robot.respond /sleep it off/i, (res) ->
robot.brain.set 'totalSodas', 0
msg.reply 'zzzzz'
如果脚本需要查找的用户数据,则对方法robot.brain
用于查找一个或多个用户可以通过ID,名称或名称的“模糊”匹配:userForName
,userForId
,userForFuzzyName
,和usersForFuzzyName
。
module.exports = (robot) ->
robot.respond /who is @?([\w .\-]+)\?*$/i, (res) ->
name = res.match[1].trim()
users = robot.brain.usersForFuzzyName(name)
if users.length is 1
user = users[0]
# Do something interesting here..
res.send "#{name} is user - #{user}"
加载脚本
有三种加载脚本的方式:
- 目录下与hubot安装捆绑在一起的所有脚本scripts/
- npm软件包中指定
hubot-scripts.json
并随附的社区脚本hubot-scripts
- 从外部npm程序包加载并在
external-scripts.json
从scripts/
目录加载的脚本按字母顺序加载,因此可以期望脚本的加载顺序一致。例如:
- scripts/1-first.coffee
- scripts/_second.coffee
- scripts/third.coffee
共享脚本
一旦构建了一些新脚本来扩展您的机器人的能力,您就应该考虑与世界分享这些脚本!至少,您需要打包脚本并将其提交到Node.js Package Registry。您还应该在下面查看共享脚本的最佳做法。
插件脚本是否已经存在
首先检查是否已存在类似您的脚本的NPM软件包。如果看不到可提供的现有软件包,则可以使用hubot脚本yeoman生成器轻松入门。
创建脚本Package
为hubot创建脚本包非常简单。首先安装hubot
为hubot创建脚本包非常简单。首先安装hubot yeoman生成器:生成器:
% npm install -g yo generator-hubot
一旦安装了Hubot生成器,创建Hubot脚本就类似于创建新的Hubot。您为hubot脚本创建目录并hubot:script
在其中生成新目录。例如,如果我们想创建一个名为“my-awesome-script”的hubot脚本:
% mkdir hubot-my-awesome-script
% cd hubot-my-awesome-script
% yo hubot:script
此时,系统将询问您一些有关脚本作者,脚本名称(由目录名称猜测),简短说明以及用于查找脚本的关键字的问题(建议您至少hubot, hubot-scripts在此清单)。
如果使用git,则生成的目录包含.gitignore,因此您可以初始化并添加所有内容:
% git init
% git add .
% git commit -m "Initial commit"
现在,您已经可以使用Hubot脚本存储库了!随意打开预先创建的src/awesome-script.coffee
文件并开始构建脚本!当你得到它准备好了,你可以将它发布到npmjs通过以下的文件!
侦听器元数据
除了正则表达式和回调外,hear和respond函数还接受可选选项Object,可用于将任意元数据附加到生成的Listener对象。此元数据可轻松扩展脚本的行为,而无需修改脚本包。
最重要和最常见的元数据键是id。应该为每个侦听器指定一个唯一的名称(options.id;默认为null)。名称应按模块确定范围(例如“ my-module.my-listener”)。这些名称允许其他脚本直接寻址各个侦听器,并通过授权和速率限制等其他功能对其进行扩展。
其他扩展可以定义和处理其他元数据键。有关更多信息,请参见侦听器中间件部分。
回到前面的示例:
module.exports = (robot) ->
robot.respond /annoy me/, id:'annoyance.start', (msg)
# code to annoy someone
robot.respond /unannoy me/, id:'annoyance.stop', (msg)
# code to stop annoying someone
这些作用域标识符使您可以在外部指定新行为,例如:
- 授权策略: “allow everyone in the annoyers group to execute annoyance.* commands”
- 速率限制: “only allow executing annoyance.start once every 30 minutes”
中间件
共有三种中间件:接收,侦听器和响应。
接收中间件运行一次,然后再检查侦听器。侦听器中间件针对与消息匹配的每个侦听器运行。响应中间件针对发送到消息的每个响应运行。
## 执行过程和API
类似于Express 中间件,Hubot按照定义的顺序执行中间件。每一个中间件都能继续执行下一个中间件(通过调用next
)或者中断(通过调用done
)。如果所有中间件都继续,那么会执行done
并且回调监听。中间件可以宝桩该done
回调,并允许在过程的后半部分执行代码(在执行侦听器回调或者更审查的中间件中断之后)。
调用中间件:
- context
- 查看每种中间件类型的API,已了解上下文将公开的内容。
- next
- 一个没有附加属性的函数,应调用该函数来继续进行下一个中间件/执行Listener回调
- next应该使用单个可选参数调用:提供的done函数或最终调用的新函数done。如果未提供参数,done则将嘉定提供了该参数。
- done
- 一个没有附加属性的函数,应该调用该函数来中断中间件的执行并开始执行完成的函数链
- done应该没有参数的调用
每一个中间件接收相同的API签名context
,next
和done
。不同种类的中间件可能在context
对象中接收不同的信息。有关更改单详细信息,请参见每种中间件的API。
中间件错误处理
对于同步中间件(永远不会屈服于时间循环),error
就像标准侦听器一样,hubot将自动捕获错误并发出时间。Hubot还将自动调用最新的done
回调以展开中间件堆栈。异步中间件应该捕获自己的异常,发出error
事件,然后调用done
。任何未捕获的异常都将中断中间件完成回调的所有执行。
侦听器中间件
侦听器中间件在匹配消息的侦听器与执行侦听器之间插入逻辑。这使您可以创建针对每个匹配脚本运行的扩展。示例包括几种授权策略,速度限制,日志记录和指标。中间件的实现与其他hubot脚本一样:代替使用hear
和respond
方法,而是使用来注册中间件listenerMiddleware
。