Misskey.io で bot を作る ―― MiAuth からストリーミング API、そしてレートリミットとの戦い

Page content

今回は Misskey.io で bot を作成するにあたって調べたことや、実際に手を動かしてハマったポイントなどをまとめておきます。 これから Misskey で bot 開発を始めようと思っている方の参考になれば幸いです。

bot アカウントの作成と心得

まず最初に、bot 用のアカウントを作成する必要があります。

ここで重要なのは、アカウントを作成したら設定画面から必ず「bot フラグ」を有効にしておくことです。 これは単なる自己申告ではなく、システム側や他のユーザーに対して「これは自動実行プログラムですよ」ということを明示するための重要な設定です。

公式ドキュメント( https://misskey-hub.net/ja/docs/for-developers/bot/ )にも記載がありますが、bot アカウントを運用する上では、サーバーに過度な負荷をかけない、周囲のユーザーに迷惑をかけないといったマナーが求められます。 特に Misskey.io のような大規模サーバーでは、一つの bot の暴走がサーバー全体のパフォーマンスに影響を与える可能性もあります。

MiAuth によるトークンの取得

bot を動かすには API を叩くためのトークンが必要になります。

トークンを取得するには MiAuth という認証方式を利用します。 MiAuth は、ざっくり言うと OAuth をシンプルにしたような仕組みです。 セキュリティの観点から見ても、不必要に強い権限を持ったトークンを永続的に保持するのは避けるべきです。

パーミッションの設計

MiAuth でトークンを取得する際、どのような権限(PERMISSION)を要求するかを指定します。 詳細は公式( https://misskey-hub.net/ja/docs/for-developers/api/permission/ )を参照して欲しいのですが、ここで一つ悩みどころがあります。

ドキュメントの記載だけだと、どの機能にどの権限が必要なのかがイマイチ分かりにくいのです。 例えば「投稿を取得したいだけ」なのに、どの read 権限を付ければいいのか、あるいは「ファイルをアップロードしたい」時にどの write 権限が必要なのか。

私の経験上、=write:notes=(投稿作成)や read:account=(アカウント情報取得)あたりは必須になることが多いでしょう。 =write:* 系や、 admin:* 系の権限は、万が一トークンが流出した際のリスクが極めて高いため、必須でない場合は避けましょう。

取得フロー

実際の取得手順は以下の通りです。

  1. bot アカウントでログイン済みのブラウザで、次の URL にアクセスします。

    • https://misskey.io/miauth/$(UUID)?permission=$(PERMISSION)
    • ここで $(UUID) は適当な ID(UUID 形式)を自分で生成します。
    • $(PERMISSION) はカンマ区切りの権限リストです。
  2. 画面に「連携を承認しますか?」といった内容が表示されるので、承認します。
  3. 承認後、次の curl コマンドを実行してトークンを回収します。
1
  curl -v -X POST https://misskey.io/api/miauth/$(UUID)/check

ここで指定する UUID は、手順 1 で使用したものと同じでなければなりません。 成功すると、レスポンスの JSON 内に待望の token が含まれています。 これを大事に保管して bot のコードに組み込みます。

ストリーミング API によるリアルタイム処理

Misskey の醍醐味といえば、リアルタイムに流れてくるタイムライン(TL)です。 これを bot で扱うには、HTTP によるポーリングではなく、WebSocket を使った「ストリーミング API」を利用するのが一般的です( https://misskey-hub.net/ja/docs/for-developers/api/streaming/ )。

ポーリングは実装が簡単ですが、サーバーへの無駄なリクエストが発生しやすく、またリアルタイム性も落ちます。

チャンネルの選択

WebSocket でサーバと接続した後、どの「チャンネル」を購読(connect)するかを決定します。

  • homeTimeline: 自分のフォローしているユーザーの投稿が流れます。bot の自分宛てのメンションに反応する場合などはここを使います。
  • localTimeline: インスタンス全体の投稿が流れます。いわゆる「LTL」です。

開発初期の動作確認であれば、投稿頻度の高い localTimeline に接続して、次々と流れてくる JSON を眺めるのが手っ取り早いです。 ただし、Misskey.io の LTL は濁流のような勢いで流れてくるため、不用意に全てのログを出力するとコンソールが浦島太郎状態になるので注意が必要です。

投稿とファイルのアップロード

メッセージを投稿するだけであれば notes/create API を叩くだけですが、ファイルを添付しようとすると少し手順が複雑になります。

ファイルのアップロード仕様

ファイルのアップロードについては、こちらの API ドキュメント( https://api-doc.misskey.io/api-7254083 )が参考になりますが、ここで大きなハマりポイントがあります。

Misskey では、同じ内容のファイルは基本的に 1 つしか存在できないようです。

つまり、異なるファイル名であってもハッシュ値(バイナリの内容)が同じファイルを再度アップロードしようとすると、既存のファイル ID が返ってくる挙動になります。 「bot が定期的に同じ画像を投稿する」ような実装をする場合、毎回アップロードを試みるのではなく、一度アップロードした際の fileId を再利用する設計にする必要があります。 これを無視して毎回アップロードしようとすると、無駄な API コールが増えるだけでなく、後述するレートリミットにも引っかかりやすくなります。

フォルダによる管理

ファイルを整理するために、ドライブ内にフォルダを作成することも可能です( https://api-doc.misskey.io/api-7254091 )。 事前にフォルダを作成、あるいは参照して folderId を取得しておき、アップロード時にそれを指定します。 bot 用の画像がドライブのルートに散らばっているのは精神衛生上よろしくないので、ディレクトリ構造を整えるのは基本ですね。

添付ファイル付き投稿

ファイルの準備ができたら、=notes/create=( https://api-doc.misskey.io/api-7254018 )の引数 fileIds に、取得した ID の配列を指定して投稿します。 これで、画像付きの投稿が完了します。

レートリミットとの戦い

今回、私が最も苦労したのがこれです。「API request rate リミット」。

bot のテストを繰り返していると、突然 API がエラーを返すようになります。 「ちょっと数回叩いただけなのに……」と思うのですが、Misskey.io の制限はそこそこ厳しめに設定されているようです。

リミットの詳細は不明

ネットを検索しても、具体的な「1 分間に何回まで」という数値は見当たりませんでした。 インスタンスの設定(config)に依存するため、管理者以外には分からないブラックボックスです。 ただ、感覚としては数分間に数十回程度リクエストを送るとロックがかかるような印象です。

40 分間の沈黙

一度レートリミットに引っかかると、しばらくロックがかかります。 私の環境で実測した限りでは、*約 40 分程度* 経過すると自動的に解除されるようです。

さいごに

Misskey.io での bot 開発は、一見簡単そうに見えて、実は分散型 SNS 特有の設計思想や運用ルールへの理解が求められる奥の深い作業です。 単に API を叩くだけではなく、レートリミットやファイル重複といった制約をどう乗り越えるか。 そこには、アルゴリズムの工夫やアーキテクチャの選定といった、プログラミングの根源的な楽しさが詰まっています。

英語のドキュメントを読み解き、プロトコル(WebSocket/JSON)と格闘する時間は、エンジニアとしての基礎体力を鍛えてくれます。

皆さんも、自分だけのスマートな bot を作って、Misskey の世界を彩ってみてはいかがでしょうか。 ただし、くれぐれもサーバーへの負荷には気をつけて。

以上