discord.py製のBotを運用していたのですが、Botを置いていたHerokuの無料枠が消えたため、Cloud Functionsに引っ越し、というかほぼ置き換えすることにしました。インターネット上に見当たらなかったのでそのメモです。
参考までに、Cloud Functionsの料金は200万リクエスト(≒コマンド呼び出し回数)まで無料です。
【Firebase】Cloud Functions チュートリアル
こちらの冒頭無料部分を参考に環境構築を行います。(丸投げ)
$ firebase init
https://zenn.dev/drumath2237/articles/112fd0bfa7ea4f836195#applicationの作成
こちらの記事のDiscord Slash Commandを作成する~Slash Commandの登録までを進めます。(丸投げ)
function/index.ts
が生成されていると思うのでこれを弄っていきます。
とりあえず $ npm install discord-interactions
をします。
Slash Commandのエンドポイントが不正でないか証明するために、いくつか検証プロセスが必要になります。わざと不正なリクエストが飛んできたりします。
具体的には
https://discord.com/developers/docs/interactions/receiving-and-responding#security-and-authorization
https://discord.com/developers/docs/interactions/receiving-and-responding#receiving-an-interaction
それを踏まえたのが以下のコードになります。今回は、コマンドに関係なく、hi! 名前と応答するよう実装します。
import * as functions from "firebase-functions";
import {
verifyKey,
InteractionType,
InteractionResponseType,
} from "discord-interactions";
// Start writing Firebase Functions
// https://firebase.google.com/docs/functions/typescript
export const discordBot = functions.https.onRequest((request, response) => {
// 検証:不正な署名を弾く
const sig = request.headers["x-signature-ed25519"];
const time = request.headers["x-signature-timestamp"];
if (typeof sig !== "string" || typeof time !== "string") {
response.status(401).send("");
return;
}
const CLIENT_PUBLIC_KEY = process.env.CLIENT_PUBLIC_KEY ?? "";
const isValid = verifyKey(request.rawBody, sig, time, CLIENT_PUBLIC_KEY);
if (!isValid) {
response.status(401).send("");
return;
}
const interaction = request.body;
if (!interaction) return;
if (interaction.type === InteractionType.PING) {
// 検証:PINGが送信された場合はPONGを返す
response.send({
type: InteractionResponseType.PONG,
});
return;
} else {
// コマンド:挨拶する
response
.status(200)
.type("application/json")
.send({
type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
data: {
content: `hi! ${interaction.member.user.username}`,
},
});
}
});
それから、Discord ApplicationのCLIENT_PUBLIC_KEY
を.env
ファイルに置きます。
具体的にはfunctions/.env
を作成し、 Discord Developer Portalの アプリケーションの General Infomationの PUBLIC KEY を以下の様にコピペします。
CLIENT_PUBLIC_KEY=0123456789abcdef0123456789abcdef
$ firebase deploy
します。
その後、firebaseのプロジェクトページからデプロイされた関数の詳細を確認します。
リクエストURLを控え、
Discord Developer Portalの アプリケーションの General Infomationの INTERACTION ENDPOINT に先程のリクエストURLを記述します。
お疲れ様でした。適当なサーバーでコマンドを叩いて確認してみてください。
interaction.data.name
でコマンド名が取れます。コマンドの判別はidでも良いでしょう。
CloudFunctionsのデバッグについては以下が参考になります。
https://qiita.com/seya/items/c37207cd65ec914692ba
DiscordBotの場合はローカルでリクエストを作るのが大変なので、公式チュートリアルも推奨しているngrokでどうにかするとよいでしょう。
おわり