分散型SNSマストドン
私は分散型SNSのマストドンによく参加しており最近ではよくRustを用いてマストドン関連のサービスを書いていたりしました。その中の一つでBotを作ったので使い方などを説明したいと思います。
リポジトリ
https://github.com/nacika-ins/nanachibot
Mastodonのベースとなるライブラリ「Mammut」
Mammutは、Mastodon APIのラッパーライブラリです。マストドンにアプリを登録したり、フォローやタイムラインの取得などができます。一通りのエンティティも揃っており、これだけでマストドンのAPIが簡単に叩く事ができます。
Mammutで出来なかったこと
Mammutでは一通りのマストドンのAPIを叩く事ができますが、マストドンの特徴であるリアルタイムなストリーミングによるタイムラインの自動取得が出来ません。通信をキープすることで自動取得が実現できるのですがそのようなコードが見当たりませんでした。😢
ないなら作れとforkしたのがこちらです。
nacika-ins/Mammut
こちらのリポジトリでは、まだちゃんとコード整理出来てないですが get_user_streaming というメソッドを用意しました。thread
と loop
と channel
を用いて websocket
によって常に通信を監視するようになっています。かなり試行錯誤しました。😓
マストドンがまだ1系の頃は pingに対してpongを送らなくても通信が維持されていたりしていたのがいつのまにかpingに対して正しくpongを返さないと切断されるようになっていたり、rust の websocket
自体が仕様変更で改修が必要だったりとなかなかうまく行きませんでした。
もしもwebsocketの通信が切断されても、loop によって再試行されます。
数回の実行でアプリの簡単登録出来るようにした
Bot側のコードでは、まだconfig.toml
が作成されていない場合はアプリ作成の問い合わせを行うようになっています。複数回実行することで、config.toml
の中のキーが自動的に設定されます。ただ、アクセストークンだけは手動で貼り付ける必要があります。
config.toml
が満たされているとBotが起動します。
ストリーミングの実行部分
let (srx, nrx) = mastodon.get_user_streaming();
ユーザータイムラインのストリーミングを開始すると、2つのReceiverが渡されます。
左がHTL(ホームタイムライン)、右が通知です。それぞれ Status
というエンティティを扱いますが、
HTLと通知では若干構成がことなるので注意が必要です。Mammut標準のエンティティだと型が違っていてエラーになっている箇所があったので修正している部分があります。
Receiverから受信するとThreadがそこで待機状態になってしまうので、新しいThreadを作成しそこで受信するようにしています。肝心のBotの部分は、
let nanachi_arc = Arc::new(Mutex::new(nanachi));
Arc Mutexを用いて、スレッドを一時的にロックしHTLと通知用のスレッドでそれぞれ共通で使っています。
そこまでリソース食わないし状態を持たないので2つ作っても問題はないです。
Botの投稿
Botに何か投稿させる処理は別なチャンネルで行うようにしました。投稿自体はMammutの機能を使い、StatusBuilder
でStatus
を作成し、new_status
で投稿します。 .in_reply_to_id
は、ユーザーIDではなく、返信先のステータスIDのようです。
今後やってみたいこと
まだLTLや連合のストリーミングに対応していないので今後対応させて、自動的に学習させたりしてみようかと考えています。