HVDSGMの仕様を少し整理した

これまでのあらすじ

サービス

HVDSGMは複数のサービスの集合体として構成されるミニブログである。それぞれのサービスは複数のホストに分散していてもよい。サービスは以下のものがある。

  • ソーシャルグラフサービス
  • テキストサービス
  • マルチメディアサービス
  • 疫病サービス

ソーシャルグラフサービス

ソーシャルグラフサービスはユーザー (複数) のレコードを永続化する。ユーザーは以下のフィールドを持つ。

  • ユーザー名 (単数、独自のログイン機構を持つ場合)
  • パスワード (単数、独自のログイン機構を持つ場合)
  • スクリーンネーム (単数、文字列)
  • Bio (単数、文字列)
  • 観察対象のソーシャルグラフサービスのユーザーURL (複数)
  • テキストサービスのユーザーURL (単数)
  • テキストサービスのユーザーURLのタイムスタンプ (単数、Unixエポックからの秒数)

ソーシャルグラフサービスにログインしているユーザーは、パスワード、スクリーンネーム、Bio、テキストサービスのユーザーURLを変更できる。このうち、テキストサービスのユーザーURLが変更されたときは、テキストサービスのユーザーURLのタイムスタンプが更新される。また、観察対象のソーシャルグラフサービスのユーザーURLを追加または削除することができる。

ソーシャルグラフサービスのユーザーには一意なURLが割り当てられる。これをソーシャルグラフサービスのユーザーURLという。このURLに対してGETメソッドを要求すると、以下の情報が得られる。

  • スクリーンネーム
  • Bio
  • 観察対象のソーシャルグラフサービスのユーザーURL
  • テキストサービスのユーザーURL
  • テキストサービスのユーザーURLのタイムスタンプ

テキストサービス

テキストサービスはホスト設定 (単数) のレコードを永続化する。ホスト設定は以下のフィールドを持つ。

  • 信頼するマルチメディアサービスのホスト名 (複数)

テキストサービスはユーザー (複数) のレコードを永続化する。ユーザーは以下のフィールドを持つ。

  • ユーザー名 (単数、独自のログイン機構を持つ場合)
  • パスワード (単数、独自のログイン機構を持つ場合)
  • ソーシャルグラフサービスのユーザーURL (単数)
  • イベント (複数)

イベントは以下のフィールドを持つ。

  • タイムスタンプ (単数、Unixエポックからの秒数)
  • イベントID (単数、機械可読な文字列)

イベントは以下の種類がある。

  • 投稿
  • 賛美
  • 拡散
  • 削除
  • 疫病
  • 疫病の拡散

投稿は以下のフィールドを持つ。

  • 内容 (単数、文字列)

賛美は以下のフィールドを持つ。

  • オリジナルのテキストサービスのユーザーURL (単数)
  • オリジナルのイベントID (単数)

拡散は以下のフィールドを持つ。

  • オリジナルのテキストサービスのユーザーURL (単数)
  • オリジナルのイベントID (単数)
  • 内容のコピー (単数、文字列)

削除は以下のフィールドを持つ。

  • 削除されたイベントのイベントID (単数)

疫病は以下のフィールドを持つ。

  • タイトル (単数、文字列)
  • 疫病のURL (単数)

疫病の拡散は以下のフィールドを持つ。

  • オリジナルのテキストサービスのユーザーURL (単数)
  • オリジナルのイベントID (単数)
  • タイトルのコピー (単数、文字列)
  • 疫病のURL (単数)

テキストサービスにログインしているユーザーは、パスワードを変更できる。また、イベントを追加することができる。タイムスタンプとイベントIDと疫病のURLは自動的に生成される。

テキストサービスのユーザーには一意なURLが割り当てられる。これをテキストサービスのユーザーURLという。このURLに対してGETメソッドを要求すると、以下の情報が得られる。

  • イベント (複数)

ユーザーがテキストサービスにログインしているとき、テキストサービスは一定時間ごとにリフレッシュ動作を行う。リフレッシュ動作は以下のように行う。

  1. ソーシャルグラフサービスのユーザーURLに対してGETメソッドを発行し、諸情報を得る。
  2. 観察対象のソーシャルグラフサービスのユーザーURLに対してGETメソッドを発行し、諸情報を得る。
  3. 観察対象としているユーザーが、自分自身を新たに観察対象に加えたならば、通知を表示する。
  4. 観察対象のテキストサービスのユーザーURLに対してGETメソッドを発行し、諸情報を得る。
  5. 削除イベントによって無効化されていないイベントを以下のように表示する。ただし、疫病の拡散は削除イベントによって無効化されない。
    • 賛美、拡散、疫病の拡散のオリジンが自分自身であれば、通知を表示する。
    • 投稿または拡散の内容を表示する。このとき、信頼するマルチメディアサービスのホスト名を持つURLが含まれている場合は、そのURLの内容をダウンロードし、自動再生する。
    • 疫病または疫病の拡散のタイトルを表示する。

ユーザーがテキストサービスにログインしており、疫病の内容を表示する操作を行ったとき、テキストサービスは以下のように動作する。

  1. ソーシャルグラフサービスのユーザーURLに対してGETメソッドを発行し、諸情報を得る。
  2. ソーシャルグラフサービスが申告するテキストサービスのユーザーURLが自分自身に一致しているか調べる。一致していなければ、疫病の内容を開示しないことを表すメッセージを表示する。一致していれば、次のステップに進む。
  3. 疫病のURLに対してGETメソッドを発行し、応答を受け取る。このとき引数として、ソーシャルグラフサービスのホスト名と、テキストサービスのユーザーURLのタイムスタンプを渡す。
  4. 疫病サービスが疫病の開示を拒否したならば、疫病の内容を開示しないことを表すメッセージを表示する。そうでなければ、次のステップに進む。
  5. 疫病の拡散イベントを追加する。
  6. 疫病の内容を表示する。

マルチメディアサービス

マルチメディアサービスはファイル (複数) を永続化する。ファイルは以下のフィールドを持つ。

  • ファイル名 (単数、機械可読な文字列)
  • バイトストリーム (単数)

ユーザーはマルチメディアサービスにファイルを追加できる。

ファイルには一意なURLが割り当てられる。これをファイルのURLという。ファイルのURLに対してGETメソッドを要求すると、バイトストリームが得られる。

疫病サービス

疫病サービスはホスト設定 (単数) のレコードを永続化する。ホスト設定は以下のフィールドを持つ。

  • 信頼するソーシャルグラフサービスのホスト名 (複数)
  • 信頼するテキストサービスのホスト名 (複数)
  • テキストサービスのユーザーURLの最低安定時間 (秒、単数)

疫病サービスは疫病 (複数) のレコードを永続化する。疫病は以下のフィールドを持つ。

  • 内容 (単数、文字列)

ユーザーは疫病サービスに疫病を追加できる。

疫病には一意なURLが割り当てられる。これを疫病のURLという。疫病のURLに対してGETメソッドを発行するときは、以下のパラメーターが必要である。

  • ソーシャルグラフサービスのホスト名 (単数)
  • テキストサービスのユーザーURLのタイムスタンプ (単数、Unixエポックからの秒数)

疫病のURLに対してGETメソッドを発行すると、疫病サービスは以下のように動作する。

  1. 下記の条件を満たしているか調べる。
    • GETメソッドを発行したホストが、信頼するテキストサービスのホスト名に含まれている。
    • ソーシャルグラフサービスのホスト名が、信頼するソーシャルグラフサービスのホスト名に含まれている。
    • テキストサービスのユーザーURLのタイムスタンプが、テキストサービスのユーザーURLの最低安定時間よりも古い。
  2. 前項の条件がすべて満たされるならば、疫病の内容を返す。そうでなければ、疫病の開示を拒否するメッセージを返す。

GNU Social のボットを C++ で作る

プログラミング界隈の姫になるためにはツイッターのボットをPHPで作ることが有効であることが知られています。しかし、ツイッターは2018年を迎えられないかもしれないので、かわりにGNU Socialのボットを作ります。あと、2017年にもなってPHPを学ぶのもダサいので、C++でやります。

GNU Socialは自由なソフトウェアとして実装されたツイッタークローンです。外見はツイッターを丸パクリしている (補足: Qvitterというプラグインを入れるとツイッターそっくりな外見になります。オリジナルのUIはダサいです。) ので、簡単に移行できます。ツイッターにはない特徴として、複数のサーバーの連合であることが挙げられます。すなわち、有志がそれぞれサーバーを建てて、それらが互いに情報を共有することでGNU Socialの全体が成り立っています。ユーザーは所属したいサーバーを選んでユーザー登録します。他のサーバーのユーザーをフォローすることもできる (ただし操作のクリック数がちょっと多い) し、検索とハッシュタグはすべてのサーバーで共有されます。地味に不便なところとしては、他のサーバーから流れてくる画像は、埋め込みではなくリンクになります。これは不便ですが必要な仕様で、悪意のあるサーバーがユーザーの閲覧履歴を勝手に取るのを防ぐためだと思います。

FAQとしては、スマートフォンアプリなどという軟弱なものはありません。がんばってウェブUIを使ってください。

あと、用語の説明ですが、ツイッターの「ツイート」に相当するものはGNU Socialでは「クイップ」と呼びます。

GNU Socialは複数のサーバーの連合なので、好きなサーバーを選べばいいのですが、日本では FreezePeach を選ぶ人が多いです。これは Kawana Kiyoshi が誘致したのがきっかけのようです。特にこだわりがなければFreezePeachを選べばよいのですが、注意が必要なのは、女児の水着姿をクイップするとWe have 1 simple ruleされるということです。

GNU SocialのAPIは AtomPub 形式と Twitter互換 形式があります。AtomPubのほうが仕様がきれいなのですが、誰も使ってないみたいなので、Twitter互換のやつにします。

例として、サーバーは freezepeach.xyz、ユーザー名は vaginaplant、パスワードは XXXXX で、LGBTPZN という文字列をクイップしたいとします。とりあえず wget コマンドで試します。

wget -O - \
    --http-user=vaginaplant \
    --http-passwd=XXXXXX \
    --post-data='status=LGBTPZN' \
    https://freezepeach.xyz/api/statuses/update.json

あとはこれをC++でやります。定番のcURLです。パスワードは /etc/fubai-gnusocial-password というファイルに書いてあると思ってください。なお、このファイルを他人に読まれるとセキュリティが終了します。

#include <curl/curl.h>
#include <string>
#include <fstream>

using namespace std;

static int writer
    (char * data, size_t size, size_t nmemb,
    std::string * writerData)
{
	if (writerData == nullptr) {
		return 0;
	}
	writerData->append (data, size * nmemb);
	return size * nmemb;
}

void quip (string message)
{
    CURL *curl;
    CURLcode res;
    curl_global_init (CURL_GLOBAL_ALL);
    curl = curl_easy_init ();
    if (! curl) {
        return;
    }

    curl_easy_setopt (curl, CURLOPT_URL,
        "https://freezepeach.xyz/api/statuses/update.json");

    string user_name {"vaginaplant"};
    string password;
    ifstream secret_file {"/etc/fubai-gnusocial-password"};
    secret_file >> password;
    string userpwd = user_name + string {":"} + password;
    curl_easy_setopt (curl, CURLOPT_USERPWD, userpwd.c_str ());

    curl_easy_setopt (curl, CURLOPT_POST, 1);

    string arguments = string {"status="} + message;
    curl_easy_setopt (curl, CURLOPT_POSTFIELDS, arguments.c_str ());

    string reply;
    curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, writer);
    curl_easy_setopt (curl, CURLOPT_WRITEDATA, & reply);

    res = curl_easy_perform (curl);

    if (res != CURLE_OK) {
        return;
    }
    curl_easy_cleanup (curl);
    curl_global_cleanup ();
}

quip 関数の message 引数に適当な文字列を入れてください。リンクとハッシュタグは自動的に解釈されます。

読者の知識をどのくらいに想定すればいいのかわからないのですが、リンクするとき -lcurl を指定すべきであることを申し添えます。

フリップフラッパーズ イロドリ先輩メインSS (改訂)

(13話を視聴したので設定を合わせました。改訂前。)

美術準備室には先輩がいた。先輩の指先にマニキュアが光る。

「先輩、私、先輩の絵が好きです! だから、もう、絵が邪魔だなんて、言わないでください。」

「ああ、あれね。ごめんね、ちゃんと説明してなくて。でも安心して。絵が嫌いになったわけじゃない。ここは狭いし、それに、いまは新しい絵をたくさん描きたいんだ。」

テーブルには、このまえ見たのとは違う、花柄のティーカップが3個。でも、紅茶が注がれるのは、私たち二人分だけ。

先輩が絵を捨てたのは、たぶん、三人でこの部屋にいても狭くないようにするためだったと思う。

アモルファスの力が失われて、ヤヤカたちもピュアイリュージョンには行けなくなった。お母さんとパピカは、ピュアイリュージョンに閉じ込められている。

でも、先輩となら、もう一度、ピュアイリュージョンに行ける気がする。先輩の変身アイテムは、マニキュアのびん。

二人で手をつないで考える。イロちゃんのこと、おばちゃんのこと、お母さんのこと。

そして、パピカのこと。

先輩も、きっと、パピカのことを思ってる。

待ってて、パピカ! いま迎えに行くから!