パスを受け持つ
セッションは、パスを一つずつ出す代わりに、プレフィックスを受け持てます。その下のパスを読む人には、そのセッションが答え、読まれている間そのパスのブロードキャストを作ります。Tablebox のプログラムはこの仕組みで動き、アプリやバックエンドも同じようにして自分のプログラムを書けます。
プレフィックスを受け持つ
serve(prefix, handler) は、prefix とその下のすべてのパスを受け持ちます。セッションの publish のパターンが prefix を覆っている必要があります。ハンドラーは、読まれているパスごとに一度、request.path を持って呼ばれ、返した promise が決まる前に答えます。
request.accept(broadcast): トラックを自分で書く公式のブロードキャストで答える。request.refuse(name): 下のコードのどれかで断る。読み手のトラックはそのコードで終わる。
例外を投げたり、答えずに終わったりしたハンドラーは failed で断ります。serve は { close() } を返し、これでプレフィックスを取り下げます。
// Serves every path under clock/: clock/Asia/Tokyo gives a track, time, with the time there every second.
import { connect, moq } from 'tablebox.io';
import { relay } from './relay.ts';
import { sign } from './token.ts';
const connection = await connect({ ...relay, getToken: () => sign('clock', { publish: ['clock/**'] }) });
connection.serve('clock', request => {
const zone = request.path.slice('clock/'.length);
if (!Intl.supportedValuesOf('timeZone').includes(zone)) return request.refuse('bad-request');
const broadcast = new moq.Broadcast.Producer();
const time = broadcast.createTrack('time');
const timer = setInterval(() => time.writeString(new Date().toLocaleTimeString('en', { timeZone: zone })), 1_000);
request.accept(broadcast);
// Once nobody reads it, end it; the next read calls this again.
void (async () => {
while (!time.used.peek()) await time.used.changed();
await time.unused();
clearInterval(timer);
time.close();
broadcast.close();
})();
});需要
受け持ったパスは、読まれている間続きます。ハンドラーは、トラックがもう読まれていないことを、そのトラックの公式の需要 track.used と track.unused() で知り、ブロードキャストを閉じます。次にそのパスが読まれると、ハンドラーがまた呼ばれます。
コード
パスを受け持つものは、Tablebox のプログラムも含めて、依頼やトラックを次のコードで断ります。
| コード | 名前 | 意味 |
|---|---|---|
| 80 | bad-request |
パスか入力が、そこで受け持つものに合わない |
| 81 | missing-variable |
依頼に要るプロジェクトの環境変数がない |
| 82 | failed |
受け持つ側が試したができなかった(ストレージ、プロバイダ、送り先) |
| 83 | too-large |
結果が受け持つ側の大きさの上限を超える |
読み手に届くのはコードとその名前で、文は届きません。もっと伝えたいプログラムは、状態のトラックに出します(Tablebox のプログラム)。いまは Node から断ると、@moq/web-transport 0.1.5 がストリームを 0 でリセットするので、読み手にはコード 0 の内部エラーとして届きます。ブラウザーと Rust からはコードが届きます。
複数で受け持つ
一つのプレフィックスを複数のセッションが受け持つと、Relay が一つでも複数でも、各読み出しはそのどれか一つに届きます。受け持っていたものが去ると、その読み出しは終わり、新しい読み出しは別のものに届きます。Tablebox のプログラムは、グループの番号を始めた時刻(Unix エポックからのミリ秒)から作り、読み直した読み手が前に受け取ったものの続きを受け取れるようにしています。
Rust
serve(prefix, handler) は、読まれたパスごとに、ハンドラーをそれぞれのタスクで呼びます。request.accept(&broadcast) か request.refuse(Reason::BadRequest) で答え、答えずに捨てた依頼は failed で断ります。ハンドラーは求められたトラックを公式の broadcast.dynamic() で渡し、パスがもう読まれていないことを broadcast.demand().unused() で知ります。受け持ちは、返された Serving がある間続きます。