Mastodonに来たらRubyを覚える羽目になった話
Fediverse (2) Advent Calender 2021 4日目の記事です。 (22日に枠取得、26日 19:55に投稿。 大変遅くなりました!!!)
あすらも (@dk_k@fedibird.com, @qk_k@mstdn.jp) と申します。
ここ1~2年の間、mstdn.jpやFedibirdに高くない頻度で投稿しています。
今年もAdvent Calenderは見る専のつもりでしたが、なんかFediverse Advent Calender第二会場の枠が多めに空いてたので取ってみました。
本当は12/25までに自鯖を立ててそのことを書きたかったのですが、鯖立てが間に合ってないので、私がMastodonに来てから今までの振り返りをしてみます。 タイトルはちょっと誇大表現入ってます。
// RubyはMastodonの実装に使われているプログラミング言語です
// 文章ド下手なので読みづらい・違和感がある箇所が多いと思いますが頑張って読んでください
経緯
Fediverseに住み着く
私がMastodonを知ったのは、TwitterのUserStream終了騒動があった2018年8月です。
最初はmstdn.jpにアカウントを作り、LTLの流れにすこしだけ参加しましたが、「当時持っていたPC・スマホ・タブレットがどれもクソスペで、まともに使えなかった」*1「精神的になんとなく合わなかった」などの要因があり、馴染めずに離れることとなりました。
2020年になり、最新スペックのノートPCを購入して、旧PCからデータ移行をしていたところ、以前使っていたMastodonクライアントアプリ (TheDesk) を見つけました。 そこでふと「今なら出来るんじゃないか」と思い、2月の終わりにjpに復帰しました。
当時は (2018年ほどではないものの) 今よりローカルタイムライン (LTL) が賑わっていて、LTLで会話したり、新規を囲ったり、新規を名乗ったり、例の漢字1文字トゥートをしたり、脳死で駄洒落トゥートをしたり、20万ユーザー達成を祝ったり… と楽しんでいました。
その後、jp閉鎖騒動やその前後でのjp鯖の長時間ダウンなどによる大移動をきっかけに、Fediverseの概念と広さを知り、Fedibirdのアカウントも使い始めて今に至ります。
最近は投稿頻度が落ちていて、住み着いたと言えるか怪しくなっていますが…
鯖を立てたい
2020年5~6月に一度、とある理由 (黒歴史) で改造Mastodonサーバを立てようとしたことがあります。 その時はMastodonのコードを十数行弄って、さくらのVPSで仮サーバを立てるまではしましたが、モチベが上がらずそこで頓挫しました。
これ以降、たまにVirtualBoxでMastodonを立てたり、何もわからないなりにMastodonのコードを眺めてみたりしていました。
同年10月くらいから、「Mastodon楽しいけど通信量ヤバい → 通信量を減らしたい → そのための機能 *2 を付けたサーバーを立てたい」という感じで再び自鯖欲が出てきました。
後に「モバイル回線の低速モード (≒通信制限) でも少しは画像を見たい」という理由も加わり、2021年になってから、とりあえず今年中に鯖を立てるという目標をこっそり立てました。
そのまましばらく何もしていませんでしたが、ここ数ヶ月で自鯖に引っ越された方をよく見かけるようになり、「なんか自鯖ブーム起きてるっぽいしやるか~」とようやく準備にとりかかったのが11月下旬です。 この調子なので実際に立つ頃には2022年になってる気がしますが。。。
本家にPRするきっかけ
準備を始めたのと同時期に、初めてのiPhone (iPhone SE 第2世代) を購入し、初期設定をしていました。
初期設定が終わり、App StoreにあるいろいろなMastodonクライアントアプリを試していたところ、「Mastodonクライアントの認証中に、WebAuthn (指紋認証とかYubiKeyとかでログインするやつ) を使ってログインすると、認証画面ではなくWebのMastodonのホームに飛ぶ」というバグを見つけました。
MastodonのコードをVSCodeで検索しまくった結果、原因と直し方の見当はつきました。 ただコードをどう書き換えて直すのが正解か判断できる自信は無かったので、とりあえず不具合をボロボロの英語 *3 で長々と説明したissueを投げました。
その後「あなたがPull Requestして (≒直して) くれてもいいのよ」 (超絶意訳) と言っていただき、折角なので「数日以内にやる、できなかったら自分には無理だと伝える」と決めて自分で直してみることにしました。
PRを投げるまで
今までもMastodonのコードを雰囲気で適当に弄ることはありましたが、本家に適用されるかもしれないとなると、適当ではなく、これで直るとある程度確信できるようになってから出したいと思いました。
私はこれまで、プログラミング言語ではJavaScript (ECMAScript) がチョットデキルのと、他のいくつかの言語 (Java, Pythonとか) を軽く触ったことがあるくらいで、Rubyを勉強したことはありませんでした。
この状態からRubyやRailsを0から勉強しても間違いなく追いつかないので、「該当コードを適当に眺めて、分からないところはWeb検索してRubyや各種ライブラリ (Gem) の公式ドキュメントやブログなどと見比べる」作業を何度も繰り返しました。
また、リアルタイムデバッグの方法が分からなかったので、鯖立てのために用意していたOracle Cloudのテスト用サーバにVSCode SSHで接続して、サーバ上のコードに Rails.logger.warn
を大量に挿入して実際の動作ログを見るという、いわゆるprintデバッグで処理の流れを把握しました。
その途中で、他の言語で見たことがない、RubyやRails特有の書き方や仕様 (:symbol
とかmix-inとか) に遭遇することが何度かありました。 以前適当に弄っていたときは「わからん」で済ませてそれ以上追求していませんでしたが、今回は可能な限り調べてその仕様を理解しようとしました。 *4
これはissueを投げる前の原因追及時からですが、 /spec
以下にあるテストコードの確認も処理の理解に役立ちました。
1から勉強せず場当たり的にやっていたため、「何故このリクエストが来た時このファイルのここの処理がこう発動するのか」というのが全く分かってなかったんですが、このテストコードに分かりやすい処理の概要説明と実際に動作するサンプルコードが書かれていたので、そこで呼び出されている関数などを検索することで、簡単に目的の処理を特定できました。
(最初はテストコードだと分からず、実際の動作でここがいつ呼ばれるのか探ってました)
こんな感じで数日かけてコードを弄って動作テストを繰り返した結果、たった1行の書き換えで直るだろうということがわかり、拍子抜けしながらPRを作成しました。
// VSCodeに「Ruby Solargraph」という拡張機能を入れて入力補完できるようにしたんですが、Gemの機能 (Paperclip, Deviseとか) に関する候補を出せず、Web上のリファレンスを都度確認する必要がありました。 Mastodonのディレクトリで yard gems
するなど色々試しても何故か変わらず。 なにか方法があるんでしょうか?
最後に
ここまで好き勝手に文章を書いて公開したのは久しぶりです。 Fediverseに来てからは初めてかもしれません。
復帰当時は、Twitterの公開アカウントでの活動を過去の黒歴史のためにほぼストップして数年経ったという状況でした。
またネット上に (一応) 名前をもった存在として足を踏み入れ、こうして文章を公開できたのは、Mastodon、そしてFediverseで関わってくださった方々のお陰だと思っています。 ありがとうございました。
リアルの事情などいろいろあって鯖立て作業が止まっていましたが、鯖用ドメインを既に買ってしまったので近いうちに作業に戻ろうと思います。
この記事の締めとして (?) 、今回のために過去の投稿を見直した際に見つけて以来、ずっと頭の隅に残っている投稿をおすそ分けさせていただきます。
睡眠はしっかりとりましょう! *5
お読みいただきありがとうございました!
脚注
*1:2018年当時はAndroid2.xの時代からある軽量な2ch専ブラやTwitterクライアントを使っていて、「軽量最強! 重くて端末容量をひっ迫させる公式Twitterアプリを入れるなど有り得ない」とマジで思ってました。 そんな状況で、2017年に広まったイケイケなサービスであるMastodonに適応できなかったのも無理はないかも。
*2:連合先サーバから来るでかい (数MBとかある) 画像をなんやかんやしてファイルサイズを減らす処理を検討してます。
*3:英和和英辞典と睨めっこしながら2時間かけて書いた結果がこれ ("a issue" とか…) です。 でも多分伝わったのでヨシ!
*5:なお、この部分を書いたの深夜4時
Cloudflareで送信元ポート番号を取得する
Cloudflareではヘッダーに発信元IPアドレスしか載らないから不可能だと思っていたら、最近出来るようになってたので記録します。
経緯
IPv4 アドレスが共有されている環境でよろしくないことをされた時のために、クライアント (発信者) の IP アドレスだけでなく送信元 (発信元) ポート番号も記録したほうがよいらしいです。
リンク先 PDF の p71 「サーバのアクセスログに関する対応」 より:
- RFC 6302 では、ログに送信元ポート番号を含めることを推奨
- 平成27年に、プロバイダ責任制限法第4条第1項 「発信者情報を定める省令」 の一部が改正され、開示の対象となる発信者情報にポート番号が追加
やり方
今年6月に実装された、 変換ルール (Transform Rules) の中の HTTP Request Header Modification (HTTPリクエストヘッダの修正) という機能を使います。
blog.cloudflare.com
※2021/10/25時点では 「ヘッダーを (の) 修正」 (Header Modification) という名前でしたが、2021/12/05現在「 HTTP Request Header Modification」 に変わっています
CF- から始まるヘッダー名は使えません。 また、 X-Forwarded-Port などのありきたりな名前にすると、後に公式実装されて競合する可能性も無くはないので、被らさそうなものにするとよいでしょう。
これで、Cloudflareを経由する全てのリクエストでヘッダに送信元ポート番号が載るようになります。 Apache や nginx のログ対象に加える *1 なり、Webアプリの実装を弄るなりして、IPアドレスと一緒に記録しましょう。
他の情報も取得する
発信元ポート番号以外にも色々取得できます。
- フィールド (変数) 一覧
- 関数一覧
- 文字結合の concat と、 concat に数値を渡すための to_string が使えます。
- concat の引数は4つまでで、各行で1回しか使えません。
使えそうなフィールドを適当に載せてみました。
Mod-CF-ASN: ip.geoip.asnum Mod-CF-Client-Port: cf.edge.client_port Mod-CF-Client-Trust-Score: cf.client_trust_score Mod-CF-Geo: concat("continent=", ip.geoip.continent, "; country=", ip.geoip.country) Mod-CF-Http-Version: http.request.version Mod-CF-Is-Good-Bot: cf.client.bot Mod-CF-Original-Host: http.host Mod-CF-Recieved-Timestamp: http.request.timestamp.sec Mod-CF-Recieved-Timestamp-Msec: http.request.timestamp.msec Mod-CF-Threat-Score: cf.threat_score
実際のヘッダー例
2021/10/25 に、この設定をして実際にサーバーで取得できた情報です。 ブラウザが送信したヘッダは除いています。 xxxx や example の部分は伏せてます。
CDN-Loop: cloudflare CF-Connecting-IP: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx CF-IPCountry: JP CF-Ray: 6a34abf38fdc0a66-KIX CF-Visitor: {"scheme":"http"} Mod-CF-ASN: xxxx Mod-CF-Client-Port: 58846 Mod-CF-Client-Trust-Score: 90 Mod-CF-Geo: continent=AS; country=JP Mod-CF-Http-Version: HTTP/3 Mod-CF-Is-Good-Bot: false Mod-CF-Original-Host: xxxx.example.com Mod-CF-Recieved-Timestamp-Msec: 10 Mod-CF-Recieved-Timestamp: 1635093886 Mod-CF-Threat-Score: 0 X-Forwarded-For: xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx X-Forwarded-Proto: http
注意点
Freeプランだと、URLリライトとヘッダーの修正で合わせて2→10枠まで
2021/12/05時点で10枠になってました!!
まだドキュメントでは2枠のままなので、正式な変更なのかわかりませんが…
以下古い記述です:
2枠埋まっていると新規作成ができません。 ルールを無効化しても枠が減らないので、複数のルールで運用したい場合かなりつらいです。
ページルールのように枠を買うこともできません。
Proプランにすると5枠に増えますが、このためだけに$20/月はなかなか払えないと思います…
枠数が少ない中でやりくりしていると、間違ってルールを消してしまう可能性も高まります。
該当するヘッダーの行が無くても不具合が起こらないよう実装しましょう。
Cloudflare Workers で再度同じドメインに fetch する場合、 クライアントでなく Workers の情報が入る
変換ルールの適用条件を絞る、 Workers 側でヘッダを弄るなどで対応しましょう。
そのほか
- Cloudflare Workers 単体では出来ないようです
- IncomingRequestCfProperties (request.cf) に送信元ポート番号がない
- 10年ぶりくらいにブログ書いた… (この名義では初めて)
*1: 方法は 「サーバーソフトウェア名 x-forwarded-for ログ」 などでググれば出ます