跳到主要內容

Discord Slash 指令

Discord 有項稱為斜線指令的新功能。它們允許您輸入 /,後面接指令名稱,以執行一些動作。例如,您可以輸入 /giphy cats (內建指令) 來取得一些貓咪 GIF。

Discord 斜線指令會在有人發出指令時,向 URL 發出要求。您不需要讓應用程式一直執行,斜線指令才能運作,這讓 Deno Deploy 成為建置此類指令的完美解決方案。

在這篇文章中,讓我們看看如何使用 Deno Deploy 建置一個 hello world 斜線指令。

步驟 1:在 Discord Developer Portal 上建立應用程式

  1. 前往 https://discord.com/developers/applications (如果需要,請使用您的 Discord 帳戶登入)。
  2. 按一下個人頭像左側的新增應用程式按鈕。
  3. 為您的應用程式命名,然後按一下建立
  4. 前往機器人區段,按一下新增機器人,最後按一下是的,執行!來確認。

這樣就完成了。已建立一個新的應用程式,它將包含我們的斜線指令。請勿關閉分頁,因為我們在開發過程中需要從此應用程式頁面取得資訊。

步驟 2:使用 Discord 應用程式註冊斜線指令

在我們撰寫程式碼之前,我們需要 curl 一個 Discord 端點,以便在我們的應用程式中註冊一個 Slash Command。

使用 機器人 區段中提供的代碼填入 BOT_TOKEN,並使用頁面 一般資訊 區段中提供的 ID 填入 CLIENT_ID,然後在你的終端機上執行指令。

BOT_TOKEN='replace_me_with_bot_token'
CLIENT_ID='replace_me_with_client_id'
curl -X POST \
-H 'Content-Type: application/json' \
-H "Authorization: Bot $BOT_TOKEN" \
-d '{"name":"hello","description":"Greet a person","options":[{"name":"name","description":"The name of the person","type":3,"required":true}]}' \
"https://discord.com/api/v8/applications/$CLIENT_ID/commands"

這將註冊一個名為 hello 的 Slash Command,它接受一個名為 name 的字串型別參數。

步驟 3:在 Deno Deploy 上建立並部署 hello world Slash Command

接下來,我們需要建立一個伺服器,以便在 Discord 使用某人的 slash command 提出 POST 要求時回應 Discord。

  1. 瀏覽至 https://dash.deno.com/new,然後按一下 遊樂場 卡片下的 播放

  2. 在下一頁的編輯器中,按一下頂端功能表上的 設定 圖示。在彈出的對話框中,選取 + 新增變數

  3. 輸入 DISCORD_PUBLIC_KEY 作為 KEY。VALUE 應為 Discord 應用程式頁面 一般資訊 區段中提供的公開金鑰。

  4. 複製並貼上以下程式碼至編輯器

    // Sift is a small routing library that abstracts away details like starting a
    // listener on a port, and provides a simple function (serve) that has an API
    // to invoke a function for a specific path.
    import {
    json,
    serve,
    validateRequest,
    } from "https://deno.land/x/sift@0.6.0/mod.ts";
    // TweetNaCl is a cryptography library that we use to verify requests
    // from Discord.
    import nacl from "https://cdn.skypack.dev/tweetnacl@v1.0.3?dts";

    // For all requests to "/" endpoint, we want to invoke home() handler.
    serve({
    "/": home,
    });

    // The main logic of the Discord Slash Command is defined in this function.
    async function home(request: Request) {
    // validateRequest() ensures that a request is of POST method and
    // has the following headers.
    const { error } = await validateRequest(request, {
    POST: {
    headers: ["X-Signature-Ed25519", "X-Signature-Timestamp"],
    },
    });
    if (error) {
    return json({ error: error.message }, { status: error.status });
    }

    // verifySignature() verifies if the request is coming from Discord.
    // When the request's signature is not valid, we return a 401 and this is
    // important as Discord sends invalid requests to test our verification.
    const { valid, body } = await verifySignature(request);
    if (!valid) {
    return json(
    { error: "Invalid request" },
    {
    status: 401,
    },
    );
    }

    const { type = 0, data = { options: [] } } = JSON.parse(body);
    // Discord performs Ping interactions to test our application.
    // Type 1 in a request implies a Ping interaction.
    if (type === 1) {
    return json({
    type: 1, // Type 1 in a response is a Pong interaction response type.
    });
    }

    // Type 2 in a request is an ApplicationCommand interaction.
    // It implies that a user has issued a command.
    if (type === 2) {
    const { value } = data.options.find((option) => option.name === "name");
    return json({
    // Type 4 responds with the below message retaining the user's
    // input at the top.
    type: 4,
    data: {
    content: `Hello, ${value}!`,
    },
    });
    }

    // We will return a bad request error as a valid Discord request
    // shouldn't reach here.
    return json({ error: "bad request" }, { status: 400 });
    }

    /** Verify whether the request is coming from Discord. */
    async function verifySignature(
    request: Request,
    ): Promise<{ valid: boolean; body: string }> {
    const PUBLIC_KEY = Deno.env.get("DISCORD_PUBLIC_KEY")!;
    // Discord sends these headers with every request.
    const signature = request.headers.get("X-Signature-Ed25519")!;
    const timestamp = request.headers.get("X-Signature-Timestamp")!;
    const body = await request.text();
    const valid = nacl.sign.detached.verify(
    new TextEncoder().encode(timestamp + body),
    hexToUint8Array(signature),
    hexToUint8Array(PUBLIC_KEY),
    );

    return { valid, body };
    }

    /** Converts a hexadecimal string to Uint8Array. */
    function hexToUint8Array(hex: string) {
    return new Uint8Array(
    hex.match(/.{1,2}/g)!.map((val) => parseInt(val, 16)),
    );
    }
  5. 按一下 儲存並部署 以部署伺服器

  6. 檔案部署後,請注意專案 URL。它將位於編輯器的右上角,並以 .deno.dev 結尾。

步驟 3:設定 Discord 應用程式,以使用我們的 URL 作為互動端點 URL

  1. 回到 Discord Developer Portal 上的應用程式 (Greeter) 頁面
  2. 填入 互動終端點網址 欄位為上方 Deno Deploy 專案網址,並按一下 儲存變更

應用程式現在已準備就緒。讓我們繼續進行下一部分來安裝它。

步驟 4:在 Discord 伺服器上安裝斜線指令

因此,要使用 hello 斜線指令,我們需要在 Discord 伺服器上安裝我們的 Greeter 應用程式。以下是步驟

  1. 前往 Discord 開發者入口網站上 Discord 應用程式頁面的 OAuth2 區段
  2. 選取 applications.commands 範圍,並按一下下方的 複製 按鈕。
  3. 現在貼上網址並在瀏覽器中開啟。選取您的伺服器,並按一下 授權

開啟 Discord,輸入 /hello Deno Deploy,並按下 Enter。輸出結果會類似於下方。

Hello, Deno Deploy!

恭喜您完成本教學課程!繼續前進,建立一些很棒的 Discord 斜線指令!並在 Deno Discord 伺服器deploy 頻道與我們分享。