Azure Functionsを使ってチーム分けDiscord Botを作ってみた
2023/08/19
やったこと
Azure Functionsをバックエンドのサービスとして、チーム分けをするDiscord Botを作ってみました。 /grouping {グループ数}
というフォーマットでコマンドを入力することで、チーム分け対象のメンバーを選択するセレクトメニューが表示され、選択が完了するとBotはチーム分けの結果を投稿してくれます。
GitHubリポジトリはこちらです。
背景
友人とオンラインでゲームで遊ぶときにチーム分けしたいことがあります。Web上でグループ分けしてくれるようなサービスやアプリはググれば見つかるのですが、毎回メンバーの名前を入力したり、そもそもググるのが面倒です。Discord上でサクッとできれば嬉しいなと思います。既存のDiscordアプリケーションや、Botにチーム分けしてくれる機能を持つものもあるかと思いますが、管理しているDiscordサーバーに誰が作ったかわからないアプリやBotを入れるのは個人的に抵抗があります。特にインストール時にメッセージのRead権限などを与える必要がある場合には一層慎重になります。なるべく自分の目の届く範囲で管理したいので、自分でDiscord Botを作ってみることにしました。
技術選定
DiscordはWeb APIを公開しており、公式チュートリアルではNode.jsを使ったサンプルを公開しています。素直にランタイムとしてはNode.jsを使って開発することにしました。
Node.jsを動かすコンピュータリソースには、なるべくコストがかからないものを利用したいと考えていました。個人的にいくつかのサーバーに導入して使うだけなので、そんなに頻繁にリクエストを裁く必要がないことから、常時サーバーを動かすのは非効率的です。サーバーレス・コンピューティングを採用するのが筋が良さそうです。選択肢としてはAWS lambda, Microsoft AzureのAzure Functions, GCPのCloud Functinsがあります。個人開発なので、超過分が自動で課金されるAWSはちょっと抵抗があったので、AzureかGCPに絞りました。中でもあんまり使ったことがないMicrosoft Azureを試してみたいことからAzure Functionsを使ってみることにしました。
厳密にはAzure Functionsで動くコードや構成ファイルがストレージアカウントのAzure Filesに保存され、ストレージアカウントは無料枠の対象外であるため若干のコストがかかります。Azure FunctionsでシンプルなAPIを作る場合はそんなにコストはかからないので、登録時に与えられるクレジットのおかげで賄えます。
- 参考
お勉強
Discord AppもMicrosoft Azureもよくわからないので色々お勉強しました。多分どちらもチュートリアル的な記事をこなすと大体要領がわかるので、まずはそれに取り組んで、わからないことはドキュメントで補完するのがいいと思います。
- Discord App
- Azure Functions
アプリやアカウントなどの登録作業
Discord
- Discordのアカウントにログインする。
- https://discord.com/developers/applications からNewアプリケーションを作成する。
- チュートリアルに倣っていろいろ設定する。
Microsoft Azure
- Microsoftアカウントでサインインする。
- Microsoftアカウントを使ってMicrosoft Azureにサインアップする。
- Microsoft Azureを使ったことがない場合は無料アカウントからスタート。
- 無料アカウントでもカード情報の登録が必要。従量課金制サブスクリプションにアップグレードしない限り料金が発生することはないので安心。
- 詳細はこちら: Azure の無料アカウントを今すぐ作成する | Microsoft Azure
実装
Discord Appのチュートリアルコードをベースに作ります。しかし、チュートリアルのAPIはExpress.jsで実装されているため、そのままではAzure Functionsのランタイムでは動きません。Azure Functionsのお作法に倣って、書き換えていく必要があります。
Discord Appの実装での工夫ポイントは、セレクトボックスでユーザーを選択し、結果を返してもらったあと、セレクトボックスを操作できないように無効化する処理を入れたところです。操作できないようにしておかないと、何度も同じセレクトボックスを操作される可能性があるためです。当該箇所は以下のURLです。
あとからセレクトメニューの有効・無効を上書きするために、メッセージを編集するためのDiscordのEdit Message APIを呼び出します。エンドポイントにChannelのIDやMessageのIDを指定する必要がありますが、Interactionオブジェクトの中に、channel.id, message.idが入っているのでそれを使います。
デプロイ
GitHub Actionsを使ってエレガントに継続的デプロイをやりたかったのですが、かなり時間をかけて何回トライしても失敗するので諦めました。
かわりにVisual Studio CodeのAzure Functions拡張機能でぽちぽち手動デプロイしました。手順としては数クリックで、時間も1分かからないくらいで反映までできてしまうので全然困っていないです。やりかたは以下を参考にしています。
参照したドキュメントなど
Discord
チュートリアル
- https://discord.com/developers/docs/getting-started
- ここのページを読み進めることでDiscord Botの作り方を一通り理解することができます。まずはこれに取り組んでみるのがおすすめです。
- サンプルコードのリポジトリ: https://github.com/discord/discord-example-app
Interaction
Discordのスラッシュコマンドも、メッセージ中のUIに対するユーザーの入力も、Interactionという概念でサーバー側に届きます。処理の中心はInteractionになるので、中身を理解しておくことが重要っぽいです。
- Slash Command Interaction Example
- https://discord.com/developers/docs/interactions/application-commands#slash-commands-example-interaction
- Slashコマンドでアプリに送られてくるInteractionの例。
- Interaction object structure
- https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object
- ユーザーがアプリに働きかけるとき、Interactionオブジェクトがリクエストボディとして返ってくる。そのオブジェクトの構造が書かれている。
- Interaction data structure
- https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-data
- InteractionTypeがPINGのInteraction以外には、
data
という名のフィールドが存在する。 - InteractionTypeによってこの
data
の構造は異なる。
- Interaction callback type
- https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type
- ユーザーのコマンドに対するインタラクションのタイプがdiscord-interactinosというパッケージで提供されている。どんなタイプが定義されているかが書かれたセクション。
- Interaction Callback Data Structure
- https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-data-structure
- Interaction Callbackで返却する
data
の構造が書かれたセクション。
- Message Components
- https://discord.com/developers/docs/interactions/message-components
- Message Components。通称
components
と呼ぶ。 - アプリやボットがユーザーに送るメッセージの中で使えるインタラクティブな要素。
Microsoft Azure
Azure Functions
- Visual Studio Code を使用して JavaScript 関数を作成する - Azure Functions | Microsoft Learn
- まずは関数アプリの作り方の流れを確認。
- Azure Functions のドキュメント | Microsoft Learn
- Azure Functionsに関する公式ドキュメントのトップ。
- Azure Functions の開発に関するガイダンス | Microsoft Learn
- 開発言語によらない共通する内容が書いてある。
- Azure Functions 用 Node.js 開発者向けリファレンス | Microsoft Learn
- 公式トレーニング
- Azure Functions の概要 - Training | Microsoft Learn
- Azure Functionsとはなんぞや?がわかる資料。
- Azure Functions の開発 - Training | Microsoft Learn
- Azure Functionsの設定やデプロイを理解するチュートリアル。
- Node.js Express API をサーバーレス Azure Functions API にリファクタリングする - Training | Microsoft Learn
- Node.jsアプリをAzure Functions APIに書き換えるためのチュートリアル。
- Azure Functions の概要 - Training | Microsoft Learn
有志のブログ
- Azure FunctionsでサーバーレスDiscord Botを作る | cloud.config Tech Blog
- Discord Slash CommandのInteractionをAzure Functionsにデプロイしてみる
蛇足
Discordのチュートリアルコードのタイポを見つけたので修正のプルリクを送ったらマージされました。やったぜ。
感想
作りたいものは作れました。 Discord AppもAzure Functionsもまだあんまり使いこなせるほどは理解できていないので、次何か作るときに本腰を入れてドキュメントを読み込みたい。