Perl Hackers Hub

第59回 Fediverse入門―非中央集権型SNSサーバを作ろう!(2)

この記事を読むのに必要な時間:およそ 3 分

前回の(1)こちらから。

Perlでの実装

それでは,筆者が作成したPerl製の発信専用1ユーザーActivityPubサーバであるActubを例に,Perlでの実装について説明します。Actubは,WebフレームワークにMojoliciousを使い,Fediverseに参加するための最小限の機能を実装することを目標にしています。Actubは購読機能を持たないのでほかのユーザーをフォローしてタイムラインを読むことはできませんが,ほかのサーバのユーザーにフォローされることでFediverseに情報を発信できます。

ActivityPubはWeb APIベースのプロトコルですので,Actubも「リクエストを受け付けて,情報を加工し,レスポンスを返す」という一般的なWeb APIサーバと同様の動作をします。以降では,一般的な処理については説明せず,Actubで特徴的な処理を行っている部分について説明します。

AS2オブジェクトモデルの作成

Actubでは,ActivityPubのデータモデルであるAS2オブジェクトを表現するためのクラスを作成します。

個々のオブジェクトを表現するクラスを作成する前に,まずベースとなるクラスを作成します。

package WWW::ActivityPub::Base;

use strict;
use warnings;

use Class::Tiny;

sub TO_JSON {
    my %ret;
    my $self = shift;
    for (keys %$self){
    my $key = $_;
    my $jsonkey = $key;
    if($key eq 'context'){
        $jsonkey = '@context';
        if(!defined $$self{$_}){next;}
    }
    $ret{$jsonkey} = $$self{$_};
  }
  return \%ret;
}

1;

ここではClass::Tinyモジュールを用いています。これは属性のゲッタとセッタを設定するだけのシンプルなモジュールですが,コアモジュール以外に依存のない軽量なモジュールです。これを使って属性名と同じ名前のメソッドでAS2の各属性にアクセスできるようにしたいところですが,AS2には@context属性があり,@はメソッド名に使えないため,この名前のままではメソッド名として使えません。この問題に対応するため,個々のクラス定義では@contextではなくcontext属性として定義し,JSON直列化の際にcontext属性を@contextに変換して出力するためのTO_JSON関数を定義しています。

この下準備により,たとえばFollowクラスの定義は次のようにシンプルなものになっています。

package WWW::ActivityPub::Follow;

use strict;
use warnings;

use parent qw(WWW::ActivityPub::Base);

use Class::Tiny qw(
    context id type object
    );

1;

MIME型の登録

GETリクエストに対する返却処理は通常のレスポンスなので実装上特筆することはあまりありませんが,前述のとおりMIME型としてapplication/ld+json; profile="https://www.w3.org/ns/activitystreams"を使う必要があるため,あらかじめMojoliciousのstartupフック内で次のようにしてこのMIME型を登録しておきます。

sub startup {
    my $self = shift;
    ...;
    $self->types->type(as =>
      'application/ld+json; profile=' .
      '"https://www.w3.org/ns/activitystreams"');
}

これにより,実際にレスポンスを出力するときには次のようなコードでMIME型を指定して出力できます。

# $outは出力するデータ
$self->render(text => $out,
              format => 'as');

送信キューの登録

Actubは送信処理を非同期で行う実装となっているので,購読アクターからFollowオブジェクトが送信されると,対応するAcceptオブジェクトをジョブキューに追加します。ここでのジョブキューシステムはJonkモジュールを使っています。これはデータベースをバックエンドに使う軽量なジョブキューシステムで,次のようなコードでキューに追加します。

# $dbhはデータベースハンドル
my $jonk = Jonk->new($dbh);
...;
my $job_id = $jonk->insert('post', $queuestr);

著者プロフィール

白方健太郎(しらかたけんたろう)

株式会社モカ代表取締役。自称「さすらいのプログラマー」。Perl関連ではJapanized Perl Resources Projectなどで活動中。