Ⅲ. HubotによるBotの作成
1. Botの雛形を作成
※ 以降の作業は適当な作業ディレクトリを作って行ってください。
また、以降の説明はカレントディレクトリが作成した作業ディレクトリである前提で進みます。
yeoman (ヨーマン)でbotの雛形を作成する
以下コマンドを叩くとHubotのテンプレートの作成が始まる
yo hubot
また、以下の入力が求められるので、適宜入力する。
Owner
所有者を表す情報(メールアドレスなど)。
省略可能(デフォルト値が設定される)。Bot name
Botの名前。
任意に入力可能。
省略可能(ディレクトリ名が設定される)。Description A simple helpful robot for your Company
Botの概要。
省略可能。Bot adapter
Botのアダプターを選択。
今回はSlack向けのBotなので"slack"と入力
yo hubot
? ==========================================================================
We're constantly looking for ways to make yo better!
May we anonymously report usage statistics to improve the tool over time?
More info: https://github.com/yeoman/insight & http://yeoman.io
========================================================================== Yes
_____________________________
/ \
//\ | Extracting input for |
////\ _____ | self-replication process |
//////\ /_____\ \ /
======= |[^_/\_]| /----------------------------
| | _|___@@__|__
+===+/ /// \_\
| |_\ /// HUBOT/\\
|___/\// / \\
\ / +---+
\____/ | |
| //| +===+
\// |xx|
? Owner example@com
? Bot name botname
? Description A simple helpful robot for your Company
? Bot adapter (campfire) slackgot back false
? Bot adapter slack
・
・
・
2. Hubotの起動
以下コマンドで、Hubotを起動する
sudo PORT=80 HUBOT_SLACK_TOKEN=XXXXX bin/hubot -a slack
ポイント
環境変数
PORT
Hubotが利用するポート番号を指定する。ポート番号は任意のものを利用できるが、今回はVagrantのプロビジョニングで80番ポートを開けているので、80を利用する。HUBOT_SLACK_TOKEN
「Ⅰ. SlackとHubotの連携」で設定を行った際に、発行されたトークンを設定する。
hubotコマンドのオプション
- -a slack
Hubotのアダプターを指定する。今回はSlackのBotを作成するため、Slackを指定する。
- -a slack
3. Hubotのライブラリを使ってみる
yeomanで作成したHubotの雛形にはサンプルソースが含まれている
scripts/example.coffee
サンプルソースの多くはコメントアウトされているので、コメントアウトを外して、下記の robotオブジェクトのメソッド を参考に、サンプルソースの動きを確認してみてください。
example.coffee(コメントアウトを除き、補足コメントを追加)
# Description:
# Example scripts for you to examine and try out.
#
# Notes:
# They are commented out by default, because most of them are pretty silly and
# wouldn't be useful and amusing enough for day to day huboting.
# Uncomment the ones you want to try and experiment with.
#
# These are from the scripting documentation: https://github.com/github/hubot/blob/master/docs/scripting.md
module.exports = (robot) ->
###
第一引数の"/badger/i"は正規表現で、
最後に"i"を付与することマッチングの際、大文字小文字を無視する
###
robot.hear /badger/i, (res) ->
res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
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"
robot.hear /I like pie/i, (res) ->
res.emote "makes a freshly baked pie"
lulz = ['lol', 'rofl', 'lmao']
robot.respond /lulz/i, (res) ->
# res.random は配列の要素をランダムで1つ返すメソッド
res.send res.random lulz
robot.topic (res) ->
res.send "#{res.message.text}? That's a Paddlin'"
enterReplies = ['Hi', 'Target Acquired', 'Firing', 'Hello friend.', 'Gotcha', 'I see you']
leaveReplies = ['Are you still there?', 'Target lost', 'Searching']
robot.enter (res) ->
res.send res.random enterReplies
robot.leave (res) ->
res.send res.random leaveReplies
answer = process.env.HUBOT_ANSWER_TO_THE_ULTIMATE_QUESTION_OF_LIFE_THE_UNIVERSE_AND_EVERYTHING
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?"
robot.respond /you are a little slow/, (res) ->
setTimeout () ->
res.send "Who you calling 'slow'?"
, 60 * 1000
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?"
###
Webサーバとして機能することも可能。
下記処理は、「http://192.168.10.200/hubot/chatsecrets/XXX」という
URIにPOSTメソッドでアクセスするとメソッドが呼び出される。
###
robot.router.post '/hubot/chatsecrets/:room', (req, res) ->
room = req.params.room
data = JSON.parse req.body.payload
secret = data.secret
robot.messageRoom room, "I have a secret: #{secret}"
res.send 'OK'
robot.error (err, res) ->
robot.logger.error "DOES NOT COMPUTE"
if res?
res.reply "DOES NOT COMPUTE"
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
res.reply 'zzzzz'
robotオブジェクトのメソッド
それぞれのメソッドはそれぞれの一定の条件で呼び出され、呼び出されたメソッドの処理はコールバック関数内に定義します。
また、コールバックの引数のresオブジェクトのsendメソッドを呼ぶことによってSlackにメッセージを返すことができます。
respond (message, callback(res))
messageに含まれるワードが投稿されると呼ばれるメソッド。
hearとの違いはBotにメンションをしないと呼ばれない。
例) Botの名前が"botname"で、ソースが以下の場合
robot.respond (/hello.*/i, callback(res){
// 処理
});
このメッセージには反応する
@botname hello makoto
このメッセージには反応しない
hello makoto
hear (message, callback(res))
messageに含まれるワードが投稿されると呼ばれるメソッド。
respondとの違いはBotにメンションをしなくても呼ばれる。
enter (callback(res))
誰かがチャネルに参加した時に呼ばれるメソッド
leave (callback(res))
誰かがチャネルを抜けた時に呼ばれるメソッド
topic (callback(res))
トピックに変更があると呼ばれるメソッド
messageRoom (room, resMsg)
第一引数で指定したチャネルに、第二引数で指定したメッセージを送信する。
error (callback(err, res))
エラーが発生すると呼ばれるメソッド
robot.brainについて
Hubotにはデータ永続化の仕組みが備わっていて、robot.brainオブジェクトを利用することで、データの永続化が可能になります。 barinの内部ではKVS(key Value Store)方式のDBであるredisが利用されています。
brain.set(key, value)
例)
const key = 'key01';
let value = 'hogehoge';
brain.set(key, value)
brain.get(key)
例)
const key = 'key01';
let value = brain.set(key);
console.log(value); // hogehoge
robot.routerについて
Hubotはチャットのメッセージだけでなく、Webサーバとして機能させることもできます。
サンプルソースはpostメソッドを利用しているため、試しにくいですが、以下のようにgetメソッドを利用すればWebブラウザから簡単に試すことができます。
###
以下ソースを scripts/example.coffee に追加し、
Webブラウザで「http://192.168.10.200/test」にアクセスしてみてください。
###
robot.router.get '/test', (req, res) ->
html = """
<html>
<script type="text/javascript">(function(){ alert('called from Hubot'); } )();</script>
</html>
"""
res.type 'html'
WebAPIの呼び出し
サンプルソースにはありませんが、Hubotは簡単にWebAPIを呼び出すことができます。
robot.http(url)
例)http://example.com/member/list からgetメソッドでデータを取得
robot.http('http://example.com/member/list')
.get() ((err, res, body) => {
let obj = JSON.parse(body);
});
詳しくは https://github.com/github/hubot/blob/master/docs/scripting.md#making-http-calls を参照
4. node-inspectorによるデバッグ
以下のコマンドでHubotを起動する
sudo PORT=80 HUBOT_SLACK_TOKEN=XXXXX coffee --nodejs --debug node_modules/.bin/hubot -a slack
node-inspectorの起動
Hubotを起動したターミナルとは別途ターミナルを開く。
開いたターミナルで以下のコマンドを起動。node-inspector
起動すると以下のようにバージョン、とnode-inspectorにアクセスするためのURLが表示される
node-inspector Node Inspector v0.12.8 Visit http://127.0.0.1:8080/?port=5858 to start debugging.
node-inspectorの利用
Chromeを開き、手順2で表示されたURLにアクセスする。Chromeの開発者ツールと同じ要領でデバッグができます