🐿️

DiscordのSlash commands返信にて、実行したユーザーにだけ見せる「これらはあなただけに表示されています」を試す、他

2023/08/12に公開

はじめに

  • なんらかの決済サービスで有料会員になった人だけ見られるDiscordチャンネル
  • Discordサーバーのメンバーだけ見られる外部コンテンツ

決済状況とロールの連動や外部アカウントとDiscordアカウントの連携などを、自動でできたら便利だろうなと思い、試作品を作ってみることにしました。

今回はその仕組みの一部、スラッシュコマンドを実行したら連携用の外部URLが本人にだけ見える状態で送信される仕組みを作ってみようと思います。

外部サービスと連携するためにDiscordから遷移するURLには、紐付け用の文字列を含む予定です。これを第三者に見られないようにやり取りするのが今回の目的となります。

前提

開発言語はNode.jsになります。
discord.jsは使っていません。
Discord自体の説明やapplicationの作成方法については説明しません。

Getting Started - Building your first Discord app
あたりを事前にご一読いただくと良いかと思います。

Ephemeral Messages

「これらはあなただけに表示されています」
この機能の名称は"Ephemeral Messages"と言うそうです。

Ephemeral Messages FAQ

スラッシュコマンドで使える機能で、DMとは異なります。

  • 受信した本人だけが読める。
  • 一定時間で消える
  • アプリやブラウザの再起動(再読み込み)で消える
  • 受信した人が消すことができる

あたりが特徴です。
DMも検討しましたが、DMのブロックや件数制限など考えるとこちらの機能を選ぶのが得策かと思います。

それでは実際に試作品を作ってみましょう。

コマンド作成

コマンド作成スクリプトは公式のサンプルコードを利用します。
公式 example

今回利用する設定箇所だけ掲載しておきます。

const SUBSCRIBE_COMMAND = {
  name: "subscribe",
  description: "決済・外部サービス連携",
  type: 1,
  options: [
    {
      name: "service",
      type: 3,
      required: true,
      description: "決済・連携サービスを選択してください",
      choices: [
        { name: "stripe", value: "stripe" },
        { name: "wix", value: "wix" },
        { name: "shopify", value: "shopify" },
      ],
    },
  ],
};

const ALL_COMMANDS = [
  //既存コマンドは省略
  SUBSCRIBE_COMMAND,
];

InstallGlobalCommands(DISCORD_APP_ID, ALL_COMMANDS);

連携サービスはいくつか試す予定なので、引数で選択できるようにしました。

コマンドの受信から返信の流れ

ここは人によって実装が異なる点かもしれませんが、コマンドを受け付けたら一時的な返信をします。
(Interaction Callback Type = DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE = 5)
※ Discordでは3秒以内にレスポンスを返さないといけないためです。受信後別のLambdaを非同期的に呼び出し、そちらに本処理を委ねてレスポンスだけ返します。

Interaction Callback Type

その後、ユーザーを外部サービスと連携するためのURLを、Followup Messagesで送信します。
Followup Messagesを送るためには追加のtokenが必要で、これはスラッシュコマンドが送られてきた際にリクエストに含まれています。

Followup Messages
Create Followup Message

※DEFERREDでレスポンス時間が猶予されても、Followupメッセージはスラッシュコマンド実行後15分以内です。またEphemeral Messages自体も永久に保持されるわけではない点注意しましょう。

Interaction tokens are valid for 15 minutes and can be used to send followup messages but you must send an initial response within 3 seconds of receiving the event. If the 3 second deadline is exceeded, the token will be invalidated.

flags、ビット演算

通常の返信ではメッセージは第三者からも見られてしまいます。
そのため、Ephemeral Messagesを有効にするためflagsというパラメーターを使います。
この時注意が必要なのは、すでに書いたように仮返信と本返信の2回メッセージを返しますが、本返信だけEphemeral Messagesを有効にしようとしてもできません。必ず仮返信を含めた2回ともEphemeral Messagesを有効にしなければいけません。

Interaction Callback Data Structure - Messages

Message Flags

上記の仕様の通り、flagsはビット演算になっています。
(運用時、DBの値を直接見た時とかに直感的にわからず手間取るので、私はあまり好きではないです。。。)

他の項目を指定しなければ単純に

1 << 6

で  "64"を指定しまいます。

他に利用している項目があれば
(というより事前に想定して処理を作っておくべきですが)
愚直な書き方ですが、、、例えば以下のようにします。

let flags = 0;
const EPHEMERAL_FLAG = 1 << 6;
const HOGE_FLAG = 1 << 5;
const FUGA_FLAG = 1 << 4;

if (ephemeral) {
  flags |= EPHEMERAL_FLAG;
}

if (hoge) {
  flags |= HOGE_FLAG;
}
if (fuga) {
  flags |= FUGA_FLAG;
}

※私は有効無効の2択で済ませて省いてますが。

メッセージの内容

本返信(Followup Messages)は見た目を少し工夫したいと思います。
今回はMidjourneyを参考に、テキストメッセージに加え、ボタンを表示するためにcomponentsを利用したいと思います。

表示したい内容は以下になります。

  • メッセージ
  • 注意事項
    • 10分程度でリンクが無効になること。(手続き完了メッセージをtoken有効期限内に送信したいため)
    • 第三者に見られないように注意書き。
  • リンクボタン

リンクボタンは以下に従って作成します。

Message Components

[
  {
    type: 2,
    label: "手続きを開始",
    style: 5,
    url: url,
  },
],

componentsは配列で複数の要素を格納することができます。
今回はボタン1つなので1つだけ要素を加えます。

typeはボタン(2)を選択します。

Component Types

labelはボタンのラベルテキスト
styleは以下からLinkを選択します。

Button Styles

URLは遷移先のURLを指定します。
今回は実装しませんが、ここで連携処理対象を識別するためのIDを作成し、自前のDBに保存する予定です。
Discordのサーバー、ユーザー、連携先サービス、有効期限、処理ステータスなどですかね。

実行結果

スラッシュコマンドを実行した結果は以下のようになります。

ボタンを押すと

まとめ

今回は

  • スラッシュコマンドを実行時に、本人にだけ見えるメッセージの返信
  • 返信メッセージにcomponentsを使い、リンクボタンを表示
    を試しました。

今後の記事で続き、Discordから外部サービスとの接続を試してみたいと思っています。

Discussion