botといえばHubotが有名ですが、個人的にはJavascriptがそんなに得意でもないし、hubot-slack moduleもv3→v4で大幅に仕様が変わって追従できなくなり、Slackとの連携では稀に接続が切れてBot自体黙り込んでしまうというつらい状況で、ほとほと疲れてしまいました。一方、Python製のErrbotが良い出来なので紹介します。
なお、既に先人の方が入門については記載されているので、「HubotでできるアレはErrbotでできるのか」という観点で紹介したいと思います(あとメリット/デメリットも紹介します)。
Errbotを試しに導入する
これから紹介するErrbotとその機能については、以下にまとめたDockerコンテナで確認することができるようにしました。(プラグイン自体は、公式からほとんど引っ張ってきただけですが…)
上記READMEの通り、以下の通り実行すればTextモードで対話的に実行できます。
docker run -it --rm \
--name err-text \
-e BACKEND=Text \
-e BOT_USERNAME="@testbot" \
-e BOT_ADMINS="@tkit" \
-e "TZ=Asia/Tokyo" \
rroemhild/errbot
Slackで動かす場合は、 BACKEND=Slack
とする必要があります。(Bot用のTOKENは別途取得してください)
docker run --rm \
--name err-slack \
-e BACKEND=Slack \
-e BOT_TOKEN=xoxb-...... \
-e BOT_USERNAME="@testbot" \
-e BOT_ADMINS="@tkit" \
-e "TZ=Asia/Tokyo" \
rroemhild/errbot
BOT_USERNAME
とBOT_ADMINS
は好きに書き換えてください。
起動後、以下のコマンドでプラグインをインストールしてください。
!repos install https://github.com/tkit/errbot-plugin-example
機能について
基本的な命令
Errbotは、命令をmentionなどで送り込むのではなく、(デフォルトでは)!
というPrefixを付与することによって発行します。
[@tkit ➡ @testbot] >>> !hello
[@tkit ➡ @testbot] [␍]
Hello, world!
[@tkit ➡ @testbot] >>> !help
[@tkit ➡ @testbot] [␍]
All commands
Backup
Backup related commands.
• !backup - Backup everything.
ChatRoom
This is a basic implementation of a chatroom
• !room create - Create a chatroom.
• !room list - List chatrooms the bot has joined.
• !room destroy - Destroy a chatroom.
(snip)
mentionに反応して返事を返す
さて本題です。Hubotでいう robot.respond
相当のことです。
callback_mention
を使う方法と@re_botcmd
デコレータを使う方法の2種類がありますが、後者の方が使いやすいでしょう。
(早速ですがTextモードでは動かないので、確認する場合はSlackなどを利用してください)
callback_mention
を使う
callback_mention
関数を使うことで、非常に簡単に反応させることができます。
from errbot import BotPlugin, botcmd
class Example(BotPlugin):
# like robot.respond
def callback_mention(self, message, mentioned_people):
for identifier in mentioned_people:
self.send(message.frm, 'User %s has been mentioned' % identifier)
if self.bot_identifier in mentioned_people:
self.send(message.frm, 'Errbot has been mentioned !')
コードを見ると分かる通り、callback_mention
は、別にBot向けのmentionに限らず あらゆるmention に反応します。そこから、Bot向けのmentionだけを条件で取ることができるので、そのときだけ反応させるようにすればよいわけです。
ちなみに、上記を動かすと、2つの条件がどちらも反応して無限ループします…。
この方法がお勧めではないのは、簡単ではあるものの、あらゆる処理がcallback_mention
に集約されてしまうためです。見通しも悪くなります。この関数を使う場合は、Bot以外のmentionに反応させる場合などに限った方がよいでしょう。
@re_botcmd
デコレータを使う
一方、関数に@re_botcmd
デコレータを利用するこちらの場合は、パターンを正規表現で指定でき、よりrobot.respond
に近い形で利用できます。
from errbot import BotPlugin, botcmd, re_botcmd
import re
class Example(BotPlugin):
# like hubot.respond
@re_botcmd(pattern=r"^(([Cc]an|[Mm]ay) I have a )?cookie please\?$")
def hand_out_cookies(self, msg, match):
yield "Here's a cookie for you, {}".format(msg.frm)
yield "/me hands out a cookie."
しかし、これだけではmentionに反応しません。mentionによっても反応させるためには、config中にある BOT_ALT_PREFIXES
を指定すれば思った通りにいきます。
今回のケースでは、 BOT_ALT_PREFIXES=@testbot
とすれば、mentionでも反応するようになります。
docker run --rm \
--name err-slack \
-e BACKEND=Slack \
-e BOT_TOKEN=xoxb-...... \
-e BOT_ALT_PREFIXES="@testbot" \ # この行を追加
-e BOT_USERNAME="@testbot" \
-e BOT_ADMINS="@tkit" \
-e "TZ=Asia/Tokyo" \
rroemhild/errbot
ただし、今回のExampleでは、これとcallback_mention
が競合するので、これもまた無限ループになります。
callback_mention
と比べると、こちらのほうが起動時にオプションが必要な分、ちょっとだけ面倒ですが、一度設定してしまえば気にならないですし、callback_mention
に全てまとめてしまうよりは後々やりやすくなるかと思います。
特定の発言に反応する
Hubotでいう robot.hear
相当のことです。
これも2種類の方法がありますが、後者のほうがよいでしょう。
callback_message
関数を使う
単純にやると、以下の方法で callback_message
を使えば、全ての発言を拾うので、その中から発動する条件だけを拾って動かすことができます。
from errbot import BotPlugin
class Example(BotPlugin):
# like hubot.hear
def callback_message(self, message):
if message.body.find('cookie') != -1:
self.send(
message.frm,
"What what somebody said cookie!?",
)
これで問題はないのですが、全てのメッセージを拾うので、この callback_message
が肥大化しますし、一見何をするのか分かりづらくなります。(Classごと分けてしまってもいいでしょうけれど)
@re_botcmd
デコレータ+prefixed=False
指定を使う
mentionのときも紹介した@re_botcmd
デコレータを使う方法もあります。デコレータのオプションでprefixed=False
とすれば、プレフィックス(つまり@testbot
相当のmention)なしで反応させることができます。
from errbot import BotPlugin
import re
class Example(BotPlugin):
# like robot.hear
@re_botcmd( pattern=r"(^| )cookies?( |$)", prefixed=False, flags=re.IGNORECASE)
def listen_for_talk_of_cookies(self, msg, match):
"""Talk of cookies gives Errbot a craving..."""
return "Somebody mentioned cookies? Om nom nom!"
発言を記憶する
Hubotでいうrobot.brain
相当のコマンドです。といっても簡単で、self
(つまり自分自身)に保存させるだけです。
from errbot import BotPlugin
class Example(BotPlugin):
# like robot.brain
@botcmd
def remember(self, msg, args):
self['TODO'] = args
@botcmd
def recall(self, msg, args):
return self['TODO']
Errbotが凄いのは、ちゃんと永続化してくれます。具体的には、BOT_DATA_DIR
に定義している場所に保存しているようです。
他の保管先(手段)もPluginによって選べます。
定期的に実行する
Hubotでも標準ではできませんが、Errbotでも標準ではできません。
…が、attakeiさんのerrcronを使えば解決してしまいます!
まとめ
上記の通り、Hubotでできる主だったことはほとんどErrbotでもできます…というか、大抵のBotなら基本機能としてこの辺りはできるのでしょうね。
加えて、今回は紹介しませんでしたがErrbotはそのBot単体でかなり完成度が高いので、「ただErrbotがあるだけ」でいろいろできるのが強みであるように思います。
Errbotのいいところ
公式の情報が非常に充実している
もう公式だけ見ればいいんじゃないかというくらい公式の情報が充実しています。プラグインの開発や設定などは、とりあえず公式を一読すれば大まかにイメージがつきます。
Botだけで運用が全てできる
例えばプラグインのインストール・アップデートや、Bot自体の再起動、ログ参照、プラグインの削除までできてしまいます。Hubotなら、別途CI/CD環境が必要になりそうなところですが、ErrbotではBotさえ立ち上げてしまえば、Botとの対話の中でほぼ全て完結してしまいます。プラグインで何かしらのバグがあると、ちゃんとそのプラグインだけを切り離してくれたりもします。
これらの重要度の高い操作は実行できるユーザを絞ることもでき、よく考えられているなぁと思います。
Errbotのあまり嬉しくないところ
Errbotにも不満はあります。
名前がひどい
Errbotという名前で9割損している気がするのですが、どうなんでしょうかね…。Google検索しても、大抵はerr + botっていう結果で他の文献がヒットしている気がします。なんでこんな名前なんだろう…。
公式以外に情報が少ない
文献は公式にかなり充実していますし、大抵それを見れば解決するのですが、すこし欲張ったことをすると途端に情報がなくなる気がします。(そもそも利用者が少ない?)
なぜか動かないことが多く、結局のところはソースを死ぬほど読んで解決することが多かったのですが、自分だけなのだろうか…。
コードでBotの全てを定義できない
Hubotの場合は、Node.jsでHubotを作り、スクリプトをパスに配置して利用することになりますが、Errbotの場合はSlackなどのChatツールのなかで対話的にBotに命令を出し、Chatツールの中でプラグインをインストールしたり各種設定を行ったりするのが主として考えられているようです。
例えば、プラグインのインストールは !repos install <path>
と命令を送り、Webserver機能を有効にするためには !plugin config <jsonで書いたconfig>
を送り込む必要があります。
普通はそれでも問題ないのですが、これの問題点はコードでBotを定義できないことにあります。つまり、一度別の環境でBotを使おうとした時に、それをそのまま持っていっただけだは設定は完了せず、Botを起動後に追加で設定をしないとセットアップが完了しないという問題があります。(回避策はあるにはあるようですが、まだそれほど追えていません)
これはメリットでもありデメリットでもあって、毎回コードを修正したりしなくとも、チャットツールとBotさえあればほとんど解決してしまうので、良し悪しあるとは思います。
Chatツールとしての「共通」を目指している
例えばSlackにはInteractive Messageという機能がありますが、どうやら公式では対応予定がなさそうです。これは、Errbotが別にSlackだけのものではないからで、他のチャットツールを広くカバーする共通部分のみを対応するからのようです。
同様に、Slackのattachmentも、他のチャットツールとパラメータを同じにできる部分だけが使えるようになっていて、attachmentの幅広く豊かな表現を全て自由に使えるかというとそんなことはないです。これも、Backendのプラグインを改修すればいいのでしょうけれど、なかなかそこまでは…。
なので、チャットツールは特定のプロダクトのみで利用しようとしている場合(大抵そうだと思いますが)は、多少の作り込みが発生すると思ったほうがよさそうです。
最後に
いろいろ書きましたが、結局は一番使いやすい言語のBotを使えばいいんじゃないかなと思いました。Botが大流行している最近で、Hubotを必ずしも使わなければならないこともないかと思います。
そんな中で、Errbotは機能が充実していていい感じだったので、しばらく使ってみようかと思います。