discord.pyとherokuでDiscordBot

# はじめに
私は社会人1年目のプログラマです
弊社有志主催の開発合宿に参加したので、その際使った技術やハマりポイントをアウトプットしたいと思い、筆をとりました。
乱文乱筆ではありますが、お付き合いいただければ幸いです。

※あまりに内輪ネタが激しいため、実際の動作の様子はありません。ご了承ください。

# 環境
Windows 10
Python 3.6.4
discord.py 0.16.13

# Discordとは
<img src="https://qiita-image-store.s3.amazonaws.com/0/226689/ad237962-2d63-caf1-82cd-a674898367d8.png" width="100" height="100">
Discordは、ゲーマー版slackのようなテキスト＆ボイスチャットのサービスです
無料でログ無制限、ボイスチャンネルも無制限、画面共有もお手軽と大変便利なサービスで、私もゲーム仲間とボイスチャットしながらスプラトゥーンをしています。
slackと同様に、チャットボットも作れます。
そこで今回は、ゲーム仲間の迷言と~~悪口雑言、~~スプラトゥーン2のブキをランダムで一つ返信してくれるボットを作り公開することを目標としました。

# Bot用アカウント作成
こちらの記事を参考にBot用アカウントを作成し、仲間内のサーバに招待しました
- [Discord用のBotアカウントの用意 - Qiita](https://qiita.com/oosawa/items/e5b01e88a209d9087432)

この際、トークンを忘れずに保存しておきます。
# discord.py
discordBot用ラッパモジュールです。
普段使ってるanacondaにはリポジトリがなかったので、pipからインストールしました。

# Botを動かしてみる
Botへメンション+特定のキーワードで迷言機能、ブキランダム機能を実装したコードがこちらになります。

```python:mainBody.py
import discord
import asyncio
import random
import sys
import os
import botFunction.functions as f

client = discord.Client()

func_list = {
    '名言': f.random_meigen,
    '迷言': f.random_meigen,
    '武器': f.random_splat_buki,
    'ブキ': f.random_splat_buki,
    'help': f.help,
    'ヘルプ': f.help
}


@client.event
async def on_ready():
    '''
    起動時に呼ばれるメソッド
    '''
    print('-----Logged in info-----')
    print(client.user.name)
    print(client.user.id)
    print('------------------------')


@client.event
async def on_message(message):
    '''
    特定のメッセージを受け取って処理する\n
    今はメンションを送るとランダムに名言を返す
    '''
    try:
        if client.user.id in message.content:
            for k in func_list:
                if k in str(message.content):
                    await func_list[k](client, message)
                    break
            else:
                await f.random_reply(client, message)
    except:
        print(sys.exc_info())

client.run(os.environ.get('ENV_VAR_DISCORD_ID'))
```

async関数に`@client.event`デコレータをつけてイベントループに登録します。
`on_ready`関数ではBotがログインに成功したとき、`on_message`関数はなにかしらメッセージが送信されたときのイベントです。


```python
if client.user.id in message.content:
```
このif文でBotに対するメンションかどうかを判定します。
`client.user.id`がBotのユーザID、`message.content`がメッセージ本文に相当します。
属性や関数はAPIリファレンスに使い方が書いてあったので、それを参考にしました。
[API Reference — discord.py 0.16.12 documentation](http://discordpy.readthedocs.io/en/latest/api.html)

run メソッドの引数にBot作成時にコピーしたトークンを引数に渡します。
（ここではherokuの環境変数に設定しています)



一通り書いたらローカルで実行してみます。`on_ready`の中身がコンソールに出力されれば成功です。

# herokuにデプロイ
一通り書いてローカルで動作を確認したら、herokuにpushしてデプロイします。
herokuのアカウントを作成し[heroku toolbelt](https://devcenter.heroku.com/articles/heroku-cli)をインストールして、以下のコマンドでherokuの準備をします。

```bash
heroku login
```

表示に沿って登録したアドレスとパスワードを入力するとSSHキーが生成されます。

つづいてherokuに新しいアプリを登録します。

```bash
heroku create {アプリ名}
```

アプリを登録した時点でherokuのリポジトリがローカルに登録されます。
あとは`.gitignore`をいくつか設定し、`requirements.txt`に依存関係にあるモジュールを指定します。
今回はdiscord.pyだけです。

それともう一つ、`Procfile`（拡張子なし）というファイルを用意します
（[procfile · herokaijp/devcenter Wiki](https://github.com/herokaijp/devcenter/wiki/procfile)）

ざっくり説明すると、Procfileに指定した名前のコマンドで実行するよ！という感じですかね。
正直理解不足な部分ではあるのですが、今回はこのように記述したらうまく動きました。

```:Procfile
bot: python mainBody.py
```

あとはこれらのファイルと書いたコードをherokuにpushするだけです。
勝手にビルドしてくれるので、herokuのダッシュボードから起動すれば動き始めます。

herokuはGitHubと連携する機能があり、ダッシュボードから連携するリポジトリを指定して有効化すると、指定したブランチにコードがマージされると自動でリビルドします。
GitHubで管理したい場合はherokuでなくGitHubにpushすることになります。


## herokuの料金プラン
今回は無料プランを使いました。
クレジットカード登録なしで月に550時間、登録すれば月1000時間プロセスを走らせることができます。
アドオンやpostgreSQLもクレジットカード登録だけで無料（制限つき）で利用できるので、登録しておいて損はないと思います。

herokuの無料プランは30分間操作がなければ自動でスリープモードに入るという仕様になっています。
discord.py はイベントループが回り続けているので自動スリープにはなりませんが、他のサービスを使う場合や月稼働時間の制限には注意する必要がありそうです。


# おわりに
ここまでの工程の総作業時間は10時間ほどでした。
デプロイにかかった時間も（初回にProcfileの設定に手こずったことを除けば）非常に短く、一度動き始めればpushするだけでデプロイできる手軽さは大変気に入っています。
今後はdiscord.pyのリファレンスをもう少し読み込んで、対話式の機能を追加したいと思っています。