Bot を実行する¶

bot.run()¶
ほとんどの Bot では、bot.run() がプログラムのすべてです。ルートロガーにまだハンドラーがなければ、INFO レベルで stderr に出力するようにロギングを設定し、イベントループを開始して、Bot が停止するまで実行します。Ctrl+C と、メインスレッドでは SIGTERM によって、Bot はクリーンに終了します。
トークンは環境変数 BOSTIE_TOKEN か、bot.run(token) から渡します。先頭の Bot は取り除かれ、トークンがない場合は ValueError を送出します。run は loop_factory も受け取ります。これはイベントループを作成する関数で、asyncio.run にそのまま渡されます。
ライフサイクル¶
run() の裏で実際の処理を行うのは bot.start() です。
Startingイベントを送り、そのリスナーを 1 つずつ順に await します。ここでは REST は使えますが、ゲートウェイは使えません。例外を送出したリスナーがあると、起動は中止されます。auto_sync=Falseでない限り、コマンドを同期します。- ゲートウェイのシャードに接続します。すべてのシャードの準備が整い、そのサーバーが届くと、
Startedを一度だけ送り、バックグラウンドタスクを開始して、wait_until_ready()が戻るようにします。 close()まで、または Discord がゲートウェイを完全に閉じるまでイベントを処理します。後者の場合はInvalidTokenやPrivilegedIntentsRequiredなどの例外を送出します。
import logging
import bostie
from bostie.events import Started, Starting, Stopped, Stopping
log = logging.getLogger("my-bot")
bot = bostie.Bot()
@bot.listen
async def starting(event: Starting) -> None:
application = await bot.rest.application.fetch()
log.info("starting %s", application.name)
@bot.listen
async def started(event: Started) -> None:
log.info("ready in %d guilds, latency %s s", len(bot.cache.guilds()), bot.latency)
@bot.listen
async def stopping(event: Stopping) -> None:
log.info("saying goodbye while the gateway is still open")
@bot.listen
async def stopped(event: Stopped) -> None:
log.info("the gateway and REST are closed")
bot.run()
await bot.close() は次の順序で終了処理を行います。
Startedが送られていた場合はStoppingを送り、ゲートウェイがまだ開いている間、そのリスナーに最大 5 秒の時間を与えます。- すべてのボイスチャンネルから退出し、各シャードを閉じます。シャードはクローズコード 1000 でセッションを終了するか、再開(resume) のためにセッションを保存します。
- バックグラウンドタスクをキャンセルします。まだ実行中のハンドラーには、キャンセルされるまで
shutdown_grace秒(既定値は 0)の猶予が与えられます。 - HTTP クライアントを閉じて
Stoppedを送り、そのリスナーを await します。この時点でbot.http、bot.rest、bot.gatewayは使えなくなります。
close() はどこからでも、何度でも、start() の実行中にも呼び出せます。その後で Bot を再び起動することもできます。async with bot: は、ブロックの終わりで Bot を閉じます。
別のプログラムの中で動かす¶
プログラムがすでにイベントループを動かしている場合は、Bot をタスクとして起動します。
import asyncio
import logging
import bostie
from bostie import StateError
log = logging.getLogger("my-bot")
bot = bostie.Bot(shutdown_grace=10.0)
async def main() -> None:
logging.basicConfig(level=logging.INFO)
running = asyncio.create_task(bot.start())
try:
await bot.wait_until_ready()
except StateError:
await running
raise
log.info("%s is in %d guilds", bot.user, len(bot.cache.guilds()))
try:
await running
finally:
await bot.close()
if __name__ == "__main__":
asyncio.run(main())
await bot.wait_until_ready() は Started が送られた時点で戻り、すでに送られていればすぐに戻ります。先に Bot が停止した場合は StateError を送出し、そのうえで start() のタスクを await すると停止の原因となった例外が送出されます。bot.is_ready は、待たずに同じことを教えてくれます。Web アプリのサンプルでは、Web サーバーの lifespan の中で Bot を動かし、Web のルートからメッセージを投稿しています。
HTTP 経由でインタラクションに応答するだけの Bot には、ゲートウェイは必要ありません。HTTP インタラクションを参照してください。await bot.open() はその方式で Bot を起動してすぐに戻ります。HTTP クライアントを開き、アプリケーションと Bot のユーザーを取得し、Starting を送り、コマンドを同期し、バックグラウンドタスクを開始して、アプリケーションを返します。ASGIApp がこれを呼び出し、close() で終了します。REST API を呼び出すだけのスクリプトでは RESTClient を使います。
実行中¶
| 属性 | 値 |
|---|---|
bot.user |
Bot の CurrentUser(接続後) |
bot.application_id |
アプリの ID(起動後) |
bot.latency |
シャードのハートビート往復時間の平均(秒)、または None |
bot.is_running |
start() または open() が Bot を実行していて、まだ close() で終了していないかどうか |
bot.is_ready |
最後の start() 以降に Started が送られたかどうか |
bot.rest、bot.http |
REST API(起動後) |
bot.gateway |
ゲートウェイのシャード(接続後) |
bot.cache |
キャッシュ |
bot.voice |
ボイス接続 |
bot.auto_defer |
既定の自動遅延応答までの時間。いつでも変更できます |
bot.rest、bot.http、bot.gateway は、start() の前には StateError を送出します。
ロギング¶
bostie は標準の logging モジュールに、次の名前でログを出力します。
| ロガー | 報告する内容 |
|---|---|
bostie.bot |
失敗したハンドラーや応答しなかったハンドラー、リスナーが必要とするインテント、処理されなかったインタラクション |
bostie.gateway |
接続、切断、再開(resume)、バックプレッシャー、無効なリクエスト |
bostie.rest |
Rust の HTTP クライアントからのレート制限とリトライ |
bostie.sync |
各コマンド同期で変更された内容 |
bostie.context |
編集時のエフェメラルフラグのように、適用できなかった応答 |
bostie.events |
イベントに合わなかったペイロード(イベント名ごとに 1 回) |
bostie.voice |
ボイス接続、DAVE、シンク、レシーバー、プレイヤー |
bostie.bridge |
Python と Rust コアの間の連携 |
Rust コアも同じロガーを通してログを出力し、Bot の起動時にそのレベルを読み込みます。ゲートウェイを詳しく見るには、run() の前に logging.getLogger("bostie.gateway").setLevel(logging.DEBUG) を設定してください。
bostie の接続先を変える¶
Bot(api_url=...) を指定すると、REST リクエストを別のベース URL に送ります。たとえば、複数のプロセスで共有するレート制限プロキシや、テストでのフェイクの Discord です。省略した場合、bostie は Bot の起動時に BOSTIE_API_URL を読み込み、それも未設定なら https://discord.com/api/v10 を使います。レート制限プロキシの背後では http_settings=HTTPSettings(rate_limiter=False) を渡し、待機をプロキシに任せてください。その他の HTTP の設定は REST ガイドで説明しています。
1 つのプロセスで複数の Bot を動かす¶
各 Bot は、Rust コアへの独自の接続、独自のキャッシュ、独自の HTTP クライアントを持ちます。そのため 1 つのプロセスで、1 つのイベントループ上に複数の Bot を動かし、それぞれを個別に起動・終了できます。
状態を保持する¶
Bot は普通のオブジェクトです。属性を持たせるには Bot をサブクラス化します。ライフサイクルのサンプルでは、Starting リスナーで開いたデータベース接続を Stopped リスナーで閉じています。Bot のすべてのオプションは、Bot のオプションのリファレンスに一覧があります。