AWS LambdaとMicrosoft BotFrameworkでサーバーレスなSlackBotを構築する（導入編）

# はじめに

開発でBotを活用する場面は少なくないと思いますが、皆さんはどうやって実装していますか？

簡単なものであれば、webhookにpostするだけで終わるのでガリガリ書くのもありですが、
インタラクティブな処理を書こうと思った場合には、やっぱりフレームワークを使ったほうが楽ですよね。

ただ、botのためだけにサーバー管理はしたくないのですが、
公開されているbotフレームワークは、
サーバーレス環境へのデプロイは考慮されていないようでした（自分のググりが足りないかもしれませんが）
そこで、AWSのサーバーレスでMS BotFrameworkを動かせるようにするのが今回の話です。

今回のコードはこちらのgithubリポジトリで公開しています。
https://github.com/takaaki-s/serverless-botframework

# どうやって動かそうか考えた

今回、数あるBotFrameworkの中でも本命の、Microsoft BotFrameworkと
Slackを使いたかったので、botbuilder-adapter-slackを使いました。

このadapterは内部でExpressを使用しているので、
aws-serverless-expressを使うとサーバーレス動かせそうというのも選択のポイントです。

それから、このBotFrameworkは会話の状態をメモリ上に保存しますが、
Lambdaはステートレスなので、ステートをS3に保存するためのライブラリを自作しました。
https://github.com/takaaki-s/botframework-s3storage


動作チェック用に、公式のexampleから２つピックアップして移植しています。

* simple-slack-bot
    * botbuilder-adapter-slack公式example
        * チャットの内容に反応してメッセージを表示、削除したりダイアログを表示する。
* store-bot
    * BotFramework公式のnodejs用example、45.state-management
        * 話しかけたユーザーの名前をステートに保存して、呼び出す。

公式のサンプルコードと見比べてもらうとわかるのですが、
変更しているのはExpressまわりだけで、Botのロジック部分はほとんどいじらずに動かせました。

```
注）
botbuilder-adapter-slackの公式サンプルはイベント判定でバグっているような箇所があるのと、
setTimeout関数がうまく動かないので、そこは手直ししています。
```

では、サンプルを動くところまでやっていきますので、
適当なディレクトリにgitからクローンしておきます。

```bash
git clone https://github.com/takaaki-s/serverless-botframework
```

# Slackの準備

まずは、Slack側でApp（Bot）を作成しての各種トークンを取得します。
https://api.slack.com/apps

必要になるのは、
Basic Information画面の`Signing Secret`と`Verification Token`、
OAuth & Permissions画面の`Bot User OAuth Access Token`です。

# デプロイの準備

`simple-slack-bot`を動かしてみますので、
ここからは`example/simple-slack-bot`ディレクトリ内で作業します。

`setting.yml.example`を`setting.yml`としてコピーしてSlackで取得したトークンを書き込みます。
これがServerlessFrameworkがデプロイ時に吐き出すCloudFormationテンプレートファイルに埋め込まれてデプロイされます。

ただ、こういった情報がファイルに埋め込まれるのはあまりよろしくないので、
実際に運用する際はSSMのParameterStoreやSecretsManagerを使うようにしましょう。


```yaml
# Basic InformationのSigning Secret
CLIENT_SIGNING_SECRET: ''
# OAuth & PermissionsのBot User OAuth Access Token
BOT_TOKEN: ''
# Basic InformationのVerification Token
VERIFICATION_TOKEN: ''
```

# デプロイ

npm、node.js、serverlessframeworkはインストールされていて、
ローカルにawsのクレデンシャルが置かれているのが前提です。

ローカルにクレデンシャルがおいてある状態とはaws configureの解説を参照するのがわかりやすいです。
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-configure.html

```bash
$ node -v
v11.6.0
$ npm -v
6.9.0
$ sls -v
1.45.1
```

まずは、node moduleをインストールします。

```bash
npm install
```

そして、おもむろにServerlessFrameworkのデプロイコマンドを叩きます。
お好みでオプションを使用してください。
ちなみに、自分の好みはデプロイ状況が見られる`-v`オプションです。

```bash
sls deploy -v
```

デプロイが終わるとターミナルにデプロイ情報が表示されます。
その中の`endpoints:`がApi Gatewayのエンドポイントになりますので、
先程SlackでAppを作った画面に戻り、そのエンドポイントをEvent Subscriptions画面のRequest URLと
Interactive Components画面のRequest URLに設定します。

それから、SlackのEvent Subscriptions画面のSubscribe to Bot EventsでBotが受信するイベントを設定します。
メンションを受信するなら`app_mention`
チャンネルのメッセージを受信するなら`message.channels`です。

# Slackで確認する

とりあえず、Slackに適当なチャンネルを作り、先程作ったBotをそのチャンネルに招待しましょう。

```
/invite @bot名
```

そして、`delete`や`update`等メッセージを流すとBotが反応してくれるはずです。
お疲れ様でした！

# 次回

これでユーザー起点のイベントは動かせるようになったので、
次回はBot側から発信（通知）する仕組みを作っていきます。
これができると、アラートやデプロイ状況の通知に使えるようになりますね。

# リンク

AWS Serverless Express
https://github.com/awslabs/aws-serverless-express

Microsoft BotFramework
https://github.com/Microsoft/botframework

botbuilder-adapter-slack
https://github.com/howdyai/botkit/tree/master/packages/botbuilder-adapter-slack

ServerlessFramework
https://serverless.com/