hubot adapterの作り方
はじめに
最近chatworkやtypetalkといったコミュニケーションツールのhubot adapterを作ったりしてます。
どちらもまだ開発途中ですが、これまでに得た知見を残していこうと思います。
間違った情報があったらコメント等でご指摘いただければ嬉しいです。
hubotとは
hubotはgithub社が開発しているchat用のbotフレームワークです。
通常のbotとどう違うのかというと、botのロジックとchatとの処理部分を分離して、様々なサービスへ応用できるようにしているところです。
前者のbotのロジック部分をhubot scriptと呼び、後者のchatとの処理部分をhubot adapterと呼びます。
hubot scriptには例えば天気を教えてくれるものからjenkinsにbuildを行わせるものまであります。 もちろん、自分で開発して追加することも簡単にできます。scriptは開発例なども豊富でわかりやすいです。
対してhubot adapterは各種サービスとのやりとりを行うものです。IRC用はもちろん、twitter用やyammer用などさまざまなadapterが公開されています。今回説明するのはこのadapterの開発方法です。
hubotについてもっと詳しく知りたい方や、hubotの導入方法などは、こちらの資料が非常にわかりやすいです。
hubotのアーキテクチャ
矢印の説明とかなんかいろいろ怪しいですが、だいたいこんなイメージです。
この図のうち、真ん中の青いところがhubotのコア部分となっており、scriptとadapterとの橋渡しや便利機能の提供をしています。
adapterの役割は、サービスからデータを受け取り(run)、そのデータをrobotというモジュールに渡し(receive)、hubot scriptから受け取ったメッセージをサービスに渡すこと(send/reply)です。
公式ドキュメント
adapterの実装方法を知るには公式ドキュメントが一番です。 この記事を書いている時点で、ドキュメントには以下の説明があります。
The best place to start is
src/adapter.coffee
, and inheriting fromAdapter
. There is not as much documentation as could exist (yet!), so it is worth reviewing existing adapters as well as how hubot internally uses an adapter.(意訳: まず
src/adapter.coffee
を読め。あ、まだドキュメントはねーから。あとはコード読んで頑張れよ!)
というわけでコードを読みましょう!!
というだけなのもアレなので、すこし補足したいと思います。
adapterのコード
実際にhubotのsrc/adapter.coffeeを見てみると、Adapter
というクラスがあります。
これがadapterのベースとなります。
実装時にはAdapter
を継承したクラスを作り、必要なメソッドをオーバーライドしていくことになります。
その中でも重要なメソッドはsend
とrun
です。
send
これはhubot scriptがなんかの処理を行ったあと、チャット側になにかを通知するときに利用するメソッドで、scriptから呼ばれるメソッドの中では一番利用頻度の高いものです。
その他のメソッドとしてはemote
やreply
、topic
、play
など色々ありますが、これらはsend
と同様にチャット側に通知するのが目的です。これらは必要に応じて実装すればよいと思います。
例えばplay
は定義のみの空メソッドですが、音の再生が可能なチャットサービスは限られているので、他のhubot adapterを見ても実装していないことが多いです。
run
hubotのコード上ではチャットとやり取りをするもののことをbot
と呼んでいます(hubotだのrobotだの色々出てきてややこしいですね)。
run
はこのbot
の初期化と、チャットから継続的にメッセージを取得し発言者情報とともに@receive
にデータを渡すための処理を実装します。
Hoge adapterの解説
実際のコードに近いものを、Hogeという架空のチャットサービスのためのadapterという形で解説したいと思います。
以下はhubot公式のadapterであるhubot-campfire
から重要な部分を抜粋して書き直したものです。
{Adapter, TextMessage} = require 'hubot' {EventEmitter} = require 'events' class Hoge extends Adapter send: (envelope, strings...) -> @bot.send str for str in strings run: -> options = token: process.env.HUBOT_HOGE_TOKEN rooms: process.env.HUBOT_HOGE_ROOMS account: process.env.HUBOT_HOGE_ACCOUNT bot = new HogeStreaming options, @robot bot.on 'message', (userId, userData, message) -> user = @robot.brain.userForId userId, userData @receive new TextMessage user, message bot.listen() exports.use = (robot) -> new Hoge robot class HogeStreaming extends EventEmitter constructor: (options, @robot) -> @token = options.token @rooms = options.rooms.split(",") @account = options.account send: (message) -> # チャットにメッセージを送信する処理... listen: -> # チャットから継続的にメッセージを取得する処理 # メッセージを取得したら... # @emit 'message', user, message
Hogeクラス
Hoge
はAdapter
を継承しているクラスで、メインの処理を記述しています。
前述のsend
とrun
というメソッドをオーバーライドしています。
send
send
は単にHogeStreaming#send
を呼び出しているだけです。
ここでenvelope
にはユーザ情報やルーム情報が格納されています。
run
run
はまず環境変数の読み取りを行っています。
hubotは設定を環境変数で行う設計になっているので、慣習的にアクセストークンや参加するルーム情報などを環境変数から受け取ります。
次にHogeStreaming
の初期化とチャットサービスメッセージ受け取りを行っています。
メッセージを受け取ったら@robot.brain.userForId
でユーザインスタンスを作り、ユーザインスタンスと取得したメッセージからTextMessage
を作成し、それを@receive
に渡しています。
@receive
にデータを渡すことで、各種hubot scriptが発火する仕組みになっています。
TextMessage
以外にもいくつかメッセージの種類が定義されているので、使い分けると良さそうです。
HogeStreamingクラス
HogeStreaming
はhubotが呼ぶところのbot
にあたるもので、チャットのAPIを叩くなどをしてメッセージの取得や送信を行うクラスです。
メッセージの取得時にはユーザ情報を付与してHoge
に渡しています。
Hoge adapterの利用
実際に利用する際には、hubot-hoge
という名前のnpmパッケージをnpm install
するか、src/robot.coffee
のHUBOT_DEFAULT_ADAPTERS
に'hoge'
を追加し、以下のコマンドでhubotを立ち上げます。
bin/hubot -a hoge
その他参考になるコード
shell & campfire
どちらも公式のadapterです。基本的な流れをつかむには一番わかりやすいと思います。
hubot-twitterは一番参考にされているadapterだと思います。 基本的な実装以外でも、OAuthやストリーミングAPIを利用するときに参考になりそうです。
その他
yammerはcometを、hipchatはXMPP(jabbar)を、idobataはpusherを使っているため、それぞれ似たようなサービスの実装時に参考になると思います。
- https://github.com/athieriot/hubot-yammer
- https://github.com/hipchat/hubot-hipchat
- https://github.com/idobata/hubot-idobata
まとめ
書く気力が尽きました…。
実装の雰囲気が伝わったかどうかわかりませんが、hubotならこんな感じで簡単にbotが作れます。 ぜひお試しください!