こうりんのブログ

主に勉強した事を書いていくつもり

Google Cloud PlatformでSlackBot開発【EventsAPIで受信編】

前回, GCPのCloud Functionsを使って, Slack Appの認証を行うところまでは終わりました.
今回は, Slackのイベントを受信をしてそれに対する簡単なアクションを返すところまでやってみようと思います.

AWSでの場合についてみると, Amazon API Gatewayを経由してAWS Lambdaを実行しているようです.
同様にGCPで考えると, Cloud Endpoints経由でCloud Functionsにリクエストを渡す感じかな?と思ったのですが, そもそもCloud FunctionsはHTTP リクエストをそのままイベントとして動くので, 単体でできそうな気がします.

というわけで構成はこんな感じ.

f:id:Kourin1996:20180501045824j:plain

Slackでイベントが発生するとWebhookが起動します.
フック先をCloud Functionにしておきます, Cloud FunctionではSlackのWeb APIを叩きます.
WebAPIではメッセージの送信などができます.

Cloud Functionの作成(イベント受信)

前回同様にHTTPリクエストを受信した際に実行する関数を作成します.
EventsAPIでは, hook先のアドレスを登録する際に正しいURLかどうか確認が行われます.
これは, challenge パラメータがを含むPOSTリクエストが送られた時, challenge の値だけを返せば大丈夫です.
というわけで, とりあえず以下のようにしました.

index.js
exports.onReceiveSlackEvents = (req, res) => {
    if (req.body.challenge !== undefined) {
        console.log('on Challenge Request');
        res.end(req.body.challenge);
        return;
    }
    console.log(req.body);
    res.status(200).send('hoge');
};

Slack Appの設定

サイドメニューから Event Subscriptions に移動し, Enable Events をonにします.
そして, Request URL をCloud FunctionsのURLにします.
この時URLの確認が行われます, 正しくCloud Functionsの設定ができていれば, 成功します.

続いて, Subscribe to Workspace Events から受信するイベントを選びます.
今回は, ユーザのメッセージ投下を確認するために, message.channels を選択します.
右下のSave Changesを選択して設定は完了です.

Event受信確認

botを適当なチャンネルに招待して, チャンネルにメッセージをpostしてみます.
StackdriverのLoggingから次のようなログが流れてくれば, 正しくイベントを受信しています.

f:id:Kourin1996:20180501053431p:plain

Cloud Functionの作成(メッセージ送信)

最後にメッセージ送信部分を記述します.

今回はnode.jsの以下のライブラリを用いました.

github.com

ソースは下のような感じ.
今回は購読するユーザを直書きしました.
トークンは前回の最後に取得したトークンのことです.
設定画面では OAuth & Permissions >> OAuth Tokens & Redirect URLs >> Tokens for Your Workspace >> OAuth Access Token に書いてあります.

userを指定しないと, botのメッセージもイベントで受信して返事しちゃうので, botのメッセージ送信が止まらなくなる.
ちゃんとしたコードを書くときは, 受信したイベントがbot自身かチェックする必要がある.
また, 最後にres.end(null);をしないとタイムアウトまで終わらないのでメッセージが2回送信されることもある.

index.js
exports.onReceiveSlackEvents = (req, res) => {
    if (req.body.challenge !== undefined) {
        console.log('on Challenge Request');
        res.end(req.body.challenge);
        return;
    }

    const { WebClient } = require('@slack/client');
    const channelID = (送信するチャンネルID);
    const token = (トークン);
    const user = (対象のユーザ);

    console.log('onReceive Slack Event ', req.body);
    let web = new WebClient(token);

    if (req.body.event.type === 'message' && req.body.event.user === user) {
        let msgBody = req.body.event.text;
        web.chat.postMessage({
                channel: channelID,
                text: msgBody
            })
            .then((res) => {
                console.log('Message sent: ', res);
            })
            .catch(console.error);
    };
    res.end(null);
    return;
};
package.json
{
  "name": "Test-SlackApp-EventsAPI",
  "version": "0.0.1",
   "dependencies": {
    "@slack/client": "^4.2.0"
  }
}

botをチャンネルに招待しメッセージをチャンネルに投稿して, メッセージが返ってきたら終わり.

参考

qiita.com