@fails-components/webtransport 1.1.4 → 1.2.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.
Files changed (53) hide show
  1. package/dist/lib/dom.d.ts +27 -10
  2. package/dist/lib/dom.d.ts.map +1 -1
  3. package/dist/lib/http2/browser/browser.d.ts +5 -2
  4. package/dist/lib/http2/browser/browser.d.ts.map +1 -1
  5. package/dist/lib/http2/browser/browserparser.d.ts.map +1 -1
  6. package/dist/lib/http2/node/capsuleparser.d.ts.map +1 -1
  7. package/dist/lib/http2/node/client.d.ts +3 -2
  8. package/dist/lib/http2/node/client.d.ts.map +1 -1
  9. package/dist/lib/http2/node/server.d.ts +10 -5
  10. package/dist/lib/http2/node/server.d.ts.map +1 -1
  11. package/dist/lib/http2/node/websocketparser.d.ts.map +1 -1
  12. package/dist/lib/http2/parserbase.d.ts +33 -1
  13. package/dist/lib/http2/parserbase.d.ts.map +1 -1
  14. package/dist/lib/http2/priorityscheduler.d.ts +167 -0
  15. package/dist/lib/http2/priorityscheduler.d.ts.map +1 -0
  16. package/dist/lib/http2/session.d.ts +25 -16
  17. package/dist/lib/http2/session.d.ts.map +1 -1
  18. package/dist/lib/http2/stream.d.ts +10 -0
  19. package/dist/lib/http2/stream.d.ts.map +1 -1
  20. package/dist/lib/http2/websocketcommon.d.ts.map +1 -1
  21. package/dist/lib/server.d.ts.map +1 -1
  22. package/dist/lib/session.d.ts +31 -17
  23. package/dist/lib/session.d.ts.map +1 -1
  24. package/dist/lib/stream.d.ts +13 -0
  25. package/dist/lib/stream.d.ts.map +1 -1
  26. package/dist/lib/types.d.ts +18 -15
  27. package/dist/lib/types.d.ts.map +1 -1
  28. package/dist/lib/webtransport.browser.d.ts +3 -2
  29. package/dist/lib/webtransport.browser.d.ts.map +1 -1
  30. package/dist/lib/webtransportbase.d.ts +1 -0
  31. package/dist/lib/webtransportbase.d.ts.map +1 -1
  32. package/eslint.config.js +20 -22
  33. package/lib/dom.ts +31 -13
  34. package/lib/http2/browser/browser.js +28 -13
  35. package/lib/http2/browser/browserparser.js +4 -1
  36. package/lib/http2/node/capsuleparser.js +4 -1
  37. package/lib/http2/node/client.js +38 -27
  38. package/lib/http2/node/server.js +56 -19
  39. package/lib/http2/node/websocketparser.js +5 -2
  40. package/lib/http2/parserbase.js +76 -7
  41. package/lib/http2/priorityscheduler.js +654 -0
  42. package/lib/http2/session.js +69 -20
  43. package/lib/http2/stream.js +60 -10
  44. package/lib/http2/websocketcommon.js +1 -1
  45. package/lib/server.js +0 -1
  46. package/lib/session.js +128 -64
  47. package/lib/stream.js +50 -8
  48. package/lib/types.ts +15 -8
  49. package/lib/webtransport.browser.js +77 -18
  50. package/lib/webtransportbase.js +7 -0
  51. package/old_test/testsuite.js +6 -2
  52. package/package.json +6 -6
  53. package/readme.md +3 -1
@@ -162,7 +162,10 @@ export class BrowserParser extends ParserBase {
162
162
  if (typeof streamid !== 'undefined') {
163
163
  let object = this.wtstreams.get(streamid)
164
164
  if (!object) {
165
- object = this.newStream(streamid)
165
+ object = this.newStream(streamid, {
166
+ sendOrder: 0n,
167
+ sendGroupId: 0n
168
+ })
166
169
  if (!object) return // stream broken
167
170
  }
168
171
  // TODO submit data
@@ -154,7 +154,10 @@ export class Http2CapsuleParser extends ParserBaseHttp2 {
154
154
  if (typeof streamid !== 'undefined') {
155
155
  let object = this.wtstreams.get(streamid)
156
156
  if (!object) {
157
- object = this.newStream(streamid)
157
+ object = this.newStream(streamid, {
158
+ sendOrder: 0n,
159
+ sendGroupId: 0n
160
+ })
158
161
  if (!object) return // stream broken
159
162
  }
160
163
  // TODO submit data
@@ -15,6 +15,7 @@ export class Http2WebTransportClient {
15
15
  this.port = Number(port)
16
16
  this.hostname = args?.host || 'localhost'
17
17
  this.serverCertificateHashes = args?.serverCertificateHashes || undefined
18
+ this.protocols = args?.protocols || []
18
19
  this.localPort = Number(args?.localPort) || undefined
19
20
  this.allowPooling = args?.allowPooling || false
20
21
  this.forceIpv6 = args?.forceIpv6 || false
@@ -29,12 +30,12 @@ export class Http2WebTransportClient {
29
30
  args?.initialUnidirectionalSendStreams || 100
30
31
 
31
32
  this.streamShouldAutoTuneReceiveWindow =
32
- args.streamShouldAutoTuneReceiveWindow || false
33
+ args.streamShouldAutoTuneReceiveWindow || true
33
34
  this.streamFlowControlWindowSizeLimit =
34
35
  args?.streamFlowControlWindowSizeLimit || 6 * 1024 * 1024
35
36
 
36
37
  this.sessionShouldAutoTuneReceiveWindow =
37
- args.sessionShouldAutoTuneReceiveWindow || false
38
+ args.sessionShouldAutoTuneReceiveWindow || true
38
39
  this.sessionFlowControlWindowSizeLimit =
39
40
  args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
40
41
  /** @type {import('../../session.js').HttpClient} */
@@ -92,9 +93,9 @@ export class Http2WebTransportClient {
92
93
  0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
93
94
  0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
94
95
  0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
95
- },
96
- remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65]
96
+ }
97
97
  },
98
+ remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65],
98
99
  localPort: this.localPort,
99
100
  // TODO: REMOVE BEFORE RELEASE; UNSAFE SETTING
100
101
  rejectUnauthorized: !this.serverCertificateHashes
@@ -109,26 +110,8 @@ export class Http2WebTransportClient {
109
110
  http2Options
110
111
  )
111
112
 
112
- let rtt = 100
113
- let adjust = 1
114
- // ok we got a session and want to measure RTT
115
- let pingsender = setInterval(() => {
116
- if (this.clientInt && !this.clientInt.closed) {
117
- // eslint-disable-next-line no-unused-vars
118
- this.clientInt.ping((err, duration, payload) => {
119
- if (!err) {
120
- rtt = adjust * duration + (1 - adjust) * rtt
121
- adjust = 0.2
122
- // @ts-ignore
123
- this.clientInt.WTrtt = rtt
124
- }
125
- })
126
- } else {
127
- clearInterval(pingsender)
128
- // @ts-ignore
129
- pingsender = undefined
130
- }
131
- }, 1000)
113
+ /** @type {NodeJS.Timeout|undefined} */
114
+ let pingsender
132
115
 
133
116
  this.clientInt.on('close', () => {
134
117
  if (pingsender) clearInterval(pingsender)
@@ -180,6 +163,28 @@ export class Http2WebTransportClient {
180
163
  this.jsobj.onClientConnected({
181
164
  success: true
182
165
  })
166
+ let rtt = 100
167
+ let adjust = 1
168
+ // ok we got a session and want to measure RTT
169
+ const pingupdater = () => {
170
+ if (this.clientInt && !this.clientInt.closed) {
171
+ // eslint-disable-next-line no-unused-vars
172
+ this.clientInt.ping((err, duration, payload) => {
173
+ if (!err) {
174
+ rtt = adjust * duration + (1 - adjust) * rtt
175
+ adjust = 0.2
176
+ // @ts-ignore
177
+ this.clientInt.WTrtt = rtt
178
+ }
179
+ })
180
+ } else {
181
+ clearInterval(pingsender)
182
+ // @ts-ignore
183
+ pingsender = undefined
184
+ }
185
+ }
186
+ pingsender = setInterval(pingupdater, 1000)
187
+ pingupdater()
183
188
  }
184
189
  })
185
190
  this.clientInt.on('error', (error) => {
@@ -207,14 +212,20 @@ export class Http2WebTransportClient {
207
212
  openWTSession(path) {
208
213
  if (!this.clientInt) throw new Error('clientInt not present')
209
214
 
210
- const stream = this.clientInt.request({
215
+ const requestOpts = {
211
216
  ':method': 'CONNECT',
212
217
  ':protocol': 'webtransport',
213
218
  ':scheme': 'https',
214
219
  ':path': path,
215
220
  authority: this.hostname,
216
221
  origin: this.hostname
217
- })
222
+ }
223
+ if (this.protocols.length > 0) {
224
+ // @ts-ignore
225
+ requestOpts['wt-available-protocols'] = this.protocols.join(',')
226
+ }
227
+
228
+ const stream = this.clientInt.request(requestOpts)
218
229
  const {
219
230
  0x2b65: remoteBidirectionalStreams = undefined,
220
231
  0x2b64: remoteUnidirectionalStreams = undefined,
@@ -255,7 +266,7 @@ export class Http2WebTransportClient {
255
266
  sendWindowOffset:
256
267
  remoteSessionFlowControlWindow ||
257
268
  this.sessionFlowControlWindowSizeLimit,
258
- receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
269
+ receiveWindowOffset: this.initialSessionFlowControlWindow,
259
270
  shouldAutoTuneReceiveWindow: this.sessionShouldAutoTuneReceiveWindow,
260
271
  receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
261
272
  }),
@@ -33,12 +33,12 @@ export class Http2WebTransportServer {
33
33
  args?.initialUnidirectionalStreams || 100
34
34
 
35
35
  this.streamShouldAutoTuneReceiveWindow =
36
- args.streamShouldAutoTuneReceiveWindow || false
36
+ args.streamShouldAutoTuneReceiveWindow || true
37
37
  this.streamFlowControlWindowSizeLimit =
38
38
  args?.streamFlowControlWindowSizeLimit || 6 * 1024 * 1024
39
39
 
40
40
  this.sessionShouldAutoTuneReceiveWindow =
41
- args.sessionShouldAutoTuneReceiveWindow || false
41
+ args.sessionShouldAutoTuneReceiveWindow || true
42
42
  this.sessionFlowControlWindowSizeLimit =
43
43
  args?.sessionFlowControlWindowSizeLimit || 15 * 1024 * 1024
44
44
 
@@ -65,9 +65,9 @@ export class Http2WebTransportServer {
65
65
  0x2b63: this.initialStreamFlowControlWindow, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAM_DATA_BIDI
66
66
  0x2b64: this.initialUnidirectionalStreams, // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_UNI
67
67
  0x2b65: this.initialBidirectionalStreams // SETTINGS_WEBTRANSPORT_INITIAL_MAX_STREAMS_BIDI
68
- },
69
- remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65]
70
- }
68
+ }
69
+ },
70
+ remoteCustomSettings: [0x2b60, 0x2b61, 0x2b62, 0x2b63, 0x2b64, 0x2b65]
71
71
  })
72
72
 
73
73
  this.serverInt.on('listening', () => {
@@ -95,7 +95,7 @@ export class Http2WebTransportServer {
95
95
  let rtt = 100
96
96
  let adjust = 1
97
97
  // ok we got a session and want to measure RTT
98
- let pingsender = setInterval(() => {
98
+ const pingupdater = () => {
99
99
  if (!session.closed)
100
100
  // eslint-disable-next-line no-unused-vars
101
101
  session.ping((err, duration, payload) => {
@@ -111,7 +111,9 @@ export class Http2WebTransportServer {
111
111
  // @ts-ignore
112
112
  pingsender = undefined
113
113
  }
114
- }, 1000)
114
+ }
115
+ let pingsender = setInterval(pingupdater, 1000)
116
+ pingupdater()
115
117
 
116
118
  session.on('close', () => {
117
119
  if (pingsender) clearInterval(pingsender)
@@ -136,7 +138,11 @@ export class Http2WebTransportServer {
136
138
  path = path?.slice(1)
137
139
  }
138
140
  const header = { ...request.headers, ':path': path }
139
- const websocketProt = this.checkProtocolHeader(header)
141
+ const { websocketProt, webtransportProt } =
142
+ this.checkProtocolHeader(header)
143
+ if (webtransportProt) {
144
+ header['wt-available-protocols'] = webtransportProt
145
+ }
140
146
  if (!websocketProt) {
141
147
  stream.destroy()
142
148
  return
@@ -227,7 +233,11 @@ export class Http2WebTransportServer {
227
233
  header[':protocol'] === 'websocket' &&
228
234
  header['sec-websocket-protocol']
229
235
  ) {
230
- websocketProt = this.checkProtocolHeader(header)
236
+ let obj = this.checkProtocolHeader(header)
237
+ websocketProt = obj.websocketProt
238
+ if (obj.webtransportProt) {
239
+ header['wt-available-protocols'] = obj.webtransportProt
240
+ }
231
241
  }
232
242
  if (header[':protocol'] !== 'webtransport' && !websocketProt) {
233
243
  stream.respond({
@@ -334,8 +344,11 @@ export class Http2WebTransportServer {
334
344
  const resp = {
335
345
  ':status': '200'
336
346
  }
337
- // @ts-ignore
338
- if (websocketProt) resp['sec-websocket-protocol'] = websocketProt
347
+
348
+ if (websocketProt) {
349
+ // @ts-ignore
350
+ resp['sec-websocket-protocol'] = websocketProt
351
+ }
339
352
  stream.respond(resp)
340
353
  this.jsobj.onHttpWTSessionVisitor(retObj)
341
354
  } else {
@@ -352,9 +365,12 @@ export class Http2WebTransportServer {
352
365
 
353
366
  /**
354
367
  * @param {import("http2").IncomingHttpHeaders} header
368
+ * @return {{websocketProt: string|undefined, webtransportProt?: string}}
355
369
  */
356
370
  checkProtocolHeader(header) {
357
371
  const sechead = header['sec-websocket-protocol']
372
+ ?.split?.(',')
373
+ ?.map?.((el) => el.trim())
358
374
  let prots
359
375
  if (!Array.isArray(sechead)) {
360
376
  prots = [sechead]
@@ -365,8 +381,19 @@ export class Http2WebTransportServer {
365
381
  .map((el) => (el ? el.split('_') : [undefined, undefined]))
366
382
  .filter((el) => el[0] === 'webtransport')
367
383
  .filter((el) => (el[1] ? supportedVersions.includes(el[1]) : false))
368
- if (prots.length > 0) return prots[0].join('_')
369
- else return undefined
384
+ if (prots.length > 0) {
385
+ const selWtVersion = prots[0][1]
386
+ prots = prots.filter((el) => el[1] === selWtVersion)
387
+ /** @type {{websocketProt: string|undefined, webtransportProt?: string}} */
388
+ const retObj = { websocketProt: prots[0].slice(0, 2).join('_') }
389
+ if (prots[0][2]) {
390
+ // @ts-ignore
391
+ retObj.webtransportProt = [
392
+ ...new Set(prots.map((el) => el.slice(2).join('_')))
393
+ ].join(',')
394
+ }
395
+ return retObj
396
+ } else return { websocketProt: undefined }
370
397
  }
371
398
 
372
399
  startServer() {
@@ -444,7 +471,8 @@ export class Http2WebTransportServer {
444
471
  protocol,
445
472
  head,
446
473
  path,
447
- transportPrivate
474
+ transportPrivate,
475
+ selectedProtocol
448
476
  }) {
449
477
  if (status !== 200) {
450
478
  if (protocol === 'websocketoverhttp1') {
@@ -462,8 +490,11 @@ export class Http2WebTransportServer {
462
490
  // @ts-ignore
463
491
  stream,
464
492
  header,
465
- // @ts-ignore
466
- protocol: transportPrivate.websocketProt
493
+ protocol: selectedProtocol
494
+ ? // @ts-ignore
495
+ transportPrivate.websocketProt + '_' + selectedProtocol
496
+ : // @ts-ignore
497
+ transportPrivate.websocketProt
467
498
  })
468
499
  .then(() => {
469
500
  const retObj = {
@@ -496,7 +527,7 @@ export class Http2WebTransportServer {
496
527
  initialUnidirectionalReceiveStreams:
497
528
  this.initialUnidirectionalStreams,
498
529
  sendWindowOffset: 0,
499
- receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
530
+ receiveWindowOffset: this.initialSessionFlowControlWindow,
500
531
  shouldAutoTuneReceiveWindow:
501
532
  this.sessionShouldAutoTuneReceiveWindow,
502
533
  receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
@@ -518,7 +549,13 @@ export class Http2WebTransportServer {
518
549
  // @ts-ignore
519
550
  if (transportPrivate?.websocketProt)
520
551
  // @ts-ignore
521
- resp['sec-websocket-protocol'] = transportPrivate.websocketProt
552
+ resp['sec-websocket-protocol'] = selectedProtocol
553
+ ? // @ts-ignore
554
+ transportPrivate.websocketProt + '_' + selectedProtocol
555
+ : // @ts-ignore
556
+ transportPrivate.websocketProt
557
+ // @ts-ignore
558
+ else if (selectedProtocol) resp['wt-protocol'] = selectedProtocol
522
559
  stream.respond(resp)
523
560
  const {
524
561
  0x2b65: remoteBidirectionalStreams = undefined,
@@ -587,7 +624,7 @@ export class Http2WebTransportServer {
587
624
  ? remoteSessionFlowControlWindow ||
588
625
  this.sessionFlowControlWindowSizeLimit
589
626
  : 0, // TODO, once supported by node, use initial settings
590
- receiveWindowOffset: this.sessionFlowControlWindowSizeLimit,
627
+ receiveWindowOffset: this.initialSessionFlowControlWindow,
591
628
  shouldAutoTuneReceiveWindow:
592
629
  this.sessionShouldAutoTuneReceiveWindow,
593
630
  receiveWindowSizeLimit: this.sessionFlowControlWindowSizeLimit
@@ -132,8 +132,8 @@ function applyMask(ms, buffer, offset, length) {
132
132
  for (let run = 0 /* Math.round(length / 4) * 4 */; run < length; run++) {
133
133
  data[run] ^= workmask[run % 4]
134
134
  }
135
- ms.offset += length
136
135
  }
136
+ ms.offset += length
137
137
  }
138
138
  /*
139
139
  function readDWord(bs) {
@@ -541,7 +541,10 @@ export class WebSocketParser extends ParserBaseHttp2 {
541
541
  if (typeof streamid !== 'undefined') {
542
542
  let object = this.wtstreams.get(streamid)
543
543
  if (!object) {
544
- object = this.newStream(streamid)
544
+ object = this.newStream(streamid, {
545
+ sendOrder: 0n,
546
+ sendGroupId: 0n
547
+ })
545
548
  if (!object) return // stream broken
546
549
  }
547
550
  // TODO submit data
@@ -1,5 +1,6 @@
1
1
  import { Http2WebTransportStream } from './stream.js'
2
2
  import { logger } from '../utils.js'
3
+ import { PriorityScheduler } from './priorityscheduler.js'
3
4
 
4
5
  const pid = typeof process !== 'undefined' ? process.pid : 0
5
6
  const log = logger(`webtransport:parserbase(${pid})`)
@@ -59,6 +60,8 @@ export class ParserBase {
59
60
 
60
61
  /** @type {Map<bigint,Http2WebTransportStream>} */
61
62
  this.wtstreams = new Map()
63
+
64
+ this.scheduler = new PriorityScheduler()
62
65
  }
63
66
 
64
67
  /**
@@ -101,8 +104,9 @@ export class ParserBase {
101
104
 
102
105
  /**
103
106
  * @param {bigint} streamid
107
+ * @param {{sendOrder: bigint,sendGroupId: bigint}} priority
104
108
  */
105
- newStream(streamid) {
109
+ newStream(streamid, priority) {
106
110
  const incoming = this.isclient ? !(streamid & 0x1n) : !!(streamid & 0x1n)
107
111
  const streamIdManager =
108
112
  streamid & 0x2n
@@ -138,16 +142,36 @@ export class ParserBase {
138
142
  streamIdManager
139
143
  })
140
144
  this.wtstreams.set(streamid, stream)
145
+ this.scheduler.Register(streamid, priority)
141
146
  this.session.jsobj.onStream({
142
147
  bidirectional: !(streamid & 0x2n),
143
148
  incoming,
144
- stream
149
+ stream,
150
+ sendGroupId: priority.sendGroupId,
151
+ sendOrder: priority.sendOrder
145
152
  })
146
153
  return stream
147
154
  }
148
155
 
156
+ scheduleDrainWrites() {
157
+ if (this._scheduledDrainWriteCall) return
158
+ const prom = Promise.resolve()
159
+ this._scheduledDrainWriteCall = prom
160
+ prom
161
+ .then(() => {
162
+ delete this._scheduledDrainWriteCall
163
+ this.drainWrites()
164
+ })
165
+ .catch((error) => log('Error in drainWrites', error))
166
+ }
167
+
149
168
  drainWrites() {
150
- for (const stream of this.wtstreams.values()) {
169
+ if (!this.blocked) this.session.drainWrites()
170
+ while (!this.blocked) {
171
+ const frontId = this.scheduler.PopFront()
172
+ if (typeof frontId === 'undefined') break
173
+ const stream = this.wtstreams.get(frontId)
174
+ if (!stream) break
151
175
  stream.drainWrites()
152
176
  }
153
177
  }
@@ -156,8 +180,16 @@ export class ParserBase {
156
180
  * @param {bigint|undefined} val
157
181
  */
158
182
  onMaxData(val) {
159
- if (val && this.session.flowController.updateSendWindowOffset(val))
160
- this.drainWrites()
183
+ if (val && this.session.flowController.updateSendWindowOffset(val)) {
184
+ let pending = false
185
+ this.wtstreams.forEach((stream, streamid) => {
186
+ if (stream.hasPendingData()) {
187
+ pending = true
188
+ this.scheduleDrainWriteStream(streamid)
189
+ }
190
+ })
191
+ if (pending) this.drainWrites()
192
+ }
161
193
  }
162
194
 
163
195
  /**
@@ -167,8 +199,10 @@ export class ParserBase {
167
199
  onMaxStreamData(streamid, offset) {
168
200
  const object = this.wtstreams.get(streamid)
169
201
  if (object && offset) {
170
- if (object.flowController.updateSendWindowOffset(offset))
171
- object.drainWrites()
202
+ if (object.flowController.updateSendWindowOffset(offset)) {
203
+ this.scheduleDrainWriteStream(streamid)
204
+ this.drainWrites()
205
+ }
172
206
  }
173
207
  }
174
208
 
@@ -251,6 +285,41 @@ export class ParserBase {
251
285
  this.session.jsobj.onGoAwayReceived()
252
286
  }
253
287
 
288
+ /**
289
+ *
290
+ * @param {bigint} streamid
291
+ */
292
+ shouldYieldStream(streamid) {
293
+ return this.scheduler.ShouldYield(streamid)
294
+ }
295
+
296
+ /**
297
+ *
298
+ * @param {bigint} streamid
299
+ */
300
+ scheduleDrainWriteStream(streamid) {
301
+ this.scheduler.Schedule(streamid)
302
+ }
303
+
304
+ /**
305
+ *
306
+ * @param {bigint} streamid
307
+ */
308
+ removeStream(streamid) {
309
+ this.scheduler.Unregister(streamid)
310
+ //this.wtstreams.delete(streamid) // why does this create troubles
311
+ }
312
+
313
+ /**
314
+ *
315
+ * @param {bigint} streamid
316
+ * @param {{sendOrder: bigint, sendGroupId: bigint}} arg2
317
+ */
318
+ streamUpdateSendOrderAndGroup(streamid, { sendOrder, sendGroupId }) {
319
+ this.scheduler.UpdateSendGroup(streamid, sendGroupId)
320
+ this.scheduler.UpdateSendOrder(streamid, sendOrder)
321
+ }
322
+
254
323
  /**
255
324
  * @param {number} code
256
325
  */