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のアーキテクチャ

矢印の説明とかなんかいろいろ怪しいですが、だいたいこんなイメージです。

f:id:akiomik:20131216050155p:plain

この図のうち、真ん中の青いところがhubotのコア部分となっており、scriptとadapterとの橋渡しや便利機能の提供をしています。

adapterの役割は、サービスからデータを受け取り(run)、そのデータをrobotというモジュールに渡し(receive)、hubot scriptから受け取ったメッセージをサービスに渡すこと(send/reply)です。

公式ドキュメント

adapterの実装方法を知るには公式ドキュメントが一番です。 この記事を書いている時点で、ドキュメントには以下の説明があります。

The best place to start is src/adapter.coffee, and inheriting from Adapter. 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を読め。あ、まだドキュメントはねーから。あとはコード読んで頑張れよ!)

rtsl

というわけでコードを読みましょう!!

というだけなのもアレなので、すこし補足したいと思います。

adapterのコード

実際にhubotのsrc/adapter.coffeeを見てみると、Adapterというクラスがあります。

これがadapterのベースとなります。 実装時にはAdapterを継承したクラスを作り、必要なメソッドをオーバーライドしていくことになります。

その中でも重要なメソッドはsendrunです。

send

これはhubot scriptがなんかの処理を行ったあと、チャット側になにかを通知するときに利用するメソッドで、scriptから呼ばれるメソッドの中では一番利用頻度の高いものです。

その他のメソッドとしてはemotereplytopicplayなど色々ありますが、これらは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クラス

HogeAdapterを継承しているクラスで、メインの処理を記述しています。 前述のsendrunというメソッドをオーバーライドしています。

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.coffeeHUBOT_DEFAULT_ADAPTERS'hoge'を追加し、以下のコマンドでhubotを立ち上げます。

bin/hubot -a hoge

その他参考になるコード

shell & campfire

どちらも公式のadapterです。基本的な流れをつかむには一番わかりやすいと思います。

twitter

hubot-twitterは一番参考にされているadapterだと思います。 基本的な実装以外でも、OAuthやストリーミングAPIを利用するときに参考になりそうです。

その他

yammerはcometを、hipchatはXMPP(jabbar)を、idobataはpusherを使っているため、それぞれ似たようなサービスの実装時に参考になると思います。

まとめ

書く気力が尽きました…。

実装の雰囲気が伝わったかどうかわかりませんが、hubotならこんな感じで簡単にbotが作れます。 ぜひお試しください!