2015/09/26

SlackのOutgoing Webhookで@つきのmentionを捕まえる

そういえば今週末はISUCONですね! ぼくは昨シーズンの成績不振により自由契約の身となったためどうしよっかな〜と思案していましたが、とくに社内のどこのチームからも声がかからなかったので今年はエントリーできず予選不戦敗?となっております。ちょうど今週末F1日本GPだしゴロゴロしながらテレビ観て過ごします。

さて今日はちょっとしたTipsです。最近会社のチャットがIRCからSlackに移行している最中でして、IRCで飼ってたBOTをSlackで再実装している真っ最中の今日この頃。

社内には3時間で書かれたとりあえずIRC BotをSlackにゲートウェイするやつとかもあったりしますが、ぼくのbotは単純に時間がきたらreminderかけるというただそれだけのやつなのでさっさとSlackのWebhookベースで書き直すことにしました。元のIRC BotはPerl製ですが、もうここ1年くらいずっとほぼGoしか書いてないのでGoで書くことにしてゴリゴリと移植しています。GoならHTTP周りが異様に充実してるのでWebhookのエンドポイント作るのも便利で良いですね。

ちなみにSlackに標準でついてるslackbotには実はreminder機能があったりするので移植しなくてもいいのでは説もあったんですが、ちょっとslackbotのreminder機能では不便な点がありました。slackbotに頼んだreminderはその人にしか通知されないので、元々IRCのRemember Botでやっていた、指定時間に他人にmention投げるみたいな使い方ができないんです。とりあえずSlack Bot作ったことなかったし、いい暇つぶしになりそうなのでそのまま移植してやるぜってことで移植しているところです。

使い方はremember: 12:40 handlename: そろそろメシとか頼んでおくと、12:40になったらacidlemon: 言わなくてもわかってるとおもうけど "handlename: そろそろメシ"みたいに他人を巻き込みつつ声をかけてくれるのでおもむろにそろそろメシに行くかみたいな感じの使い方をします。その他の利用例としては、夜帰るときにプルリクのURLを書いて翌日9時45分に頼みたい人にレビューを投げるみたいな使い方してるのをよく見ますね。

日付指定もできるように作ってあるので、3週間後あたりを目がけてremember: 10/16 10:30 ビルドマシンから古いXcode消してもいいのでは?とかかけておくと「おお、それすっかりわすれてた、ナイスリマインダーや!」って過去の自分を褒めたくなる感じです。

ということで、それじゃSlack Botとして作り直すかーってことで一昨日くらいからぼちぼち手が空いたときに移植してたのですが、TCPコネクション張りっぱなしのIRCとは違い、Slack BotはHTTPのエンドポイントさえ用意できればあらかじめ指定したトリガーに合致するメッセージが来たときにHTTPでOutgoing Webhookをかけることができるので、これでやることにしました。

で、Trigger Wordsにremember:を指定して実装しはじめました。IRCではremeまで打ったらTAB打って補完する使い方をしてたので、slackにもrememberというユーザを用意したほうが補完効くのでよいなということで@rememberというBOTユーザも追加。それなら、Trigger Wordsに@remember:も追加して@アリでもナシでもWebhookがかかるようにすべきだなーってことで設定してみたのですが、@つきのTriggerがフックにかかりません。うーむ。ということで今日の本題は@つきのTriggerをかける方法の話です。

ということで、とりあえず社内でボヤいてみたところ、有力な情報をゲット!

macopyから有力情報

なるほど! そういえばSlackのメッセージはリンクとかに特殊なマークアップがなされているので、@rememberとかがユーザへのハイパーリンクになっているとそういうマークアップされた文字列になってるんでした。詳しくはSlack APIドキュメントのMessage Formattingのところに書いてあります。

ということで頑張ってこのハイパーリンクを調べてどんな文字列(ユーザID)になってるか突き止めます。どうやればわかるんだろう…と思いましたが、そもそもremember: @rememberとOutgoing WebhookにBOTユーザへのmentionを含むようにしてやったのをとりあえずデバッグ文でダンプしてやれば、webhookのメッセージテキストに<@U08DGJVJ7>と入ってるのでBOTユーザのユーザIDを突き止めることができます。

ここまでわかればあとはOutgoing WebhookのTrigger Wordsにremember:,<@U08DGJVJ7>:と指定することでremember:でも@remember:でもOutgoing Webhookが発動するようになりました。便利便利。

もちろん、BOTユーザを作ってるわけですからWebSocketでつないでrtm.startでストリームに流れてくるのを捕まえてもいいんですが、トリガー発動で処理するだけならReal Time Message API使いまでもないよねーということで、@つきのmentionをOutgoing Webhookで捕まえたい方はこちらをお試しください。

Outgoing WebhookでやるメリットはWebSocket使わなくて良いほかにももう一つあって、たぶんBOTユーザのrtm.startはそのユーザが入ってるチャンネルしか捕まえられないんじゃないかなと思うんですが(試してないのでわかんないけど)、Outgoing WebhookでチャンネルをAnyにしておけばいちいちRemember BOTを各チャンネルでinviteしなくてもTrigger Wordsで呼び出せばWebhookがかかるというのがあります。

Joinしてないチャンネルへの発言はBOTユーザといえどもそのユーザとしての発言はできませんので、このパターンでBOTからチャットをPostするときは、as_user=1せずにusernameとicon_emojiをうまいこと設定してBotユーザのTokenでchat.postMessageするという感じでやるとよいでしょう。Incomming Webhooksで投げ込むことも出来るとは思いますが、chat.postMessageで投げるのが楽だったのでぼくはBotユーザからchat.postMessageでやっています。以上、れもんのメモでした。

うされもん @acidlemonについて

|'-')/ acidlemonです。鎌倉市在住で、鎌倉で働く普通のITエンジニアです。

30年弱住んだ北海道を離れ、鎌倉でまったりぽわぽわしています。

外部サイト情報

  • twitter
  • github
  • facebook
  • instagram
  • work on kayac