@norskvideo/moq-net 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/announced.d.ts +45 -0
- package/announced.d.ts.map +1 -0
- package/announced.js +70 -0
- package/announced.js.map +1 -0
- package/bandwidth.d.ts +11 -0
- package/bandwidth.d.ts.map +1 -0
- package/bandwidth.js +7 -0
- package/bandwidth.js.map +1 -0
- package/broadcast.d.ts +39 -0
- package/broadcast.d.ts.map +1 -0
- package/broadcast.js +76 -0
- package/broadcast.js.map +1 -0
- package/connection/accept.d.ts +15 -0
- package/connection/accept.d.ts.map +1 -0
- package/connection/accept.js +137 -0
- package/connection/accept.js.map +1 -0
- package/connection/cert.test.d.ts +2 -0
- package/connection/cert.test.d.ts.map +1 -0
- package/connection/cert.test.js +26 -0
- package/connection/cert.test.js.map +1 -0
- package/connection/connect.d.ts +37 -0
- package/connection/connect.d.ts.map +1 -0
- package/connection/connect.js +348 -0
- package/connection/connect.js.map +1 -0
- package/connection/established.d.ts +30 -0
- package/connection/established.d.ts.map +1 -0
- package/connection/established.js +3 -0
- package/connection/established.js.map +1 -0
- package/connection/handshake.d.ts +10 -0
- package/connection/handshake.d.ts.map +1 -0
- package/connection/handshake.js +48 -0
- package/connection/handshake.js.map +1 -0
- package/connection/index.d.ts +5 -0
- package/connection/index.d.ts.map +1 -0
- package/connection/index.js +6 -0
- package/connection/index.js.map +1 -0
- package/connection/reload.d.ts +47 -0
- package/connection/reload.d.ts.map +1 -0
- package/connection/reload.js +137 -0
- package/connection/reload.js.map +1 -0
- package/group.d.ts +66 -0
- package/group.d.ts.map +1 -0
- package/group.js +135 -0
- package/group.js.map +1 -0
- package/group.test.d.ts +2 -0
- package/group.test.d.ts.map +1 -0
- package/group.test.js +66 -0
- package/group.test.js.map +1 -0
- package/ietf/adapter.d.ts +65 -0
- package/ietf/adapter.d.ts.map +1 -0
- package/ietf/adapter.js +626 -0
- package/ietf/adapter.js.map +1 -0
- package/ietf/connection.d.ts +65 -0
- package/ietf/connection.d.ts.map +1 -0
- package/ietf/connection.js +248 -0
- package/ietf/connection.js.map +1 -0
- package/ietf/control.d.ts +135 -0
- package/ietf/control.d.ts.map +1 -0
- package/ietf/control.js +242 -0
- package/ietf/control.js.map +1 -0
- package/ietf/fetch.d.ts +64 -0
- package/ietf/fetch.d.ts.map +1 -0
- package/ietf/fetch.js +100 -0
- package/ietf/fetch.js.map +1 -0
- package/ietf/goaway.d.ts +15 -0
- package/ietf/goaway.d.ts.map +1 -0
- package/ietf/goaway.js +34 -0
- package/ietf/goaway.js.map +1 -0
- package/ietf/ietf.test.d.ts +2 -0
- package/ietf/ietf.test.d.ts.map +1 -0
- package/ietf/ietf.test.js +873 -0
- package/ietf/ietf.test.js.map +1 -0
- package/ietf/index.d.ts +18 -0
- package/ietf/index.d.ts.map +1 -0
- package/ietf/index.js +19 -0
- package/ietf/index.js.map +1 -0
- package/ietf/message.d.ts +4 -0
- package/ietf/message.d.ts.map +1 -0
- package/ietf/message.js +54 -0
- package/ietf/message.js.map +1 -0
- package/ietf/namespace.d.ts +5 -0
- package/ietf/namespace.d.ts.map +1 -0
- package/ietf/namespace.js +27 -0
- package/ietf/namespace.js.map +1 -0
- package/ietf/object.d.ts +40 -0
- package/ietf/object.d.ts.map +1 -0
- package/ietf/object.js +160 -0
- package/ietf/object.js.map +1 -0
- package/ietf/parameters.d.ts +56 -0
- package/ietf/parameters.d.ts.map +1 -0
- package/ietf/parameters.js +337 -0
- package/ietf/parameters.js.map +1 -0
- package/ietf/properties.d.ts +4 -0
- package/ietf/properties.d.ts.map +1 -0
- package/ietf/properties.js +33 -0
- package/ietf/properties.js.map +1 -0
- package/ietf/publish.d.ts +68 -0
- package/ietf/publish.d.ts.map +1 -0
- package/ietf/publish.js +192 -0
- package/ietf/publish.js.map +1 -0
- package/ietf/publish_namespace.d.ts +68 -0
- package/ietf/publish_namespace.d.ts.map +1 -0
- package/ietf/publish_namespace.js +176 -0
- package/ietf/publish_namespace.js.map +1 -0
- package/ietf/publisher.d.ts +50 -0
- package/ietf/publisher.d.ts.map +1 -0
- package/ietf/publisher.js +330 -0
- package/ietf/publisher.js.map +1 -0
- package/ietf/request.d.ts +52 -0
- package/ietf/request.d.ts.map +1 -0
- package/ietf/request.js +119 -0
- package/ietf/request.js.map +1 -0
- package/ietf/setup.d.ts +38 -0
- package/ietf/setup.d.ts.map +1 -0
- package/ietf/setup.js +129 -0
- package/ietf/setup.js.map +1 -0
- package/ietf/subscribe.d.ts +66 -0
- package/ietf/subscribe.d.ts.map +1 -0
- package/ietf/subscribe.js +276 -0
- package/ietf/subscribe.js.map +1 -0
- package/ietf/subscribe_namespace.d.ts +101 -0
- package/ietf/subscribe_namespace.d.ts.map +1 -0
- package/ietf/subscribe_namespace.js +256 -0
- package/ietf/subscribe_namespace.js.map +1 -0
- package/ietf/subscriber.d.ts +53 -0
- package/ietf/subscriber.d.ts.map +1 -0
- package/ietf/subscriber.js +404 -0
- package/ietf/subscriber.js.map +1 -0
- package/ietf/track.d.ts +40 -0
- package/ietf/track.d.ts.map +1 -0
- package/ietf/track.js +108 -0
- package/ietf/track.js.map +1 -0
- package/ietf/version.d.ts +56 -0
- package/ietf/version.d.ts.map +1 -0
- package/ietf/version.js +63 -0
- package/ietf/version.js.map +1 -0
- package/index.d.ts +22 -0
- package/index.d.ts.map +1 -0
- package/index.js +23 -0
- package/index.js.map +1 -0
- package/integration.test.d.ts +2 -0
- package/integration.test.d.ts.map +1 -0
- package/integration.test.js +90 -0
- package/integration.test.js.map +1 -0
- package/lite/announce.d.ts +35 -0
- package/lite/announce.d.ts.map +1 -0
- package/lite/announce.js +166 -0
- package/lite/announce.js.map +1 -0
- package/lite/connection.d.ts +47 -0
- package/lite/connection.d.ts.map +1 -0
- package/lite/connection.js +247 -0
- package/lite/connection.js.map +1 -0
- package/lite/fetch.d.ts +14 -0
- package/lite/fetch.d.ts.map +1 -0
- package/lite/fetch.js +47 -0
- package/lite/fetch.js.map +1 -0
- package/lite/goaway.d.ts +10 -0
- package/lite/goaway.d.ts.map +1 -0
- package/lite/goaway.js +37 -0
- package/lite/goaway.js.map +1 -0
- package/lite/group.d.ts +18 -0
- package/lite/group.d.ts.map +1 -0
- package/lite/group.js +46 -0
- package/lite/group.js.map +1 -0
- package/lite/index.d.ts +11 -0
- package/lite/index.d.ts.map +1 -0
- package/lite/index.js +12 -0
- package/lite/index.js.map +1 -0
- package/lite/message.d.ts +5 -0
- package/lite/message.d.ts.map +1 -0
- package/lite/message.js +51 -0
- package/lite/message.js.map +1 -0
- package/lite/origin.d.ts +25 -0
- package/lite/origin.d.ts.map +1 -0
- package/lite/origin.js +35 -0
- package/lite/origin.js.map +1 -0
- package/lite/probe.d.ts +12 -0
- package/lite/probe.d.ts.map +1 -0
- package/lite/probe.js +60 -0
- package/lite/probe.js.map +1 -0
- package/lite/publisher.d.ts +63 -0
- package/lite/publisher.d.ts.map +1 -0
- package/lite/publisher.js +350 -0
- package/lite/publisher.js.map +1 -0
- package/lite/session.d.ts +36 -0
- package/lite/session.d.ts.map +1 -0
- package/lite/session.js +130 -0
- package/lite/session.js.map +1 -0
- package/lite/setup.d.ts +18 -0
- package/lite/setup.d.ts.map +1 -0
- package/lite/setup.js +55 -0
- package/lite/setup.js.map +1 -0
- package/lite/stream.d.ts +23 -0
- package/lite/stream.d.ts.map +1 -0
- package/lite/stream.js +20 -0
- package/lite/stream.js.map +1 -0
- package/lite/subscribe.d.ts +111 -0
- package/lite/subscribe.d.ts.map +1 -0
- package/lite/subscribe.js +341 -0
- package/lite/subscribe.js.map +1 -0
- package/lite/subscriber.d.ts +80 -0
- package/lite/subscriber.d.ts.map +1 -0
- package/lite/subscriber.js +316 -0
- package/lite/subscriber.js.map +1 -0
- package/lite/track.d.ts +38 -0
- package/lite/track.d.ts.map +1 -0
- package/lite/track.js +81 -0
- package/lite/track.js.map +1 -0
- package/lite/track.test.d.ts +2 -0
- package/lite/track.test.d.ts.map +1 -0
- package/lite/track.test.js +53 -0
- package/lite/track.test.js.map +1 -0
- package/lite/version.d.ts +16 -0
- package/lite/version.d.ts.map +1 -0
- package/lite/version.js +41 -0
- package/lite/version.js.map +1 -0
- package/mock.d.ts +16 -0
- package/mock.d.ts.map +1 -0
- package/mock.js +154 -0
- package/mock.js.map +1 -0
- package/package.json +27 -0
- package/path.d.ts +111 -0
- package/path.d.ts.map +1 -0
- package/path.js +133 -0
- package/path.js.map +1 -0
- package/path.test.d.ts +2 -0
- package/path.test.d.ts.map +1 -0
- package/path.test.js +169 -0
- package/path.test.js.map +1 -0
- package/stream.d.ts +57 -0
- package/stream.d.ts.map +1 -0
- package/stream.js +326 -0
- package/stream.js.map +1 -0
- package/stream.test.d.ts +2 -0
- package/stream.test.d.ts.map +1 -0
- package/stream.test.js +210 -0
- package/stream.test.js.map +1 -0
- package/time.d.ts +109 -0
- package/time.d.ts.map +1 -0
- package/time.js +94 -0
- package/time.js.map +1 -0
- package/track.d.ts +85 -0
- package/track.d.ts.map +1 -0
- package/track.js +227 -0
- package/track.js.map +1 -0
- package/track.test.d.ts +2 -0
- package/track.test.d.ts.map +1 -0
- package/track.test.js +56 -0
- package/track.test.js.map +1 -0
- package/util/error.d.ts +3 -0
- package/util/error.d.ts.map +1 -0
- package/util/error.js +9 -0
- package/util/error.js.map +1 -0
- package/util/hex.d.ts +3 -0
- package/util/hex.d.ts.map +1 -0
- package/util/hex.js +16 -0
- package/util/hex.js.map +1 -0
- package/util/index.d.ts +2 -0
- package/util/index.d.ts.map +1 -0
- package/util/index.js +3 -0
- package/util/index.js.map +1 -0
- package/varint.d.ts +36 -0
- package/varint.d.ts.map +1 -0
- package/varint.js +288 -0
- package/varint.js.map +1 -0
- package/varint.test.d.ts +2 -0
- package/varint.test.d.ts.map +1 -0
- package/varint.test.js +106 -0
- package/varint.test.js.map +1 -0
- package/zod.d.ts +13 -0
- package/zod.d.ts.map +1 -0
- package/zod.js +19 -0
- package/zod.js.map +1 -0
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/* @ts-self-types="./subscriber.d.ts" */
|
|
2
|
+
import { Announced } from "../announced.js";
|
|
3
|
+
import { Broadcast } from "../broadcast.js";
|
|
4
|
+
import { Group } from "../group.js";
|
|
5
|
+
import * as Path from "../path.js";
|
|
6
|
+
import { error } from "../util/error.js";
|
|
7
|
+
import { Frame } from "./object.js";
|
|
8
|
+
import { PublishError } from "./publish.js";
|
|
9
|
+
import { PublishNamespaceError, PublishNamespaceOk } from "./publish_namespace.js";
|
|
10
|
+
import { RequestError, RequestOk } from "./request.js";
|
|
11
|
+
import { Subscribe, SubscribeError, SubscribeOk, Unsubscribe } from "./subscribe.js";
|
|
12
|
+
import { PublishBlocked, SubscribeNamespace, SubscribeNamespaceEntry, SubscribeNamespaceEntryDone, SubscribeNamespaceLegacy, SubscribeNamespaceOk, UnsubscribeNamespace, } from "./subscribe_namespace.js";
|
|
13
|
+
import { Version } from "./version.js";
|
|
14
|
+
/**
|
|
15
|
+
* Handles subscribing to broadcasts using moq-transport protocol.
|
|
16
|
+
* Uses the stream-per-request pattern (real bidi streams for v17, virtual for v14-v16).
|
|
17
|
+
*
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export class Subscriber {
|
|
21
|
+
#session;
|
|
22
|
+
// Our subscribed tracks — keyed by trackAlias for group routing
|
|
23
|
+
#subscribes = new Map();
|
|
24
|
+
// Any currently active announcements.
|
|
25
|
+
#announced = new Set();
|
|
26
|
+
// Any consumers that want each new announcement.
|
|
27
|
+
#announcedConsumers = new Set();
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new Subscriber instance.
|
|
30
|
+
* @param session - The session abstraction for bidi streams and request IDs
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
constructor(session) {
|
|
35
|
+
this.#session = session;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Gets an announced reader for the specified prefix.
|
|
39
|
+
*/
|
|
40
|
+
announced(prefix = Path.empty()) {
|
|
41
|
+
const announced = new Announced(prefix);
|
|
42
|
+
for (const active of this.#announced) {
|
|
43
|
+
if (!Path.hasPrefix(prefix, active))
|
|
44
|
+
continue;
|
|
45
|
+
announced.append({ path: active, active: true });
|
|
46
|
+
}
|
|
47
|
+
this.#announcedConsumers.add(announced);
|
|
48
|
+
void this.#runAnnounced(announced, prefix).finally(() => {
|
|
49
|
+
this.#announcedConsumers.delete(announced);
|
|
50
|
+
announced.close();
|
|
51
|
+
});
|
|
52
|
+
return announced;
|
|
53
|
+
}
|
|
54
|
+
async #runAnnounced(announced, prefix) {
|
|
55
|
+
const version = this.#session.version;
|
|
56
|
+
// v14/v15: SubscribeNamespace on control stream (via adapter virtual stream)
|
|
57
|
+
// v16+: SubscribeNamespace on its own real bidi stream
|
|
58
|
+
const requestId = await this.#session.nextRequestId();
|
|
59
|
+
if (requestId === undefined)
|
|
60
|
+
return;
|
|
61
|
+
try {
|
|
62
|
+
// v16: use a real bidi stream (not virtual control stream)
|
|
63
|
+
const stream = version === Version.DRAFT_16 && this.#session.openNativeBi
|
|
64
|
+
? await this.#session.openNativeBi()
|
|
65
|
+
: await this.#session.openBi();
|
|
66
|
+
try {
|
|
67
|
+
// Draft-18+ uses SUBSCRIBE_NAMESPACE (0x50); earlier drafts use the
|
|
68
|
+
// legacy 0x11 message with a Subscribe Options field.
|
|
69
|
+
if (version === Version.DRAFT_14 ||
|
|
70
|
+
version === Version.DRAFT_15 ||
|
|
71
|
+
version === Version.DRAFT_16 ||
|
|
72
|
+
version === Version.DRAFT_17) {
|
|
73
|
+
await stream.writer.u53(SubscribeNamespaceLegacy.id);
|
|
74
|
+
await new SubscribeNamespaceLegacy({ namespace: prefix, requestId }).encode(stream.writer, version);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
await stream.writer.u53(SubscribeNamespace.id);
|
|
78
|
+
await new SubscribeNamespace({ namespace: prefix, requestId }).encode(stream.writer, version);
|
|
79
|
+
}
|
|
80
|
+
console.debug(`subscribe_namespace written: requestId=${requestId}`);
|
|
81
|
+
// Read response
|
|
82
|
+
const respTypeId = await stream.reader.u53();
|
|
83
|
+
if (respTypeId === RequestOk.id) {
|
|
84
|
+
await RequestOk.decode(stream.reader, version);
|
|
85
|
+
}
|
|
86
|
+
else if (respTypeId === SubscribeNamespaceOk.id) {
|
|
87
|
+
// v14: SubscribeNamespaceOk
|
|
88
|
+
const size = await stream.reader.u16();
|
|
89
|
+
await stream.reader.read(size);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
throw new Error(`SubscribeNamespace rejected: typeId=0x${respTypeId.toString(16)}`);
|
|
93
|
+
}
|
|
94
|
+
// Loop reading Namespace/NamespaceDone entries
|
|
95
|
+
const readLoop = (async () => {
|
|
96
|
+
for (;;) {
|
|
97
|
+
const done = await stream.reader.done();
|
|
98
|
+
if (done)
|
|
99
|
+
break;
|
|
100
|
+
const msgType = await stream.reader.u53();
|
|
101
|
+
if (msgType === SubscribeNamespaceEntry.id) {
|
|
102
|
+
const entry = await SubscribeNamespaceEntry.decode(stream.reader, version);
|
|
103
|
+
const path = Path.join(prefix, entry.suffix);
|
|
104
|
+
console.debug(`announced: broadcast=${path} active=true`);
|
|
105
|
+
this.#announced.add(path);
|
|
106
|
+
for (const consumer of this.#announcedConsumers) {
|
|
107
|
+
if (!Path.hasPrefix(consumer.prefix, path))
|
|
108
|
+
continue;
|
|
109
|
+
consumer.append({ path, active: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (msgType === SubscribeNamespaceEntryDone.id) {
|
|
113
|
+
const entry = await SubscribeNamespaceEntryDone.decode(stream.reader, version);
|
|
114
|
+
const path = Path.join(prefix, entry.suffix);
|
|
115
|
+
console.debug(`announced: broadcast=${path} active=false`);
|
|
116
|
+
this.#announced.delete(path);
|
|
117
|
+
for (const consumer of this.#announcedConsumers) {
|
|
118
|
+
if (!Path.hasPrefix(consumer.prefix, path))
|
|
119
|
+
continue;
|
|
120
|
+
consumer.append({ path, active: false });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (msgType === PublishBlocked.id && version === Version.DRAFT_17) {
|
|
124
|
+
const blocked = await PublishBlocked.decode(stream.reader, version);
|
|
125
|
+
console.debug(`publish_blocked: suffix=${blocked.suffix} track=${blocked.trackName}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
throw new Error(`unexpected message on subscribe_namespace stream: 0x${msgType.toString(16)}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
})();
|
|
132
|
+
// Wait for either the read loop or the announced to close
|
|
133
|
+
await Promise.race([readLoop, announced.closed]);
|
|
134
|
+
// For v14/v15: send UnsubscribeNamespace before closing
|
|
135
|
+
if (version === Version.DRAFT_14 || version === Version.DRAFT_15) {
|
|
136
|
+
try {
|
|
137
|
+
await stream.writer.u53(UnsubscribeNamespace.id);
|
|
138
|
+
const unsub = new UnsubscribeNamespace({ requestId });
|
|
139
|
+
await unsub.encode(stream.writer, version);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Stream might already be closed
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
stream.close();
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
stream.abort(error(err));
|
|
149
|
+
throw err;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const e = error(err);
|
|
154
|
+
console.warn(`subscribe_namespace error: ${e.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Consumes a broadcast from the connection.
|
|
159
|
+
*/
|
|
160
|
+
consume(path) {
|
|
161
|
+
const broadcast = new Broadcast();
|
|
162
|
+
void (async () => {
|
|
163
|
+
for (;;) {
|
|
164
|
+
const request = await broadcast.requested();
|
|
165
|
+
if (!request)
|
|
166
|
+
break;
|
|
167
|
+
void this.#runSubscribe(path, request);
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
return broadcast;
|
|
171
|
+
}
|
|
172
|
+
async #runSubscribe(broadcast, request) {
|
|
173
|
+
const version = this.#session.version;
|
|
174
|
+
const requestId = await this.#session.nextRequestId();
|
|
175
|
+
if (requestId === undefined) {
|
|
176
|
+
request.track.close(new Error("session closed"));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
console.debug(`subscribe start: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
|
|
180
|
+
try {
|
|
181
|
+
const stream = await this.#session.openBi();
|
|
182
|
+
try {
|
|
183
|
+
// Write Subscribe
|
|
184
|
+
await stream.writer.u53(Subscribe.id);
|
|
185
|
+
const msg = new Subscribe({
|
|
186
|
+
requestId,
|
|
187
|
+
trackNamespace: broadcast,
|
|
188
|
+
trackName: request.track.name,
|
|
189
|
+
subscriberPriority: request.priority,
|
|
190
|
+
});
|
|
191
|
+
await msg.encode(stream.writer, version);
|
|
192
|
+
console.debug(`subscribe written: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
|
|
193
|
+
// Pre-register with requestId so early group uni streams aren't dropped.
|
|
194
|
+
// The publisher typically uses requestId as the trackAlias.
|
|
195
|
+
this.#subscribes.set(requestId, request.track);
|
|
196
|
+
// Read response (SubscribeOk or error)
|
|
197
|
+
const respTypeId = await stream.reader.u53();
|
|
198
|
+
if (respTypeId === SubscribeOk.id) {
|
|
199
|
+
const ok = await SubscribeOk.decode(stream.reader, version);
|
|
200
|
+
// Update registration to use the actual trackAlias from SubscribeOk
|
|
201
|
+
if (ok.trackAlias !== requestId) {
|
|
202
|
+
this.#subscribes.delete(requestId);
|
|
203
|
+
this.#subscribes.set(ok.trackAlias, request.track);
|
|
204
|
+
}
|
|
205
|
+
console.debug(`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
|
|
206
|
+
try {
|
|
207
|
+
// Wait for stream close (= PublishDone) or track close (= local unsubscribe)
|
|
208
|
+
await Promise.race([stream.reader.closed, request.track.closed]);
|
|
209
|
+
// For v14-v16: send Unsubscribe before closing (removed in v17+)
|
|
210
|
+
if (version === Version.DRAFT_14 ||
|
|
211
|
+
version === Version.DRAFT_15 ||
|
|
212
|
+
version === Version.DRAFT_16) {
|
|
213
|
+
try {
|
|
214
|
+
await stream.writer.u53(Unsubscribe.id);
|
|
215
|
+
const unsub = new Unsubscribe({ requestId });
|
|
216
|
+
await unsub.encode(stream.writer, version);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// Stream might already be closed
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
request.track.close();
|
|
223
|
+
stream.close();
|
|
224
|
+
console.debug(`subscribe close: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
this.#subscribes.delete(ok.trackAlias);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
// Clean up pre-registered entry on error
|
|
232
|
+
this.#subscribes.delete(requestId);
|
|
233
|
+
// Error response
|
|
234
|
+
let reasonPhrase = "unknown error";
|
|
235
|
+
try {
|
|
236
|
+
if (respTypeId === RequestError.id) {
|
|
237
|
+
// SubscribeError (v14) or RequestError (v15+)
|
|
238
|
+
const err = version === Version.DRAFT_14
|
|
239
|
+
? await SubscribeError.decode(stream.reader, version)
|
|
240
|
+
: await RequestError.decode(stream.reader, version);
|
|
241
|
+
reasonPhrase = `code=${err.errorCode} reason=${err.reasonPhrase}`;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch {
|
|
245
|
+
// Decoding error response failed, use default message
|
|
246
|
+
}
|
|
247
|
+
throw new Error(`SUBSCRIBE error: ${reasonPhrase}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
this.#subscribes.delete(requestId);
|
|
252
|
+
stream.abort(error(err));
|
|
253
|
+
throw err;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch (err) {
|
|
257
|
+
const e = error(err);
|
|
258
|
+
request.track.close(e);
|
|
259
|
+
console.warn(`subscribe error: id=${requestId} broadcast=${broadcast} track=${request.track.name} error=${e.message}`);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Handles an incoming PUBLISH_NAMESPACE on a bidi stream.
|
|
264
|
+
* Tracks announced broadcasts and notifies consumers.
|
|
265
|
+
*
|
|
266
|
+
* @internal
|
|
267
|
+
*/
|
|
268
|
+
async runPublishNamespace(msg, stream) {
|
|
269
|
+
const version = this.#session.version;
|
|
270
|
+
const path = msg.trackNamespace;
|
|
271
|
+
if (this.#announced.has(path)) {
|
|
272
|
+
console.warn("duplicate PublishNamespace");
|
|
273
|
+
if (version === Version.DRAFT_14) {
|
|
274
|
+
await stream.writer.u53(PublishNamespaceError.id);
|
|
275
|
+
const err = new PublishNamespaceError({
|
|
276
|
+
requestId: msg.requestId,
|
|
277
|
+
errorCode: 409,
|
|
278
|
+
reasonPhrase: "duplicate namespace",
|
|
279
|
+
});
|
|
280
|
+
await err.encode(stream.writer, version);
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
await stream.writer.u53(RequestError.id);
|
|
284
|
+
const err = new RequestError({
|
|
285
|
+
requestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,
|
|
286
|
+
errorCode: 409,
|
|
287
|
+
reasonPhrase: "duplicate namespace",
|
|
288
|
+
});
|
|
289
|
+
await err.encode(stream.writer, version);
|
|
290
|
+
}
|
|
291
|
+
stream.close();
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
this.#announced.add(path);
|
|
295
|
+
try {
|
|
296
|
+
// Send OK first — must complete before notifying consumers,
|
|
297
|
+
// because consumers may trigger Subscribe writes that would
|
|
298
|
+
// interleave with our OK on the control stream.
|
|
299
|
+
if (version === Version.DRAFT_14) {
|
|
300
|
+
await stream.writer.u53(PublishNamespaceOk.id);
|
|
301
|
+
const ok = new PublishNamespaceOk({ requestId: msg.requestId });
|
|
302
|
+
await ok.encode(stream.writer, version);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
await stream.writer.u53(RequestOk.id);
|
|
306
|
+
const ok = new RequestOk({
|
|
307
|
+
requestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,
|
|
308
|
+
});
|
|
309
|
+
await ok.encode(stream.writer, version);
|
|
310
|
+
}
|
|
311
|
+
console.debug(`announced: broadcast=${path} active=true`);
|
|
312
|
+
// Notify consumers after OK is written
|
|
313
|
+
for (const consumer of this.#announcedConsumers) {
|
|
314
|
+
const suffix = Path.stripPrefix(consumer.prefix, path);
|
|
315
|
+
if (suffix === null)
|
|
316
|
+
continue;
|
|
317
|
+
consumer.append({ path, active: true });
|
|
318
|
+
}
|
|
319
|
+
// Wait for stream close (= PublishNamespaceDone)
|
|
320
|
+
console.debug(`runPublishNamespace: awaiting stream.reader.closed for ${path}`);
|
|
321
|
+
await stream.reader.closed;
|
|
322
|
+
console.debug(`runPublishNamespace: stream.reader.closed resolved for ${path}`);
|
|
323
|
+
}
|
|
324
|
+
finally {
|
|
325
|
+
this.#announced.delete(path);
|
|
326
|
+
console.debug(`announced: broadcast=${path} active=false`);
|
|
327
|
+
for (const consumer of this.#announcedConsumers) {
|
|
328
|
+
const suffix = Path.stripPrefix(consumer.prefix, path);
|
|
329
|
+
if (suffix === null)
|
|
330
|
+
continue;
|
|
331
|
+
try {
|
|
332
|
+
consumer.append({ path, active: false });
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// Consumer already closed, will be cleaned up
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Handles an incoming PUBLISH on a bidi stream.
|
|
342
|
+
* We don't support reverse publish, so send error.
|
|
343
|
+
*
|
|
344
|
+
* @internal
|
|
345
|
+
*/
|
|
346
|
+
async runPublish(msg, stream) {
|
|
347
|
+
const version = this.#session.version;
|
|
348
|
+
if (version === Version.DRAFT_14) {
|
|
349
|
+
await stream.writer.u53(PublishError.id);
|
|
350
|
+
const err = new PublishError({
|
|
351
|
+
requestId: msg.requestId,
|
|
352
|
+
errorCode: 500,
|
|
353
|
+
reasonPhrase: "publish not supported",
|
|
354
|
+
});
|
|
355
|
+
await err.encode(stream.writer, version);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
await stream.writer.u53(RequestError.id);
|
|
359
|
+
const err = new RequestError({
|
|
360
|
+
requestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,
|
|
361
|
+
errorCode: 500,
|
|
362
|
+
reasonPhrase: "publish not supported",
|
|
363
|
+
});
|
|
364
|
+
await err.encode(stream.writer, version);
|
|
365
|
+
}
|
|
366
|
+
stream.close();
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Handles an ObjectStream message (group + frames on uni stream).
|
|
370
|
+
*
|
|
371
|
+
* @internal
|
|
372
|
+
*/
|
|
373
|
+
async handleGroup(group, stream) {
|
|
374
|
+
const producer = new Group(group.groupId);
|
|
375
|
+
if (group.subGroupId !== 0) {
|
|
376
|
+
throw new Error("subgroups are not supported");
|
|
377
|
+
}
|
|
378
|
+
try {
|
|
379
|
+
// Look up by trackAlias directly
|
|
380
|
+
const track = this.#subscribes.get(group.trackAlias);
|
|
381
|
+
if (!track) {
|
|
382
|
+
// Fallback: try treating trackAlias as requestId (for compat)
|
|
383
|
+
throw new Error(`unknown track: trackAlias=${group.trackAlias}`);
|
|
384
|
+
}
|
|
385
|
+
track.writeGroup(producer);
|
|
386
|
+
for (;;) {
|
|
387
|
+
const done = await Promise.race([stream.done(), producer.closed, track.closed]);
|
|
388
|
+
if (done !== false)
|
|
389
|
+
break;
|
|
390
|
+
const frame = await Frame.decode(stream, group.flags);
|
|
391
|
+
if (frame.payload === undefined)
|
|
392
|
+
break;
|
|
393
|
+
producer.writeFrame(frame.payload, frame.extensions);
|
|
394
|
+
}
|
|
395
|
+
producer.close();
|
|
396
|
+
}
|
|
397
|
+
catch (err) {
|
|
398
|
+
const e = error(err);
|
|
399
|
+
producer.close(e);
|
|
400
|
+
stream.stop(e);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
//# sourceMappingURL=subscriber.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../../src/ietf/subscriber.ts"],"names":[],"mappings":"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","sourcesContent":["import { Announced } from \"../announced.ts\";\nimport { Broadcast, type TrackRequest } from \"../broadcast.ts\";\nimport { Group } from \"../group.ts\";\nimport * as Path from \"../path.ts\";\nimport type { Reader, Stream } from \"../stream.ts\";\nimport type { Track } from \"../track.ts\";\nimport { error } from \"../util/error.ts\";\nimport type { Session } from \"./adapter.ts\";\nimport { Frame, type Group as GroupMessage } from \"./object.ts\";\nimport { type Publish, PublishError } from \"./publish.ts\";\nimport { type PublishNamespace, PublishNamespaceError, PublishNamespaceOk } from \"./publish_namespace.ts\";\nimport { RequestError, RequestOk } from \"./request.ts\";\nimport { Subscribe, SubscribeError, SubscribeOk, Unsubscribe } from \"./subscribe.ts\";\nimport {\n\tPublishBlocked,\n\tSubscribeNamespace,\n\tSubscribeNamespaceEntry,\n\tSubscribeNamespaceEntryDone,\n\tSubscribeNamespaceLegacy,\n\tSubscribeNamespaceOk,\n\tUnsubscribeNamespace,\n} from \"./subscribe_namespace.ts\";\nimport { Version } from \"./version.ts\";\n\n/**\n * Handles subscribing to broadcasts using moq-transport protocol.\n * Uses the stream-per-request pattern (real bidi streams for v17, virtual for v14-v16).\n *\n * @internal\n */\nexport class Subscriber {\n\t#session: Session;\n\n\t// Our subscribed tracks — keyed by trackAlias for group routing\n\t#subscribes = new Map<bigint, Track>();\n\n\t// Any currently active announcements.\n\t#announced = new Set<Path.Valid>();\n\n\t// Any consumers that want each new announcement.\n\t#announcedConsumers = new Set<Announced>();\n\n\t/**\n\t * Creates a new Subscriber instance.\n\t * @param session - The session abstraction for bidi streams and request IDs\n\t *\n\t * @internal\n\t */\n\tconstructor(session: Session) {\n\t\tthis.#session = session;\n\t}\n\n\t/**\n\t * Gets an announced reader for the specified prefix.\n\t */\n\tannounced(prefix = Path.empty()): Announced {\n\t\tconst announced = new Announced(prefix);\n\t\tfor (const active of this.#announced) {\n\t\t\tif (!Path.hasPrefix(prefix, active)) continue;\n\t\t\tannounced.append({ path: active, active: true });\n\t\t}\n\t\tthis.#announcedConsumers.add(announced);\n\n\t\tvoid this.#runAnnounced(announced, prefix).finally(() => {\n\t\t\tthis.#announcedConsumers.delete(announced);\n\t\t\tannounced.close();\n\t\t});\n\n\t\treturn announced;\n\t}\n\n\tasync #runAnnounced(announced: Announced, prefix: Path.Valid) {\n\t\tconst version = this.#session.version;\n\n\t\t// v14/v15: SubscribeNamespace on control stream (via adapter virtual stream)\n\t\t// v16+: SubscribeNamespace on its own real bidi stream\n\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) return;\n\n\t\ttry {\n\t\t\t// v16: use a real bidi stream (not virtual control stream)\n\t\t\tconst stream =\n\t\t\t\tversion === Version.DRAFT_16 && this.#session.openNativeBi\n\t\t\t\t\t? await this.#session.openNativeBi()\n\t\t\t\t\t: await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Draft-18+ uses SUBSCRIBE_NAMESPACE (0x50); earlier drafts use the\n\t\t\t\t// legacy 0x11 message with a Subscribe Options field.\n\t\t\t\tif (\n\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\tversion === Version.DRAFT_16 ||\n\t\t\t\t\tversion === Version.DRAFT_17\n\t\t\t\t) {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespaceLegacy.id);\n\t\t\t\t\tawait new SubscribeNamespaceLegacy({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t} else {\n\t\t\t\t\tawait stream.writer.u53(SubscribeNamespace.id);\n\t\t\t\t\tawait new SubscribeNamespace({ namespace: prefix, requestId }).encode(stream.writer, version);\n\t\t\t\t}\n\t\t\t\tconsole.debug(`subscribe_namespace written: requestId=${requestId}`);\n\n\t\t\t\t// Read response\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === RequestOk.id) {\n\t\t\t\t\tawait RequestOk.decode(stream.reader, version);\n\t\t\t\t} else if (respTypeId === SubscribeNamespaceOk.id) {\n\t\t\t\t\t// v14: SubscribeNamespaceOk\n\t\t\t\t\tconst size = await stream.reader.u16();\n\t\t\t\t\tawait stream.reader.read(size);\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error(`SubscribeNamespace rejected: typeId=0x${respTypeId.toString(16)}`);\n\t\t\t\t}\n\n\t\t\t\t// Loop reading Namespace/NamespaceDone entries\n\t\t\t\tconst readLoop = (async () => {\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tconst done = await stream.reader.done();\n\t\t\t\t\t\tif (done) break;\n\n\t\t\t\t\t\tconst msgType = await stream.reader.u53();\n\t\t\t\t\t\tif (msgType === SubscribeNamespaceEntry.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntry.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t\t\t\t\tthis.#announced.add(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === SubscribeNamespaceEntryDone.id) {\n\t\t\t\t\t\t\tconst entry = await SubscribeNamespaceEntryDone.decode(stream.reader, version);\n\t\t\t\t\t\t\tconst path = Path.join(prefix, entry.suffix);\n\t\t\t\t\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\t\t\t\t\tthis.#announced.delete(path);\n\t\t\t\t\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\t\t\t\t\tif (!Path.hasPrefix(consumer.prefix, path)) continue;\n\t\t\t\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (msgType === PublishBlocked.id && version === Version.DRAFT_17) {\n\t\t\t\t\t\t\tconst blocked = await PublishBlocked.decode(stream.reader, version);\n\t\t\t\t\t\t\tconsole.debug(`publish_blocked: suffix=${blocked.suffix} track=${blocked.trackName}`);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t`unexpected message on subscribe_namespace stream: 0x${msgType.toString(16)}`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t})();\n\n\t\t\t\t// Wait for either the read loop or the announced to close\n\t\t\t\tawait Promise.race([readLoop, announced.closed]);\n\n\t\t\t\t// For v14/v15: send UnsubscribeNamespace before closing\n\t\t\t\tif (version === Version.DRAFT_14 || version === Version.DRAFT_15) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait stream.writer.u53(UnsubscribeNamespace.id);\n\t\t\t\t\t\tconst unsub = new UnsubscribeNamespace({ requestId });\n\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tstream.close();\n\t\t\t} catch (err) {\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tconsole.warn(`subscribe_namespace error: ${e.message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Consumes a broadcast from the connection.\n\t */\n\tconsume(path: Path.Valid): Broadcast {\n\t\tconst broadcast = new Broadcast();\n\n\t\tvoid (async () => {\n\t\t\tfor (;;) {\n\t\t\t\tconst request = await broadcast.requested();\n\t\t\t\tif (!request) break;\n\t\t\t\tvoid this.#runSubscribe(path, request);\n\t\t\t}\n\t\t})();\n\n\t\treturn broadcast;\n\t}\n\n\tasync #runSubscribe(broadcast: Path.Valid, request: TrackRequest) {\n\t\tconst version = this.#session.version;\n\t\tconst requestId = await this.#session.nextRequestId();\n\t\tif (requestId === undefined) {\n\t\t\trequest.track.close(new Error(\"session closed\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.debug(`subscribe start: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\ttry {\n\t\t\tconst stream = await this.#session.openBi();\n\n\t\t\ttry {\n\t\t\t\t// Write Subscribe\n\t\t\t\tawait stream.writer.u53(Subscribe.id);\n\t\t\t\tconst msg = new Subscribe({\n\t\t\t\t\trequestId,\n\t\t\t\t\ttrackNamespace: broadcast,\n\t\t\t\t\ttrackName: request.track.name,\n\t\t\t\t\tsubscriberPriority: request.priority,\n\t\t\t\t});\n\t\t\t\tawait msg.encode(stream.writer, version);\n\t\t\t\tconsole.debug(`subscribe written: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t\t// Pre-register with requestId so early group uni streams aren't dropped.\n\t\t\t\t// The publisher typically uses requestId as the trackAlias.\n\t\t\t\tthis.#subscribes.set(requestId, request.track);\n\n\t\t\t\t// Read response (SubscribeOk or error)\n\t\t\t\tconst respTypeId = await stream.reader.u53();\n\t\t\t\tif (respTypeId === SubscribeOk.id) {\n\t\t\t\t\tconst ok = await SubscribeOk.decode(stream.reader, version);\n\t\t\t\t\t// Update registration to use the actual trackAlias from SubscribeOk\n\t\t\t\t\tif (ok.trackAlias !== requestId) {\n\t\t\t\t\t\tthis.#subscribes.delete(requestId);\n\t\t\t\t\t\tthis.#subscribes.set(ok.trackAlias, request.track);\n\t\t\t\t\t}\n\t\t\t\t\tconsole.debug(`subscribe ok: id=${requestId} broadcast=${broadcast} track=${request.track.name}`);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Wait for stream close (= PublishDone) or track close (= local unsubscribe)\n\t\t\t\t\t\tawait Promise.race([stream.reader.closed, request.track.closed]);\n\n\t\t\t\t\t\t// For v14-v16: send Unsubscribe before closing (removed in v17+)\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tversion === Version.DRAFT_14 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_15 ||\n\t\t\t\t\t\t\tversion === Version.DRAFT_16\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait stream.writer.u53(Unsubscribe.id);\n\t\t\t\t\t\t\t\tconst unsub = new Unsubscribe({ requestId });\n\t\t\t\t\t\t\t\tawait unsub.encode(stream.writer, version);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t// Stream might already be closed\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trequest.track.close();\n\t\t\t\t\t\tstream.close();\n\t\t\t\t\t\tconsole.debug(\n\t\t\t\t\t\t\t`subscribe close: id=${requestId} broadcast=${broadcast} track=${request.track.name}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tthis.#subscribes.delete(ok.trackAlias);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Clean up pre-registered entry on error\n\t\t\t\t\tthis.#subscribes.delete(requestId);\n\n\t\t\t\t\t// Error response\n\t\t\t\t\tlet reasonPhrase = \"unknown error\";\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (respTypeId === RequestError.id) {\n\t\t\t\t\t\t\t// SubscribeError (v14) or RequestError (v15+)\n\t\t\t\t\t\t\tconst err =\n\t\t\t\t\t\t\t\tversion === Version.DRAFT_14\n\t\t\t\t\t\t\t\t\t? await SubscribeError.decode(stream.reader, version)\n\t\t\t\t\t\t\t\t\t: await RequestError.decode(stream.reader, version);\n\t\t\t\t\t\t\treasonPhrase = `code=${err.errorCode} reason=${err.reasonPhrase}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Decoding error response failed, use default message\n\t\t\t\t\t}\n\t\t\t\t\tthrow new Error(`SUBSCRIBE error: ${reasonPhrase}`);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tthis.#subscribes.delete(requestId);\n\t\t\t\tstream.abort(error(err));\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst e = error(err);\n\t\t\trequest.track.close(e);\n\t\t\tconsole.warn(\n\t\t\t\t`subscribe error: id=${requestId} broadcast=${broadcast} track=${request.track.name} error=${e.message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH_NAMESPACE on a bidi stream.\n\t * Tracks announced broadcasts and notifies consumers.\n\t *\n\t * @internal\n\t */\n\tasync runPublishNamespace(msg: PublishNamespace, stream: Stream) {\n\t\tconst version = this.#session.version;\n\t\tconst path = msg.trackNamespace;\n\n\t\tif (this.#announced.has(path)) {\n\t\t\tconsole.warn(\"duplicate PublishNamespace\");\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceError.id);\n\t\t\t\tconst err = new PublishNamespaceError({\n\t\t\t\t\trequestId: msg.requestId,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\t\tconst err = new RequestError({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t\terrorCode: 409,\n\t\t\t\t\treasonPhrase: \"duplicate namespace\",\n\t\t\t\t});\n\t\t\t\tawait err.encode(stream.writer, version);\n\t\t\t}\n\t\t\tstream.close();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.#announced.add(path);\n\n\t\ttry {\n\t\t\t// Send OK first — must complete before notifying consumers,\n\t\t\t// because consumers may trigger Subscribe writes that would\n\t\t\t// interleave with our OK on the control stream.\n\t\t\tif (version === Version.DRAFT_14) {\n\t\t\t\tawait stream.writer.u53(PublishNamespaceOk.id);\n\t\t\t\tconst ok = new PublishNamespaceOk({ requestId: msg.requestId });\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t} else {\n\t\t\t\tawait stream.writer.u53(RequestOk.id);\n\t\t\t\tconst ok = new RequestOk({\n\t\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\t});\n\t\t\t\tawait ok.encode(stream.writer, version);\n\t\t\t}\n\n\t\t\tconsole.debug(`announced: broadcast=${path} active=true`);\n\n\t\t\t// Notify consumers after OK is written\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\tconsumer.append({ path, active: true });\n\t\t\t}\n\n\t\t\t// Wait for stream close (= PublishNamespaceDone)\n\t\t\tconsole.debug(`runPublishNamespace: awaiting stream.reader.closed for ${path}`);\n\t\t\tawait stream.reader.closed;\n\t\t\tconsole.debug(`runPublishNamespace: stream.reader.closed resolved for ${path}`);\n\t\t} finally {\n\t\t\tthis.#announced.delete(path);\n\t\t\tconsole.debug(`announced: broadcast=${path} active=false`);\n\n\t\t\tfor (const consumer of this.#announcedConsumers) {\n\t\t\t\tconst suffix = Path.stripPrefix(consumer.prefix, path);\n\t\t\t\tif (suffix === null) continue;\n\t\t\t\ttry {\n\t\t\t\t\tconsumer.append({ path, active: false });\n\t\t\t\t} catch {\n\t\t\t\t\t// Consumer already closed, will be cleaned up\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Handles an incoming PUBLISH on a bidi stream.\n\t * We don't support reverse publish, so send error.\n\t *\n\t * @internal\n\t */\n\tasync runPublish(msg: Publish, stream: Stream) {\n\t\tconst version = this.#session.version;\n\n\t\tif (version === Version.DRAFT_14) {\n\t\t\tawait stream.writer.u53(PublishError.id);\n\t\t\tconst err = new PublishError({\n\t\t\t\trequestId: msg.requestId,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t} else {\n\t\t\tawait stream.writer.u53(RequestError.id);\n\t\t\tconst err = new RequestError({\n\t\t\t\trequestId: version === Version.DRAFT_15 || version === Version.DRAFT_16 ? msg.requestId : undefined,\n\t\t\t\terrorCode: 500,\n\t\t\t\treasonPhrase: \"publish not supported\",\n\t\t\t});\n\t\t\tawait err.encode(stream.writer, version);\n\t\t}\n\t\tstream.close();\n\t}\n\n\t/**\n\t * Handles an ObjectStream message (group + frames on uni stream).\n\t *\n\t * @internal\n\t */\n\tasync handleGroup(group: GroupMessage, stream: Reader) {\n\t\tconst producer = new Group(group.groupId);\n\n\t\tif (group.subGroupId !== 0) {\n\t\t\tthrow new Error(\"subgroups are not supported\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Look up by trackAlias directly\n\t\t\tconst track = this.#subscribes.get(group.trackAlias);\n\t\t\tif (!track) {\n\t\t\t\t// Fallback: try treating trackAlias as requestId (for compat)\n\t\t\t\tthrow new Error(`unknown track: trackAlias=${group.trackAlias}`);\n\t\t\t}\n\n\t\t\ttrack.writeGroup(producer);\n\n\t\t\tfor (;;) {\n\t\t\t\tconst done = await Promise.race([stream.done(), producer.closed, track.closed]);\n\t\t\t\tif (done !== false) break;\n\n\t\t\t\tconst frame = await Frame.decode(stream, group.flags);\n\t\t\t\tif (frame.payload === undefined) break;\n\n\t\t\t\tproducer.writeFrame(frame.payload, frame.extensions);\n\t\t\t}\n\n\t\t\tproducer.close();\n\t\t} catch (err: unknown) {\n\t\t\tconst e = error(err);\n\t\t\tproducer.close(e);\n\t\t\tstream.stop(e);\n\t\t}\n\t}\n}\n"]}
|
package/ietf/track.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type * as Path from "../path";
|
|
2
|
+
import type { Reader, Writer } from "../stream";
|
|
3
|
+
import { type IetfVersion } from "./version";
|
|
4
|
+
export declare class TrackStatusRequest {
|
|
5
|
+
#private;
|
|
6
|
+
static id: number;
|
|
7
|
+
requestId: bigint;
|
|
8
|
+
trackNamespace: Path.Valid;
|
|
9
|
+
trackName: string;
|
|
10
|
+
constructor({ requestId, trackNamespace, trackName, }: {
|
|
11
|
+
requestId: bigint;
|
|
12
|
+
trackNamespace: Path.Valid;
|
|
13
|
+
trackName: string;
|
|
14
|
+
});
|
|
15
|
+
encode(w: Writer, version: IetfVersion): Promise<void>;
|
|
16
|
+
static decode(r: Reader, version: IetfVersion): Promise<TrackStatusRequest>;
|
|
17
|
+
}
|
|
18
|
+
export declare class TrackStatus {
|
|
19
|
+
#private;
|
|
20
|
+
static id: number;
|
|
21
|
+
trackNamespace: Path.Valid;
|
|
22
|
+
trackName: string;
|
|
23
|
+
statusCode: number;
|
|
24
|
+
lastGroupId: bigint;
|
|
25
|
+
lastObjectId: bigint;
|
|
26
|
+
constructor({ trackNamespace, trackName, statusCode, lastGroupId, lastObjectId, }: {
|
|
27
|
+
trackNamespace: Path.Valid;
|
|
28
|
+
trackName: string;
|
|
29
|
+
statusCode: number;
|
|
30
|
+
lastGroupId: bigint;
|
|
31
|
+
lastObjectId: bigint;
|
|
32
|
+
});
|
|
33
|
+
encode(w: Writer, _version: IetfVersion): Promise<void>;
|
|
34
|
+
static decode(r: Reader, _version: IetfVersion): Promise<TrackStatus>;
|
|
35
|
+
static readonly STATUS_IN_PROGRESS = 0;
|
|
36
|
+
static readonly STATUS_NOT_FOUND = 1;
|
|
37
|
+
static readonly STATUS_NOT_AUTHORIZED = 2;
|
|
38
|
+
static readonly STATUS_ENDED = 3;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=track.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track.d.ts","sourceRoot":"","sources":["../../src/ietf/track.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAInD,OAAO,EAAE,KAAK,WAAW,EAAW,MAAM,cAAc,CAAC;AAKzD,qBAAa,kBAAkB;;IAC9B,MAAM,CAAC,EAAE,SAAQ;IAEjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAElB,YAAY,EACX,SAAS,EACT,cAAc,EACd,SAAS,GACT,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,EAItE;IAuBK,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAEhF;CAuBD;AAID,qBAAa,WAAW;;IACvB,MAAM,CAAC,EAAE,SAAQ;IAEjB,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IAErB,YAAY,EACX,cAAc,EACd,SAAS,EACT,UAAU,EACV,WAAW,EACX,YAAY,GACZ,EAAE;QACF,cAAc,EAAE,IAAI,CAAC,KAAK,CAAC;QAC3B,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACrB,EAMA;IAUK,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAE5D;IAED,OAAa,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAE1E;IAaD,MAAM,CAAC,QAAQ,CAAC,kBAAkB,KAAQ;IAC1C,MAAM,CAAC,QAAQ,CAAC,gBAAgB,KAAQ;IACxC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,KAAQ;IAC7C,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAQ;CACpC"}
|
package/ietf/track.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* @ts-self-types="./track.d.ts" */
|
|
2
|
+
import * as Message from "./message.js";
|
|
3
|
+
import * as Namespace from "./namespace.js";
|
|
4
|
+
import { Parameters } from "./parameters.js";
|
|
5
|
+
import { Version } from "./version.js";
|
|
6
|
+
// we only support Group Order descending
|
|
7
|
+
const GROUP_ORDER = 0x02;
|
|
8
|
+
export class TrackStatusRequest {
|
|
9
|
+
static id = 0x0d;
|
|
10
|
+
requestId;
|
|
11
|
+
trackNamespace;
|
|
12
|
+
trackName;
|
|
13
|
+
constructor({ requestId, trackNamespace, trackName, }) {
|
|
14
|
+
this.requestId = requestId;
|
|
15
|
+
this.trackNamespace = trackNamespace;
|
|
16
|
+
this.trackName = trackName;
|
|
17
|
+
}
|
|
18
|
+
async #encode(w, version) {
|
|
19
|
+
await w.u62(this.requestId);
|
|
20
|
+
if (version === Version.DRAFT_17) {
|
|
21
|
+
await w.u62(0n); // required_request_id_delta — always 0, not supported
|
|
22
|
+
}
|
|
23
|
+
await Namespace.encode(w, this.trackNamespace);
|
|
24
|
+
await w.string(this.trackName);
|
|
25
|
+
if (version === Version.DRAFT_14) {
|
|
26
|
+
await w.u8(0); // subscriber_priority
|
|
27
|
+
await w.u8(GROUP_ORDER); // group_order
|
|
28
|
+
await w.bool(false); // forward
|
|
29
|
+
await w.u53(0x2); // filter_type = LargestObject
|
|
30
|
+
await w.u53(0); // no parameters
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
// v15+: just parameters
|
|
34
|
+
const params = new Parameters();
|
|
35
|
+
await params.encode(w, version);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async encode(w, version) {
|
|
39
|
+
return Message.encode(w, (mw) => this.#encode(mw, version));
|
|
40
|
+
}
|
|
41
|
+
static async decode(r, version) {
|
|
42
|
+
return Message.decode(r, (mr) => TrackStatusRequest.#decode(mr, version));
|
|
43
|
+
}
|
|
44
|
+
static async #decode(r, version) {
|
|
45
|
+
const requestId = await r.u62();
|
|
46
|
+
if (version === Version.DRAFT_17) {
|
|
47
|
+
await r.u62(); // required_request_id_delta
|
|
48
|
+
}
|
|
49
|
+
const trackNamespace = await Namespace.decode(r);
|
|
50
|
+
const trackName = await r.string();
|
|
51
|
+
if (version === Version.DRAFT_14) {
|
|
52
|
+
await r.u8(); // subscriber_priority
|
|
53
|
+
await r.u8(); // group_order
|
|
54
|
+
await r.bool(); // forward
|
|
55
|
+
await r.u53(); // filter_type
|
|
56
|
+
await Parameters.decode(r, version); // parameters
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// v15+: just parameters
|
|
60
|
+
await Parameters.decode(r, version);
|
|
61
|
+
}
|
|
62
|
+
return new TrackStatusRequest({ requestId, trackNamespace, trackName });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Track status response (0x0E) — v14 only (TRACK_STATUS_OK)
|
|
66
|
+
// In v15+, the response to TrackStatusRequest is RequestOk (0x07)
|
|
67
|
+
export class TrackStatus {
|
|
68
|
+
static id = 0x0e;
|
|
69
|
+
trackNamespace;
|
|
70
|
+
trackName;
|
|
71
|
+
statusCode;
|
|
72
|
+
lastGroupId;
|
|
73
|
+
lastObjectId;
|
|
74
|
+
constructor({ trackNamespace, trackName, statusCode, lastGroupId, lastObjectId, }) {
|
|
75
|
+
this.trackNamespace = trackNamespace;
|
|
76
|
+
this.trackName = trackName;
|
|
77
|
+
this.statusCode = statusCode;
|
|
78
|
+
this.lastGroupId = lastGroupId;
|
|
79
|
+
this.lastObjectId = lastObjectId;
|
|
80
|
+
}
|
|
81
|
+
async #encode(w) {
|
|
82
|
+
await Namespace.encode(w, this.trackNamespace);
|
|
83
|
+
await w.string(this.trackName);
|
|
84
|
+
await w.u62(BigInt(this.statusCode));
|
|
85
|
+
await w.u62(this.lastGroupId);
|
|
86
|
+
await w.u62(this.lastObjectId);
|
|
87
|
+
}
|
|
88
|
+
async encode(w, _version) {
|
|
89
|
+
return Message.encode(w, this.#encode.bind(this));
|
|
90
|
+
}
|
|
91
|
+
static async decode(r, _version) {
|
|
92
|
+
return Message.decode(r, TrackStatus.#decode);
|
|
93
|
+
}
|
|
94
|
+
static async #decode(r) {
|
|
95
|
+
const trackNamespace = await Namespace.decode(r);
|
|
96
|
+
const trackName = await r.string();
|
|
97
|
+
const statusCode = Number(await r.u62());
|
|
98
|
+
const lastGroupId = await r.u62();
|
|
99
|
+
const lastObjectId = await r.u62();
|
|
100
|
+
return new TrackStatus({ trackNamespace, trackName, statusCode, lastGroupId, lastObjectId });
|
|
101
|
+
}
|
|
102
|
+
// Track status codes
|
|
103
|
+
static STATUS_IN_PROGRESS = 0x00;
|
|
104
|
+
static STATUS_NOT_FOUND = 0x01;
|
|
105
|
+
static STATUS_NOT_AUTHORIZED = 0x02;
|
|
106
|
+
static STATUS_ENDED = 0x03;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=track.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track.js","sourceRoot":"","sources":["../../src/ietf/track.ts"],"names":[],"mappings":"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","sourcesContent":["import type * as Path from \"../path.ts\";\nimport type { Reader, Writer } from \"../stream.ts\";\nimport * as Message from \"./message.ts\";\nimport * as Namespace from \"./namespace.ts\";\nimport { Parameters } from \"./parameters.ts\";\nimport { type IetfVersion, Version } from \"./version.ts\";\n\n// we only support Group Order descending\nconst GROUP_ORDER = 0x02;\n\nexport class TrackStatusRequest {\n\tstatic id = 0x0d;\n\n\trequestId: bigint;\n\ttrackNamespace: Path.Valid;\n\ttrackName: string;\n\n\tconstructor({\n\t\trequestId,\n\t\ttrackNamespace,\n\t\ttrackName,\n\t}: { requestId: bigint; trackNamespace: Path.Valid; trackName: string }) {\n\t\tthis.requestId = requestId;\n\t\tthis.trackNamespace = trackNamespace;\n\t\tthis.trackName = trackName;\n\t}\n\n\tasync #encode(w: Writer, version: IetfVersion): Promise<void> {\n\t\tawait w.u62(this.requestId);\n\t\tif (version === Version.DRAFT_17) {\n\t\t\tawait w.u62(0n); // required_request_id_delta — always 0, not supported\n\t\t}\n\t\tawait Namespace.encode(w, this.trackNamespace);\n\t\tawait w.string(this.trackName);\n\n\t\tif (version === Version.DRAFT_14) {\n\t\t\tawait w.u8(0); // subscriber_priority\n\t\t\tawait w.u8(GROUP_ORDER); // group_order\n\t\t\tawait w.bool(false); // forward\n\t\t\tawait w.u53(0x2); // filter_type = LargestObject\n\t\t\tawait w.u53(0); // no parameters\n\t\t} else {\n\t\t\t// v15+: just parameters\n\t\t\tconst params = new Parameters();\n\t\t\tawait params.encode(w, version);\n\t\t}\n\t}\n\n\tasync encode(w: Writer, version: IetfVersion): Promise<void> {\n\t\treturn Message.encode(w, (mw) => this.#encode(mw, version));\n\t}\n\n\tstatic async decode(r: Reader, version: IetfVersion): Promise<TrackStatusRequest> {\n\t\treturn Message.decode(r, (mr) => TrackStatusRequest.#decode(mr, version));\n\t}\n\n\tstatic async #decode(r: Reader, version: IetfVersion): Promise<TrackStatusRequest> {\n\t\tconst requestId = await r.u62();\n\t\tif (version === Version.DRAFT_17) {\n\t\t\tawait r.u62(); // required_request_id_delta\n\t\t}\n\t\tconst trackNamespace = await Namespace.decode(r);\n\t\tconst trackName = await r.string();\n\n\t\tif (version === Version.DRAFT_14) {\n\t\t\tawait r.u8(); // subscriber_priority\n\t\t\tawait r.u8(); // group_order\n\t\t\tawait r.bool(); // forward\n\t\t\tawait r.u53(); // filter_type\n\t\t\tawait Parameters.decode(r, version); // parameters\n\t\t} else {\n\t\t\t// v15+: just parameters\n\t\t\tawait Parameters.decode(r, version);\n\t\t}\n\n\t\treturn new TrackStatusRequest({ requestId, trackNamespace, trackName });\n\t}\n}\n\n// Track status response (0x0E) — v14 only (TRACK_STATUS_OK)\n// In v15+, the response to TrackStatusRequest is RequestOk (0x07)\nexport class TrackStatus {\n\tstatic id = 0x0e;\n\n\ttrackNamespace: Path.Valid;\n\ttrackName: string;\n\tstatusCode: number;\n\tlastGroupId: bigint;\n\tlastObjectId: bigint;\n\n\tconstructor({\n\t\ttrackNamespace,\n\t\ttrackName,\n\t\tstatusCode,\n\t\tlastGroupId,\n\t\tlastObjectId,\n\t}: {\n\t\ttrackNamespace: Path.Valid;\n\t\ttrackName: string;\n\t\tstatusCode: number;\n\t\tlastGroupId: bigint;\n\t\tlastObjectId: bigint;\n\t}) {\n\t\tthis.trackNamespace = trackNamespace;\n\t\tthis.trackName = trackName;\n\t\tthis.statusCode = statusCode;\n\t\tthis.lastGroupId = lastGroupId;\n\t\tthis.lastObjectId = lastObjectId;\n\t}\n\n\tasync #encode(w: Writer): Promise<void> {\n\t\tawait Namespace.encode(w, this.trackNamespace);\n\t\tawait w.string(this.trackName);\n\t\tawait w.u62(BigInt(this.statusCode));\n\t\tawait w.u62(this.lastGroupId);\n\t\tawait w.u62(this.lastObjectId);\n\t}\n\n\tasync encode(w: Writer, _version: IetfVersion): Promise<void> {\n\t\treturn Message.encode(w, this.#encode.bind(this));\n\t}\n\n\tstatic async decode(r: Reader, _version: IetfVersion): Promise<TrackStatus> {\n\t\treturn Message.decode(r, TrackStatus.#decode);\n\t}\n\n\tstatic async #decode(r: Reader): Promise<TrackStatus> {\n\t\tconst trackNamespace = await Namespace.decode(r);\n\t\tconst trackName = await r.string();\n\t\tconst statusCode = Number(await r.u62());\n\t\tconst lastGroupId = await r.u62();\n\t\tconst lastObjectId = await r.u62();\n\n\t\treturn new TrackStatus({ trackNamespace, trackName, statusCode, lastGroupId, lastObjectId });\n\t}\n\n\t// Track status codes\n\tstatic readonly STATUS_IN_PROGRESS = 0x00;\n\tstatic readonly STATUS_NOT_FOUND = 0x01;\n\tstatic readonly STATUS_NOT_AUTHORIZED = 0x02;\n\tstatic readonly STATUS_ENDED = 0x03;\n}\n"]}
|