この記事はドワンゴ Advent Calendar 2017、Mastodon Advent Calendar 2017の三日目の記事です。
本当は「で、結局Mastodonって何だったの?」をアドベントカレンダーに載せたかったのですが、先に公開してしまったものを載せても仕方がないので軽くMastodonの連合の仕組みを説明したいと思います。
ActivityPub: Mastodonの連合を支えるプロトコル
前述のとおり、Mastodonの最大の特徴は連合です。連合とは、Mastodonインスタンスという敷居を跨いだユーザー同士のやりとりを可能にする仕組みのことです。 Mastodonインスタンス同士はOStatusやActivityPubといった特定のプロトコルを介してつながっています。
Mastodonは、バージョン1.6以前はOStatusと呼ばれるGNU social互換のプロトコルのみで他インスタンスとの連合を行っていました。しかし、OStatusでは投稿の公開範囲に関して細かな規定がなされておらず、一人でもGNU socialのインスタンスに所属している人がフォロワーにいた場合、プライベートな投稿の内容がそちら経由で漏れてしまうなどの問題が発生していました。そこで、Mastodon 1.6.0からメインの連合プロトコルをActivityPubへと転換し、2.0.0からはOStatus経由ではプライベートな投稿が連合されなくなりました。
ActivityPubとは?
ActivityPubは、分散ソーシャルネットワーキングのプロトコルの1つで、以下の2つを定義しています。
- サーバー⇔サーバー間の連合プロトコル - 分散SNSの実装がどのようにデータをやりとりするのか
- クライアント⇔サーバー間のプロトコル - ユーザーやその代行者としての(デスクトップ|スマートフォン|Web)アプリがActivityPub対応のサーバーとどうやり取りするのか
Mastodonでは現状、連合プロトコルにはActivityPubを使用していますが、クライアント⇔サーバー間の通信に関しては独自のAPIを採用しています。
ActivityPubでは、すべてのデータは基本的にはActivity Streams 2.0のオブジェクトとして扱い、サーバー間ではJSON-LD互換の形式にエンコードしてやり取りされています。一時的に必要となるだけの(transientな)オブジェクトを除いて、すべてのオブジェクトにはURI/IRIによるIDが割り振られています。Activity Streams 2.0のオブジェクトには、以下のようなものがあります:
-
Object
-
投稿など、一般的なオブジェクト
Type 説明 Article ブログ記事など、複数段落にわたるような長い文章 Audio 音声データ Document ドキュメント Event イベント Image 画像 Note TwitterやMastodonの投稿など、短い文章 Page Webページ Place 論理的(例: 仕事)/物理的(例: 35°41'54.0"N 139°46'18.3"E)な場所 Profile ほかのオブジェクトを説明するコンテンツ Relationship 2つの個人間の関係を説明するオブジェクト Tombstone Collection内などで、削除されたオブジェクトのかわりに置かれる Video 動画 -
Actor (ユーザーなど)
Type 説明 Application ソフトウェアアプリケーション Group Actorの集合 Organization 組織 Person 個人 Service あらゆるサービス -
Activity (新しい投稿をする、投稿をお気に入りに登録する、フォローリクエストするなどアクターの起こしたアクション)
Type 説明 Accept actor
がobject
(例: Invite)を承認したことを示すAdd actor
がtarget
にobject
を追加したことを示すAnnounce actor
がtarget
にobject
を見てほしいと思っていることを示す (= ブースト)Arrive actor
がlocation
に到着したことを示すBlock actor
がobject
をブロックしたことを示す。ActivityPubではサーバー間で連合されないことになっているCreate actor
がobject
を作成した(=投稿した)ことを示すDelete actor
がobject
を削除したことを示すDislike actor
がobject
を「よくないね」と思っていることを示すFlag actor
がobject
を通報したことを示すFollow actor
がobject
をフォローしたことを示すIgnore actor
がobject
を無視すること(おそらくミュート)を示すInvite actor
がobject
への招待をtarget
に送ったことを示す。Offerの特殊版Join actor
がobject
へ参加したことを示すLeave actor
がobject
から離脱したことを示す (どうやらArrive, Joinの両方の逆の意味を持っているらしい?)Like actor
がobject
を「いいね」と思っていることを示すListen actor
がobject
を聞いたことを示すMove actor
がobject
をorigin
からtarget
へ移動したことを示すOffer actor
がobject
をtarget
にオファーしていることを示すQuestion 質問を表現している。 anyOf
,oneOf
で選択肢を提示することができる (両方同時に存在してはならない)Reject actor
がobject
を拒絶したことを示すRead actor
がobject
を読んだことを示すRemove actor
がobject
を削除したことを示す。origin
が指定することによってどこからobject
が削除されるのかを指定することができるTentativeReject Rejectの特殊版。 actor
がobject
を仮拒絶したことを示すTentativeAccept Acceptの特殊版。 actor
がobject
を仮承諾したことを示すTravel actor
がorigin
からtarget
へ旅をしていることを示すUndo actor
がobject
をアンドゥしたことを示す。object
は大体Actorの1つである (例: ふぁぼを取り消す時はLikeアクティビティをUndoする)Update actor
がobject
を更新したことを示す。Activity Streams 2.0では特段どのように更新されたかなどの取り決めはなされていないが、ActivityPubによって規定がなされているView actor
がobject
を見たことを示す Collection (投稿やフォロワーの一覧、inboxやoutboxなど)
-
ここで興味深いのは、ユーザーの起こしたアクションなどもすべてオブジェクトの一種として扱われることです。このオブジェクトとして表現されたアクティビティをあらかじめ定められたルールに従って他インスタンスへ転送することによって、Mastodonは連合という仕組みを実現しています。これらの転送の仕組みを定義しているのがActivityPubです。
では実際、ActivityPubでアクティビティの転送はどのように定義されているのでしょうか。
ActivityPubによるサーバー間のデータ転送
ActivityPubでは、すべてのActorオブジェクトにinbox
, outbox
という2つのプロパティを定義することを要件づけています。inbox
はActorが受け取ったすべてのアクティビティのOrderdCollection、outbox
はActorが行ったすべてのアクティビティのOrderedCollectionです。
他インスタンスのアクターへアクティビティを転送する際には、転送先のアクターのinbox
へHTTP POSTを行うことによって転送を行います。大規模なインスタンスでは複数のサーバーで動いている場合もありますし、ブーストを行う場合など、送信側・受信側のどちらでもない第三のインスタンスのアクティビティを転送する必要がある場合もあるので、Activity StreamsではLinked Data Signatureを用いたオブジェクトへの署名と検証を行うことが推奨されています。
おわりに
執筆時間が短かったせいもあって、結構駆け足になってしまいました。しかし、ActivityPubでどのようなものが表現できるかもしれないかということについては少しご理解いただけたかと思います。
ActivityPubはまだ未完成な規格です。特に認証周りやコンテンツをどのように表現してやりとりをするか、ユーザーのIDをどのようにルックアップするのかといった部分があまりはっきりと定まっていないイメージが感じられます。Mastodonでは認証周りはほぼ投げてしまっていますし、コンテンツは許可タグ以外のエスケープ処理がなされたHTMLが使われていますし、ユーザーIDはOStatusだった頃の仕様を引きずってWebFingerを用いています。ActivityPubの将来に期待しましょう。