セルフホストサーバー
顧客は自前のハードウェアで GameVox を運用でき、あなたのボットもそこで動きます。クラウド API が Discord 形式の REST とゲートウェイイベントを顧客のコントロールチャンネル経由で転送し、セルフホスト側がローカルのデータベースに対して実行し、同じ経路で応答が戻ります。ほとんどのエンドポイントは透過的です。未対応のものは以下のとおりです。
仕組み
ボットが GET /guilds/{id} や POST /channels/{id}/messages を呼ぶと、クラウドのボット API が対象サーバーのティアを確認します。セルフホストであれば、リクエスト(メソッド、パス、クエリ、ボディ、bot_user_id)をシリアライズし、顧客のサーバーが常時開いているコントロールチャンネルの WebSocket に送ります。セルフホストのプロセスが自身の SQLite データベースに対して同等のハンドラーを実行し、応答のエンベロープを返すので、それをそのままボットへ書き戻します。
転送はボット API のレイヤーで行われるため、ライブラリはそれを意識しません。トークンもゲートウェイ URL も SDK も同じです。ギルドがクラウドでもセルフホストでも、ボットは同じ gateway.gamevox.com に接続し、同じ bot-api.gamevox.com を呼びます。
レイテンシ
往復時間は顧客の WAN 回線と SQLite のクエリ時間に依存し、通常はクラウド呼び出しに 30〜300 ms 上乗せされます。エンドツーエンドで 12 秒の期限を設けています。セルフホストのサーバーが応答しなくなった場合(オフライン、アップグレード中、回線断など)、期限から 1 秒以内にボットへ 504 Gateway Timeout が返ります。
動作するもの
以下はすべて、セルフホストサーバーのローカルデータに対して実行され、クラウドと同じ応答形式になります。
- メッセージ: 一覧、取得、送信、編集、削除、一括削除。
- リアクション: 追加、自分の削除、他ユーザーの削除、全削除、絵文字ごとの全削除、ユーザー一覧。
- ピン留め: 追加、解除、一覧。
- 入力中表示:
POST /channels/{id}/typing。 - チャンネル: 取得、更新、削除、一覧、作成、並べ替え。
- サーバー(ギルド): 取得、更新(名前と説明)。
- メンバー: 一覧、検索、
@me、取得、更新、ニックネーム変更、キック、ロールの追加と削除。 - BAN: 一覧、取得、追加、解除。
- ロール: 一覧、取得、作成、更新、並べ替え、削除、およびロール権限。
- 絵文字: 一覧、取得(サーバー所有のもの)。
- サウンドボード: 一覧、取得(サーバー所有のもの)。
- 監査ログ:
GET /guilds/{id}/audit-logs。ボットに関係するエントリのみ。 - バニティ URL: GET(常に空の形式)。
- ボイス状態: GET(SFU からのライブ情報)、PATCH(ミュート、移動、切断)。
- Webhook: 完全な CRUD と実行。レコードはクラウド側に保存され、生成されたメッセージはボットの送信と同じ転送経路でセルフホストのチャンネルに書き込まれるため、チャンネルのバッジも正しく更新されます。
501 を返すもの(受け付けるが未実装)
deaf付きのPATCH .../voice-states/*。サーバー側でのスピーカーミュートは、現時点のセルフホスト SFU にはありません。ミュート、移動(channel_id)、切断(channel_id: null)はいずれも動作します。PUT .../channels/{id}/permissions/{oid}。セルフホストはチャンネル単位の上書きではなくグループ単位の権限を使うため、Discord の上書きを適用する対象がありません。DELETEは204を返します(存在しない上書きの削除は何もしません)。PATCH .../guilds/{id}/vanity-url。セルフホストサーバーにバニティ URL はありません。
404 を返すもの(セルフホストにルーティングされない)
これらのエンドポイントは、クラウド基盤にしか存在しないリソースを扱います。ボットに必要な場合は、クラウドのギルドで試してください。
- すべての
/interactions/*、フォローアップ、元の応答のエンドポイント。 - アプリケーションコマンドのすべての CRUD(
/applications/{id}/commandsとギルド版)。 - DM チャンネルの作成(
POST /users/@me/channels)。 - サーバーをまたぐユーザー検索(
GET /users/{id}、GET /users/by-name/{name})。 GET /users/@me/guilds。
ゲートウェイイベント
セルフホストのサーバーは、クラウドが発行するイベントの一部を配信します。ボットは同じゲートウェイセッションで受け取り、購読モデルも変わりません。
現在セルフホストから発行されるもの:
MESSAGE_CREATE,MESSAGE_UPDATE,MESSAGE_DELETE,MESSAGE_DELETE_BULKMESSAGE_REACTION_ADD,MESSAGE_REACTION_REMOVECHANNEL_CREATE,CHANNEL_UPDATE,CHANNEL_DELETECHANNEL_PINS_UPDATEGUILD_UPDATE(名前 / 説明の変更)GUILD_MEMBER_ADD,GUILD_MEMBER_REMOVE,GUILD_MEMBER_UPDATE(ニックネームまたはロールの変更)GUILD_BAN_ADD,GUILD_BAN_REMOVEGUILD_ROLE_CREATE,GUILD_ROLE_UPDATE,GUILD_ROLE_DELETE(サーバーの権限モデルが変わったときに発行)TYPING_STARTVOICE_STATE_UPDATE(参加、退出、自分/サーバーによるミュート、スピーカーミュート)
セルフホストからまだ発行されないもの:
PRESENCE_UPDATE。セルフホスト側に新しいプレゼンス配信の仕組みが必要です。- DM のメッセージイベント。セルフホストにはサーバーをまたぐ DM がありません。
INTERACTION_CREATE。セルフホストでのコマンド呼び出しはまだ転送されません。
既知の差異
- 自分によるミュートとサーバーによるミュート: セルフホストの SFU は、Discord のように
self_muteとmuteを分けず、参加者ごとに 1 つのミュートビットだけを持ちます。VOICE_STATE_UPDATEは同じ値を両方のフィールドに入れるため、サーバーミュートの解除が、自分のミュートも解除したように見えることがあります。どちらか一方のフィールドだけを読むボットは問題ありませんが、両方を混ぜて状態管理するボットは、モデレーション操作にはmuteを優先するとよいでしょう。 - 移動で 2 つのイベントが発生します: Discord では新しい
channel_idを付けたvoice-states/{uid}への PATCH はVOICE_STATE_UPDATEを 1 回だけ発行しますが、セルフホストでは移動が退出+再参加として実装されているため、対象ユーザーのchannel_idが一度nullになってから新しいチャンネルに変わります。同じユーザーについて数百ミリ秒以内に続いた更新は、1 回の移動として扱ってください。
セルフホストかどうかの判別
現時点では guild オブジェクトに「セルフホスト」を示すフラグはありません(Discord とバイト単位で同一を保つためです)。処理を分ける必要がある場合、確実な手がかりは上記のいずれかのエンドポイントから返る 501 か 404 で、JSON のエラーボディは次のようになります。
{ "code": 0, "message": "voice-state modify not supported on self-hosted yet" } より軽い判別を必要とするボットが増えれば、ギルドのペイロードに features のエントリ(例: "SELF_HOSTED")を追加します。役立つようであれば、アプリケーションのサポートタブからご意見をお寄せください。
エラー
502 Bad Gateway。セルフホストのサーバーが不正な応答を返しました。まれで、たいていはアップグレード中のバージョン不一致です。503 Service Unavailable。コントロールチャンネルが現在接続されていません。バックオフしながら再試行してください。504 Gateway Timeout。サーバーが 12 秒以内に応答しませんでした。