第4回までで,Hubotをセットアップしてチャットツールに接続し,独自のスクリプトを書くことができるようになりました。最終回となる今回は,もう少し複雑なスクリプトの書き方をサンプルコードをベースに紹介します。
定期実行で定時ミーティングの時間を通知する
デイリースクラムの時間を通知すると言った定期的な処理をHubotに行わせたい場合,cronモジュールを使うと便利です。本節では,cronモジュールの導入方法と使用例のサンプルスクリプトを掲載します。
cronモジュールの導入
cronモジュールのようなnpmのモジュールを使用するには,Hubotを導入したディレクトリの直下にあるpackage.jsonファイルのdependenciesにモジュールの情報を追加します。
通常,Hubotをインストールした直後はdependenciesの項目は次のようになっています。
"dependencies": {
"hubot": ">= 2.6.0 < 3.0.0",
"hubot-scripts": ">= 2.5.0 < 3.0.0"
},
ここにcronモジュールを追加することでスクリプトからcronモジュールを使用できるようになります。
"dependencies": {
"hubot": ">= 2.6.0 < 3.0.0",
"hubot-scripts": ">= 2.5.0 < 3.0.0",
"cron": ">= 1.0.4"
},
サンプルスクリプト
cronモジュールを使って月曜日から金曜日の午前11時にミーティングの開催を呼びかけるスクリプトの例を示します。
cronJob = require('cron').CronJob
module.exports = (robot) ->
cronjob = new cronJob('0 0 11 * * 1-5', () =>
envelope = room: "#chatroom"
robot.send envelope, "デイリースクラムを始めましょう @all"
)
cronjob.start()
見てのとおり,cronモジュールでは,通常のcronと同様の書式で定期処理を書くことができます。
注意点として,普通のhearやrespondを使った発言方法ではmsgオブジェクトのsendメソッドなどを使いますが,定期実行のように誰かから話しかけられて返答するのではない場合は,robotオブジェクトのsendメソッドを直接使ってチャットルームに発言することになります。
sendメソッドの第一引数envelopeは発言先のチャットルームや発言対象のユーザの情報を格納したオブジェクトです。この例ではhubot-ircを使ってIRCの#chatroomチャンネルに発言することを想定しています。どのようなenvelopeが必要かは,使用しているAdapterよって異なるため注意が必要です。
cronモジュールの詳しい使い方はリファレンスを参照してください。
永続化機能で投票結果を保存する
Hubotに何かを記憶させようとしたとき,初期状態ではメモリ上に情報を置くことしかできません。そのため,Hubotを再起動すると情報が消えてしまいます。この問題に対して,Hubotではbrainというインターフェースを通じて様々なストレージに情報を永続化できます。
本節では,Redisを使った永続化の方法と,チャット参加者に投票する仕組みを作る例を記します。
redis-brainによるRedis永続化機能の追加
Redisを使った永続化を行うには,HubotからアクセスできるところでRedisが動いている必要があります。Redisの公式サイトなどを参考に予めRedisをインストールして,起動してください。
HubotとRedisを接続するには,hubot-scriptsのredis-brain.coffeeを使う方法が簡単です。redis-brain.coffeeを有効化するためには,hubot-scripts.jsonでredis-brain.coffeeを読み込み,環境変数で接続先のRedisインスタンスを指定します。
hubot-scripts.json
["redis-brain.coffee"]
run_hubot.sh
#!/bin/bash
# redis://<host>:<port>[/<brain_prefix>]
export REDIS_URL=redis://127.0.0.1:6379/hubot
bin/hubot
このように設定すると,Hubotのbrainから保存したデータを127.0.0.1:6379のRedisにhubot:storageというキーでJSON文字列として保存するようになります。
サンプルスクリプト
brainを使った永続化のサンプルとして,チャット上で何か良いことをしたメンバーに投票する仕組みを作ってみます。
module.exports = (robot) ->
KEY_SCORE = 'key_score'
getScores = () ->
return robot.brain.get(KEY_SCORE) or {}
changeScore = (name, diff) ->
source = getScores()
score = source[name] or 0
new_score = score + diff
source[name] = new_score
robot.brain.set KEY_SCORE, source
return new_score
robot.respond /list/i, (msg) ->
source = getScores()
console.log source
for name, score of source
msg.send "#{name}: #{score}"
robot.hear /^(.+)\+\+$/i, (msg) ->
name = msg.match[1]
new_score = changeScore(name, 1)
msg.send "#{name}: #{new_score}"
robot.hear /^(.+)--$/i, (msg) ->
name = msg.match[1]
new_score = changeScore(name, -1)
msg.send "#{name}: #{new_score}"