これは何
nodejsを使ってslack botを作った話。
インフラエンジニアだけどコードもかけるようになりたい、といって少しだけ時間をもらってbotを作る仕事をやった。
その時のメモ的なもの。
何を使う
botkitというツールキットを使う。
hubotと何が違うの? そういうのを調べたりはしてません。お手軽にモダンな感じで作れるよ、とおすすめされたので使った見た感じ。
コード
コードは長くないのでここに貼ってしまう。
npm install --save botkit
とかして、package.json作らせた(と思う)。
channel id はチャンネルがprivateの場合はhttps://api.slack.com/methods/groups.list/test で確認する。publicの場合は /channels.list/test で確認する。slackの場合。facebook messanger とかだとまた別の取得方法だと思う。
token はbot のものを使用する。https://app.slack.com/apps/new/bot から作成したもの。custom botについてはこちらを参照のこと:https://api.slack.com/bot-users。
const Botkit = require('botkit');
const os = require('os');
// 色々変数チェック。他dest,originについてはここの説明では略
if (!process.env.token) {
console.warn('Error: Specify token in environment');
process.exit(1);
}
const controller = Botkit.slackbot({
debug: true,
});
controller.spawn({
token: process.env.token,
}).startRTM();
const destChannel = process.env.destChannel;
const originChannel = process.env.originChannel;
controller.hears('.*https?://www.example.com[sS]*', 'ambient', (bot, message) => { // [sS]* は改行含む全一致。.*だと改行入らない。ambient はbotが全発言を拾うということ(direct_messageとかもある)。
// 指定のチャンネルのときのみ発言を拾う
if (message.channel === originChannel) {
const matchMessage = message.text;
const userId = message.user;
bot.api.users.info({ user: userId }, (userApiError, userApiRes) => {
const userName = userApiRes.user.profile.real_name;
bot.api.channels.info({ channel: message.channel }, (channelApiError, channelApiRes) => {
// private channel はchannels apiからは情報取得できない。groups apiなら取れるが、privateチャンネル名は知られなくても良い
const channelName = (channelApiError !== 'channel_not_found') ? channelApiRes.channel.name : 'どこかprivate channel';
bot.say(
{
text: `${userName}さんが作品リンクを投稿しました(in #${channelName}) \n -------------------------- \n ${matchMessage} \n --------------------------`,
channel: destChannel,
});
});
});
}
});
起動は
originChannel='<channel_id1>' destChannel='<channel_id2>' token=<bot_token> node urlcopy_bot.js
その他
eslint 使ってみた。
明らかな表記ブレは適当に直してくれるし、コードはきれいになるし、紛らわしい表記とか教えてくれるし、割と良かった。
他のところにもlint入れてみようかなと思った。
追記
slack接続が切れてしまって(close RTMになる) botが死んだように見える現象があった。
最初は自分で close_rtmイベントをフックしてconnectするように書いていたが、botkitはデフォルトで予期せぬ接続断があったらreconnectするようになっているため、両方で接続しに行ってしまい、多重接続(このbotの場合は2回投稿してしまう動き)。参考:https://github.com/howdyai/botkit/blob/bee9c5c70dcf3c024e71f2a10bdb2e425c421988/lib/Slackbot_worker.js#L230-L233
また、その他のエラーでcloseRTMしたときにはretryEnabledがtrueならreconnectしてくれるっぽい。こちらの動作に任せることにした。参考: https://github.com/howdyai/botkit/blob/bee9c5c70dcf3c024e71f2a10bdb2e425c421988/lib/Slackbot_worker.js#L70-L86
そこで、ドキュメントの通り、
const controller = Botkit.slackbot({ retry: Infinity });
みたいにしたらちゃんと接続が切れてもreconnectしてくれるようになった。