LoginSignup
35
36

More than 5 years have passed since last update.

robot.brain を使った Hubot スクリプトをつくろう

Posted at

これは Hubot Advent Calendar 2014 の 18 日目の記事です。

また、今回は @bouzuya の Hubot 連載の第 11 回です。目次は、第 1 回の記事にあるので、そちらをどうぞ。

ちなみに昨日は @hiconyan さんの Hubotで「どのコマンドにも一致しない」ときの処理 でした。Robot#helpCommands() については説明する予定だったんだけど、もういいかなー。

前回まで、そして今回は

さて、前回は 設定を読み込む Hubot スクリプトをつくろう ということで、外部 (環境変数) から設定を読み込む Hubot スクリプトをつくりました。

今回は、robot.brain を使って Hubot スクリプトのデータを永続化してみましょう。

brain はシンプルな KVS であり、Hubot の標準の永続化の仕組みです。実際にどうやって永続化するのかは次回説明します。今回は使うだけです。

サンプルコード

以下のサンプルコードは、ちょっと長いのですが、メッセージを 7 日後に予約できる Hubot スクリプトです。

Heroku にデプロイした場合、単純にメモリーに保持すると 7 日後までに何度も再起動がかかり、予約情報を失ってしまいます。そこで、予約情報を brain に書き込むことで永続化します(どのような形式で永続化するかはまた後日紹介します)。永続化しておけば、再起動がかかってもデータが失われる心配はありません。

7days-later.coffee
# Description
#   A Hubot script for sending a message to yourself seven days later.
#
# Configuration:
#   None
#
# Commands:
#   hubot 7d add <message> - reserve the sending message
#   hubot 7d list - list reserved messages
#
# Author:
#   bouzuya <m@bouzuya.net>

moment = require 'moment'

module.exports = (robot) ->
  key = '7days-later'

  robot.respond /7d add (\S+)$/, (msg) ->
    message = msg.match[1]
    messages = robot.brain.get(key) ? []
    i = { room: msg.envelope.room, at: moment().add(7, 'days'), message }
    messages.push i
    robot.brain.set(key, messages)
    msg.send "#{i.at.format('YYYY-MM-DD HH:mm')} #{i.message}"

  robot.respond /7d list$/, (msg) ->
    messages = robot.brain.get(key) ? []
    message = messages.sort (a, b) ->
      if a.at.isSame(b.at)
        0
      else if a.at.isBefore(b.at)
        -1
      else
        1
    .map (i) ->
      "#{i.at.format('YYYY-MM-DD HH:mm')} #{i.message}"
    .join '\n'
    msg.send message

  watch = ->
    setTimeout ->
      messages = robot.brain.get(key) ? []
      now = moment()
      targets = messages.filter (i) -> i.at.isBefore(now)
      newMessages = messages.filter (i) -> !i.at.isBefore(now)
      if messages.length isnt newMessages.length
        robot.brain.set(key, newMessages)
      targets.forEach (i) ->
        robot.messageRoom i.room, i.message
      watch()
    , 60000

  watch()

解説

大きく分けて、3 つになります。

  • 予約を追加する robot.respond /7d add (\S+)$/, (msg) ->
  • 予約を一覧表示する robot.respond /7d list$/, (msg) ->
  • メッセージを送信する watch = ->

予約の追加

  robot.respond /7d add (\S+)$/, (msg) ->
    message = msg.match[1]
    messages = robot.brain.get(key) ? []
    i = { room: msg.envelope.room, at: moment().add(7, 'days'), message }
    messages.push i
    robot.brain.set(key, messages)
    msg.send "#{i.at.format('YYYY-MM-DD HH:mm')} #{i.message}"

ポイントは brain です。

brain からの値取得

messages = robot.brain.get(key) ? []

brain から値を取得しています。もし取得できなかった場合には、nullが返されるので、代わりに空の配列を設定しています。

brain への値設定

robot.brain.set(key, messages)

brain へ値を設定しています。

予約の一覧

特に言うことはないですね。 robot.brain.get(key) で取得して表示するだけですね。

メッセージの送信

  watch = ->
    setTimeout ->
      messages = robot.brain.get(key) ? []
      now = moment()
      targets = messages.filter (i) -> i.at.isBefore(now)
      newMessages = messages.filter (i) -> !i.at.isBefore(now)
      if messages.length isnt newMessages.length
        robot.brain.set(key, newMessages)
      targets.forEach (i) ->
        robot.messageRoom i.room, i.message
      watch()
    , 60000

  watch()

setTimeout() を使って定期的に メッセージを確認しています。

setInterval() を使って定期的に確認する方法もありますが、一回ずつ実行したいので、今回は setTimeout() を使っています。

動かしてみましょう

念のため動かしましょう。

$ HUBOT_SHELL_USER_NAME='bouzuya' PATH="./node_modules/hubot/node_modules/.bin:$PATH" $(npm bin)/hubot -a shell -n hubot -r src                               
hubot> hubot 7d add hoge
2014-12-25 23:33 hoge
hubot> hubot 7d add 忘れたころにやってくる
2014-12-25 23:34 忘れたころにやってくる
hubot> hubot 7d list
2014-12-25 23:33 hoge
2014-12-25 23:34 忘れたころにやってくる

7 日後なので、確認できないのですが、たぶん来ます。

まとめ

robot.brain の値の取得・設定を説明しました。

実際にどうやって永続化するのかや、問題点などは次回説明します。

今回の Hubot スクリプトは bouzuya/hubot-7days-later に置いています。動かない場合には参考にしてみてください。

最後に

実は今回は bouzuya/hubot-brainfxxk というボツになったネタがあって、brain といえば brainf*ck だろうと思い、 をつくったのだけど、余計なコードが多すぎるので却下されました。

というか、brain 嫌いなんですよね。

35
36
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
35
36