常時稼動Discordボットを完全無料で作ってみた話

# Herokuの無料枠が無くなった今、どのホスティングサービスを使う？
Discordボットなど、[Heroku](https://jp.heroku.com/home)の無料枠を利用して公開していた方は多いと思います。
そんな中、2022年の8月25日にHeroku DynosやHeroku Postgresなどの無料プランの廃止が[アナウンス](https://blog.heroku.com/next-chapter)されました。
私は当時Discordボットなどを公開していなかったので影響はなかったのですが、動的サイトなどを公開したいと考えていたので、どうしようかと考えていました。いろいろ探したサービスなどあまりピンとこず、導入も大変そうだなぁと諦めていました。

それから月日が経ち、最近[Deno Deploy](https://deno.com/deploy)に出会いました。

# そもそもDeno Deployとは？
> Hassle-free platform for serverless JavaScript applications
引用: [Deno Deploy公式サイト](https://deno.com/deploy)

翻訳すると
**サーバーレスJavaScriptアプリケーションのための手間いらずのプラットフォーム**
となります。

つまり、JavaScriptアプリケーションを簡単に公開できるプラットフォームとなっています。

# DenoでDiscordボットの作成
DenoでDiscordのボットを作成するために、今回は[Discordeno](https://discordeno.js.org/)を使っていきます。

## 開発環境
開発環境は以下のとおりです。

<table>
  <caption>開発環境</caption>
  <thead>
    <tr>
      <th>名前</th><th>バージョン</th>
    </tr>
  </thead>
  <tr>
    <td>Deno</td><td>2.0.2</td>
  </tr>
  <tr>
    <td>TypeScript</td><td>5.6.2</td>
  </tr>
  <tr>
      <td>Discordeno</td><td>18.0.1</td>
  </tr>
</table>

## Discordボットの準備
実際にコードを書いていく前に、ボットの準備しましょう。

[Discord Developer Portal](https://discord.com/developers/applications)にアクセスします。
アクセスしたら、画面右上にあるNew Applicationを押してボットの準備をしましょう。
![Discord Developer Portalトップ画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/1d724e0a-df5e-db2c-be65-842a6f1d03e4.png)
そうしたら、出てきたフォームに名前を入力し、
> By clicking Create, you agree...

にチェックを入れて[利用規約](https://support-dev.discord.com/hc/articles/8562894815383-Discord-Developer-Terms-of-Service)と[開発者ポリシー](https://support-dev.discord.com/hc/articles/8563934450327-Discord-Developer-Policy)に同意して、
Createをクリックし、ボットを作成しましょう！

### Discordボットのトークンの取得
ボットの作成ができたら、左のサイドメニューからBotを選択し、Reset Tokenを押してください。

![Discord Developer Portal内のBot画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/1f4c76e9-87fd-2a41-4ad6-8078645481dc.png)

> Reset Bot's Token?
> Your bot will stop working until you update the token in your bot's code.

とでてきますが、本当にリセットするの？と言われているだけなので、**Yes, do it!** を押しましょう。
そしたらトークンが表示され、コピーできるのでコピーしましょう。

:::note warn
ボットのトークンは第三者に知られないようしてください。
Botが乗っ取られます。
:::

また、この画面を更新するとトークンが見えなくなってしまうので、どこかにメモしていてください。

![Discord Developer Portalからトークンの取得](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/995d088f-b04e-2cfd-25ab-743368a8785e.png)

同じ画面で少し下に下がると、ボットの権限を設定する項目があるので、必要に応じて設定しましょう。
今回は管理者権限、Administratorを設定しています。
![Discordボットの権限設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/0867e864-43e6-b83c-e10d-938ef8725756.png)

### Discordボットをサーバーに招待しよう！
はじめに、招待リンクの準備をしましょう！
左のメニューからInstallatioを選択しGuild Installの項目まで移動してください。
そしたら、**SCOPES**に`bot`を追加し、PERMISSIONSには`Administrator`[Bot Permission](#discordボットのトークンの取得)と同じものに設定し、Saveしましょう！

![Guild Install画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/0943d1ee-8f46-cb04-43af-072d54597bfe.png)

次にInstall Linkをコピーし、招待します。
![招待リンク](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/76f06b0c-30fb-a8bc-51e7-a2d977fc00cd.png)

サーバーを選んで認証と押すことで招待が完了です！
![Discordボット 招待画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/972811e6-bde1-da29-08c4-e86d18316c52.png)

### サンプルコードの実行
以下のリポジトリのコードをダウンロードし、実行してみましょう！

https://github.com/23tas9/Discordeno-Sample/tree/first-sample

ダウンロードしたコードで、先ほど取得したトークンを設定しましょう。
`.env`内の、`<YOUR_TOKEN_HERE>`の箇所を取得したトークンに設定してください。
```.env
BOT_TOKEN = <YOUR_TOKEN_HERE>
```

そしたら、次のコマンド

```
deno task start
```

で実行してください。
ボットがオンラインになっていたら成功です！

![ボットの画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/9e2223e6-f9cf-6d23-437c-66fc5798542d.png)

### 簡単なスラッシュコマンドの実装
こちらもサンプルを用意しております。

https://github.com/23tas9/Discordeno-Sample/tree/second-sample

実装した`hello_world`コマンドを実行すると、こんにちはと表示されるはずです。

![コマンドの実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/b43b3051-bf41-4afb-f991-6e117813ec0d.png)

## Deno Deployにデプロイ

まずデプロイするために、Discordボットのコードを[Github](https://github.com)リポジトリにアップロードしてください。
次に、[Deno Deploy](https://dash.deno.com/account/overview)にアクセスし、**New Project**から先ほどアップロードしたリポジトリを選択します。
![Deno Deploy プロジェクト作成画面 1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/93520a5e-193c-8baa-f538-012066a77438.png)

次に、少し下のほうにある、**Project Configuration**から
`Project Name`からプロジェクト名を設定し、
`Entrypoint`を`main.ts`に設定してください。
(ボットの起動を`index.ts`などに設定している方はそちらにしてください)

![Deno Deploy プロジェクト作成画面 2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/b265d0b1-1d97-42aa-7606-a272359e9ec5.png)


それらが済みましたら、**Deploy Project**でプロジェクトのデプロイが完了します！

## BOT_TOKENの設定
そのままデプロイすると、以下のようにエラーが発生します。

![Deno Deploy Build Logs](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/b4882ce3-71fe-084c-edeb-d6665f84691d.png)

これは`main.ts`の11行目、
```ts:main.ts
const BotToken: string = Deno.env.get("BOT_TOKEN")!;
```
の部分で取得している環境変数の`BOT_TOKEN`がDeno Deployでは設定されていないからです。
この画面のままですと、環境変数を設定できないので、[Account Overview](https://dash.deno.com/account/overview)に戻り当該のプロジェクトを選択します。
そうしてでてきた画面の右上、**Settings**を選択してください。

![プロジェクトの画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/d4c67195-079f-364d-3c2b-b86462a56aaa.png)

少し下にスクロールすると、**Environment Variables**があるので、**Add Variable**を押し、
`Key`に`BOT_TOKEN`、`VALUE`には`.env`に設定していた自身のトークンを設定してください。
その後、**Save (1 new)** を押して環境変数の設定は完了です！
![スクリーンショット 2024-10-21 15.23.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/cb2e5b16-e18e-e60a-6abb-a6d8d20eda7c.png)

デプロイが成功すると、Botがオンラインになるのを確認してください！

![ボットの画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/9e2223e6-f9cf-6d23-437c-66fc5798542d.png)

## Discordボットの常時起動
Deno Deployは、双方向通信を維持できないため、5分ほどでボットがオフラインになります。
なので、ボットがオフラインになるまでに継続的にリクエストを送り続けます。

### Deno Cronの使用

そもそも[Deno Cron](https://docs.deno.com/deploy/kv/manual/cron/)は、スケジュールされたジョブを簡単に作成できるものです。

`main.ts`の一番下の行に次のコードを追加します。

```ts:main.ts
Deno.cron("Continuous Request", "*/2 * * * *", () => {
    console.log("running...");
});
```

このコードは2分毎にコンソールに`running...`と出力するだけのものですが、これを実行するだけで、Discordボットはオフラインにならなくなります。
コードを追加したら、リポジトリを更新しておいてください。
更新すると、プロジェクトの**Latest Deployments**に最新の状態に更新されているはずです。

![Latest Deployments](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/703604/1e66df51-c6a1-18f4-43fc-296509ea70ee.png)

おめでとうございます！これで、Discordボットの常時稼働ができました！

(今の所2分毎でオフラインになりませんが、もう少し間隔を空けることも可能かもしれません。)

# 参考にさせていただいた記事

https://qiita.com/peko-thunder/items/53537e2edec8aab1ec58