Getting Started
rx-nostr の構造を理解するためには中心となる 3 種類の登場人物について知る必要があります。 それはRxReq
, RxNostr
とあなたのアプリケーションです。rx-nostr の世界ではこれら 3 種類の登場人物の間を RxReq -> RxNostr -> Your Application
の単方向に Packet と呼ばれるデータが流れます。実際のコードを見る前に、まずは RxReq
と RxNostr
が一体何者であるのかを確認しましょう。
RxReq
RxReq
は REQ メッセージ を組み立てるために必要な情報 (ReqPacket
) を RxNostr
に送出するオブジェクトです。あなたは RxReq
が提供するインターフェースを通じて、間接的に REQ を発行することができます。ここで、RxReq
はあくまで REQ メッセージに必要な情報を提供するだけで、リレーとの交信を行うのは次に説明する RxNostr
の役目であることに注意してください。
Note
RxReq
は createRxForwardReq()
か createRxBackwardReq()
によって生成します。 両者の違いは Subscribe EVENT を参照してください。
RxNostr
RxNostr
は受け取った ReqPacket
をもとにリレーとの間に REQ サブスクリプションを確立し、これを管理するオブジェクトです。あなたは RxNostr
が提供するインターフェースを通じて、EVENT メッセージをはじめとしたリレーからもたらされる各種の情報を Packet として受け取ることができます。
なお、RxNostr
はひとつのリレープールと関連づいています。言い換えると、同じ RxNostr
インスタンスの上では同一のリレーとの通信はすべてひとつの WebSocket 接続にまとめあげられ、逆に、異なるインスタンスの間では同一リレーに対しても異なる WebSocket 接続が確立されるということです。
Note
RxNostr
は createRxNostr()
によって生成します。
First Example
全体の流れを眺めたところで、早速最小の Nostr アプリケーションを構築してみましょう!まずは RxNostr
オブジェクトを生成して、リレープールと関連付けます。 このとき verifier
が必須のパラメータであることに注意してください。 ほとんどの場合、rx-nostr-crypto が公開している verifier
を使えば十分ですが、より高度なカスタマイズが必要な場合は Verifier を参照してください。
import { createRxNostr } from "rx-nostr";
import { verifier } from "rx-nostr-crypto";
const rxNostr = createRxNostr({ verifier });
rxNostr.setDefaultRelays([
"wss://relay1.example.com",
"wss://relay2.example.com",
]);
次に RxReq
オブジェクトを生成して、RxNostr
と関連付けます。これで RxReq
から RxNostr
に ReqPacket
を送出する準備が整いました。
import { createRxNostr, createRxForwardReq } from "rx-nostr";
import { verifier } from "rx-nostr-crypto";
const rxNostr = createRxNostr();
rxNostr.setDefaultRelays([
"wss://relay1.example.com",
"wss://relay2.example.com",
]);
const rxReq = createRxForwardReq();
rxNostr.use(rxReq);
rxNostr.use()
の返り値は subscribe()
可能なオブジェクトです。REQ の結果として得られる EventPacket
をここで受け取ることができます。つまり、以下のハイライト部分が RxReq -> RxNostr -> Your Application
フローにおける Your Application
相当の部分です。
import { createRxNostr, createRxForwardReq } from "rx-nostr";
import { verifier } from "rx-nostr-crypto";
const rxNostr = createRxNostr();
rxNostr.setDefaultRelays([
"wss://relay1.example.com",
"wss://relay2.example.com",
]);
const rxReq = createRxForwardReq();
rxNostr.use(rxReq).subscribe((packet) => {
// これがあなたのアプリケーションです!
console.log(packet);
});
RxJS Tips
use()
の返り値は厳密には RxJS の Observable
ですが、それについて知っておくことは必須ではありません。しかし、RxJS に親しんでいる開発者であれば RxJS の資産との連携が可能です。
しかしこのアプリケーションはまだ何も仕事をしないでしょう。なぜなら Packet が流れてこないからです。そう、ReqPacket
を送出しなければなりませんね。
import { createRxNostr, createRxForwardReq } from "rx-nostr";
import { verifier } from "rx-nostr-crypto";
const rxNostr = createRxNostr();
rxNostr.setDefaultRelays([
"wss://relay1.example.com",
"wss://relay2.example.com",
]);
const rxReq = createRxForwardReq();
rxNostr.use(rxReq).subscribe((packet) => {
// これがあなたのアプリケーションです!
console.log(packet);
});
// kind1 event を待ち受けるために REQ メッセージを発行します。
rxReq.emit({ kinds: [1] });
17, 18 行目を追加しました。さほど不思議なコードではないはずです。 これによって、RxReq
は RxNostr
に向かって ReqPacket
をひとつ送出します。RxNostr
は受け取った Packet をもとに REQ サブスクリプションを確立・購読し、購読されたイベントが 13 行目で消費されることになるでしょう。おめでとうございます!タイムラインを表示するアプリケーションの完成です!
ただ、最後にひと仕事だけ残っています。このままでは購読は永遠に続くので、CLOSE メッセージを送出しなければなりません。
rx-nostr では subscribe()
の結果を unsubscribe()
することによって、use()
で関連づいている REQ をすべて CLOSE することができます。少し不格好ですがここでは 10 秒後に CLOSE する、ということにしましょう。次のようにコードを追加します。
import { createRxNostr, createRxForwardReq } from "rx-nostr";
import { verifier } from "rx-nostr-crypto";
const rxNostr = createRxNostr();
rxNostr.setDefaultRelays([
"wss://relay1.example.com",
"wss://relay2.example.com",
]);
const rxReq = createRxForwardReq();
const subscription = rxNostr.use(rxReq).subscribe((packet) => {
// これがあなたのアプリケーションです!
console.log(packet);
});
// kind1 event を待ち受けるために REQ メッセージを発行します。
rxReq.emit({ kinds: [1] });
// 10 秒後に CLOSE メッセージを送信します。
setTimeout(() => {
subscription.unsubscribe();
}, 10 * 1000);
完璧です!