|
|
||
github社製のボットフレームワーク、hubotをIRCボットとして導入する話。
hubotはnode.jsとcoffescriptで書かれたgithub社製のボットフレームワーク。IRCに限らず、campfireやtwitterなどいくつかのアダプタに対応しているが、ここではIRCで利用するための導入手順を記す。
あらかじめnode.jsとnpmをインストールしておいて、hubotをインストールする。
$ git clone git://github.com/github/hubot.git $ cd hubot $ npm install
hubotは、ボットが扱うデータを永続化するためにredisというKVSを利用する。redisが入っていない時はエラーになるので動かす前にインストールする。
ちょっと試してみたいけどredisまで入れるのは面倒という時は、hubot/hubot-scripts.jsonから "redis-brain.coffee" を取り除く。
$ cat hubot-script.json ["redis-brain.coffee", "tweet.coffee", "shipit.coffee"] $ vim hubot-script.json $ cat hubot-script.json ["tweet.coffee", "shipit.coffee"]
ここできちんとインストールできたかどうか試すために以下みたいにhubotを起動してみる。
$ cd hubot $ ./bin/hubot Hubot>
このコマンドラインインターフェイスは、主にデバッグ用や動作確認用に利用する。特にエラーが出なければ成功。最初から利用できるコマンドの一覧はhubot helpで見る。
Hubot> hubot help Hubot> <keyword> tweet - Returns a link to a tweet about <keyword> <user> is a badass guitarist - assign a role to a user <user> is not a badass guitarist - remove a role from a user (中略) who is <user> - see what roles a user has youtube me <query> - Searches YouTube for the query and returns the video
試しにhubot img hogeとかやってみると、hogeで検索して出てくる画像のurlが帰ってくる。
Hubot> hubot img hoge http://www.wrapupp.com/wp-content/uploads/2011/08/DM_090513_NFL_HOGEonTAYLOR.jpg#.png
hubot用のスクリプトはhubot-scriptsという別のリポジトリにたくさん収められているので適当に物色する。
次はhubotをIRCチャンネル上で動かすためのアダプタを導入する。
IRC用のアダプタはgithubの別のリポジトリに公開されているので、それのインストール手順に従って、hubot/package.jsonの依存関係にhubot-ircを追加してnpm installすると導入できる。
$ cd hubot $ cat package.json | tail -n 8 "dependencies": { "hubot": "2.1.0", "hubot-scripts": "2.0.2", "optparse": "1.0.3", "hubot-irc": "0.0.6" // <= 追加 } } $ npm install
どのIRCサーバとチャンネルで利用するかなどの設定を含んだ以下のような起動スクリプトを書く。
#!/bin/bash # runhubot export HUBOT_IRC_NICK="hubot" export HUBOT_IRC_ROOMS="#all,#hoge,#fuga" export HUBOT_IRC_SERVER="irc.example.com" export HUBOT_IRC_PASSWORD="hoge" /path/to/hubot/bin/hubot -a irc
起動。
$ ./runhubot &
IRCチャンネルを確認してhubotがいれば成功。
hubotはボットフレームワークであるので、適当に自分でなんかコマンドを作ることが出来る。手っ取り早く何かコマンドを作る場合は、hubot/scirptsディレクトリ以下に.coffeeファイルか.jsファイルを置くと起動時に読み込んでくれる。
以下は、hello worldとチャットに書くと「こんにちは世界!」と返してくれるコマンドの例。インストールした先のhubot/scripts以下にはすでにデフォルトで利用できるコマンドがたくさんあるのでそれらを見つつコマンドを作っていくと良い。
# helloworld.coffee module.exports = (robot) -> robot.hear /hello world/, (msg) -> msg.send "こんにちは世界!"
hubotを再起動して試してみる。
$ ./bin/hubot Hubot> hello world Hubot> こんにちは世界!
coffeescript使いたくないおとかいう人は普通にJavaScriptでも書ける。
// hoge.js module.exports = function(robot) { robot.hear(/hoge/, function(msg) { msg.send('hogehoge-'); }); };
hubotを起動しなおしても、以前のデータを保持し続けたい場合は、以下みたいにrobot.brain.data以下にデータを登録して、robot.brain.save()するとデータが永続化される。
module.exports = (robot) -> robot.hear /hoge/, (msg) -> unless robot.brain.data.hoge robot.brain.data.hoge = '' robot.brain.data.hoge += "hogehoge" robot.brain.save msg.send robot.brain.data.hoge
試してみたのが以下。
$ ./bin/hubot Hubot> hoge hogehoge Hubot> hoge hogehogehogehoge Hubot> exit $ ./bin/hubot Hubot> hoge hogehogehogehogehogehoge
再起動してもデータが消えていないことがわかる。
hubotだと、今のところ何らかのユーザ側の発言が無ければ何もアクションを起こしてくれない。ボットに朝の挨拶をしたり定期的に何かのURLを流したりして欲しかったのでnode-cronを導入した。
$ cd hubot $ npm install cron
んで、定期的に何かを喋らせる例が以下。これもまたhubot/scripts以下に置く。
cron = require('cron').CronJob module.exports = (robot) -> # utility function send = (msg) -> (new robot.Response(robot, {}, "")).send msg cron '* * 11 * * *', () -> send "11時ですよー"
これで、ボットが定期的に挨拶してくれるようになった。
node.js自体が、UTF-8以外の文字コードを扱うのがあまり得意じゃないせいか、ISO-2022-JPでIRCチャンネルを利用しているところでhubotを動かすと文字列の扱いがおかしくなる。っていうか普通に文字化けする。これはhubot-ircがUTF-8以外の文字列を全く考慮していないせいなので、とりあえずの解決策としてISO-2022-JPで喋らせたい場合はtiarraなどのIRCプロクシを立ててそれを経由させるのが賢明かもしれない。
この記事では、github社製のボットフレームワークであるhubotをIRCボットとして導入するための手順などを書いた。IRCは開発者間のコミュニケーションのインフラとして利用できる。そのIRCをより便利に扱うためにIRCボットやikachanやIRCBot Consoleなどの周辺ツールを導入することは、開発者間のコミュニケーションをより促進してくれるものと思われる、まる。
gitのpushがあるたびに、コミットをIRCで通知するようにする。
適当なサーバにikachanをインストールする。ikachanはIRCにメッセージを通知するためのサーバで、これを設置することで、シェルスクリプトなどから簡単にIRCにメッセージをポストできる。
例えば、以下の様にcurlコマンドを叩くだけでIRCに通知できるようになる。
$ curl -F channel=\#catalyst-ja http://localhost:4979/join $ curl -F channel=\#catalyst-ja -F message=hoge! http://localhost:4979/notice
gitのコミットにかかわらずちょっとした通知をガンガンIRCチャンネルに通知できるので便利です。
以下のようなhookスクリプトを置く。共有gitリポジトリ以下のhooks/updateに置いて実行権限を与えると動作する。
#!/bin/sh # repository name REPO_NAME="hoge.git" # IRC channnel CHANNEL="#hoge" # ikachan server IKACHAN="http://172.16.1.22:4979" curl -s -F channel=$CHANNEL -F message="$REPO_NAME#$1 updated:" $IKACHAN/notice 1> /dev/null & git rev-list $3 ^$2 --reverse | while read COMMITID do MSG=`git --no-pager log -1 --format='%an: %s' $COMMITID` curl \ -s -F channel=$CHANNEL -F message="$MSG" $IKACHAN/notice 1> /dev/null & done
チャンネル名やメッセージなど適当に書き換えて使う。実際に自分が使っている例だと、メッセージと一緒に、gitwebのdiff画面へのリンクも通知したりしている。
ちなみに、gitリポジトリをWebDAVでホストしてるとサーバサイドフックが起動されないので注意。sshかSmartHTTP経由でリポジトリはホストしましょう。
こういう通知スクリプトを置くと、IRCチャンネルを見てるとなんとなくgitリポジトリの動きがわかるようになる。いちいちgitリポジトリのウェブインターフェイスにアクセスするような手間が省けるし、人から自分のコミットのコードを見てもらえる頻度も高くなるのでおすすめ。 あとikachan++です。
上のフックスクリプトの場合、IRCへの通知が同期的に行われるのでpushが終了するのに処理が終了するのを待たなければならない。gitのhookでブロックされるのとかありえん、などと各所から言われた気がしたのでもうすこしマシな方法を調べてみた。
単に上のスクリプトを外出しして nohup /path/to/command &で非同期に実行してやればいいだけでしょとか思って試したら、シェルスクリプト自体は非同期で実行されているっぽいものの、なぜか通知処理が終了するまでpushが終わらない。シェルスクリプトに関する知識が足りないせいか何故かよく分からなかった。だれか教えて下さい。
もう少し調べた結果、以下みたいに単にatコマンドに実行したいコマンドを流してやればいいことがわかった。
#!/bin/sh # /path/to/notificationは上に書いたスクリプトを外出ししたもの echo "/path/to/notification $1 $2 $3" | at now
atコマンドは指定した時間に一度だけコマンドを発行してくれるコマンドだが、at nowにコマンドを指定することで、別プロセスで即座にコマンドが実行される。これで、通知処理が非同期で実行されるようになってブロックされなくなりgitのpushが早くなった。よかったですね、まる。
PHPのunserializeみたいに、JavaScriptでJSONからオブジェクトのデシリアライズする方法。とりあえずこうやってるけど、誰かなんかいいソリューション教えて下さい。これだと、同じオブジェクトを参照しているプロパティがデシリアライズした後、違うオブジェクトを指すようになる + 自分でクラス名を指定してあげないといけない。
// Hogeクラスの作成 var Hoge = function(msg) { this.msg = msg; }; Hoge.prototype = { doSomething : function() { console.log(this.msg); } }; Hoge.deserialize = function(json) { var result = JSON.parse(json); result.__proto__ = Hoge.prototype; return result; }; // JSONからHogeクラスのオブジェクトを復元する Hoge.deserialize(JSON.stringify(new Hoge('hoge'))).doSomething(); // => hogeと表示される