@@ -48,8 +48,10 @@ class QUICStream
48
48
protected _recvClosed : boolean = false ;
49
49
protected _recvPaused : boolean = false ;
50
50
protected resolveWritableP ?: ( ) => void ;
51
- public readonly finishedP : Promise < void > ;
52
- protected resolveFinishedP : ( ) => void ;
51
+ // This resolves when `streamSend` would result in a `StreamStopped(u64)` error indicating sending has ended
52
+ protected sendFinishedProm = utils . promise < void > ( )
53
+ // This resolves when `streamRecv` results in a `StreamReset(u64)` or a fin flag indicating receiving has ended
54
+ protected recvFinishedProm = utils . promise < void > ( )
53
55
54
56
/**
55
57
* For `reasonToCode`, return 0 means "unknown reason"
@@ -106,12 +108,6 @@ class QUICStream
106
108
this . streamMap = connection . streamMap ;
107
109
this . reasonToCode = reasonToCode ;
108
110
this . codeToReason = codeToReason ;
109
- const {
110
- p : finishedP ,
111
- resolveP : resolveFinishedP
112
- } = utils . promise < void > ( ) ;
113
- this . finishedP = finishedP ;
114
- this . resolveFinishedP = resolveFinishedP ;
115
111
116
112
// Try the BYOB later, it seems more performant
117
113
@@ -218,12 +214,17 @@ class QUICStream
218
214
await this . closeSend ( true , e ) ;
219
215
}
220
216
}
221
- await this . streamSend ( new Uint8Array ( 0 ) , true ) ;
217
+ // await this.streamSend(new Uint8Array(0), true).catch(e => console.error(e));
218
+ QUICStream . logStreamState ( this . streamId , this . conn , this . logger ) ;
219
+ this . logger . info ( 'Waiting for FINISH' )
220
+ await Promise . all ( [
221
+ this . sendFinishedProm . p . then ( ( ) => console . log ( 'send finished' ) ) ,
222
+ this . recvFinishedProm . p . then ( ( ) => console . log ( 'recv finished' ) ) ,
223
+ ] )
224
+ this . logger . info ( 'DONE waiting for FINISH' )
225
+ QUICStream . logStreamState ( this . streamId , this . conn , this . logger ) ;
222
226
this . streamMap . delete ( this . streamId ) ;
223
- this . logger . info ( `finished ${ this . conn . streamFinished ( this . streamId ) } ` ) ;
224
227
// We need to wait for the connection to finish before fully destroying
225
- this . logger . info ( 'Waiting for finish' )
226
- await this . finishedP ;
227
228
this . dispatchEvent ( new events . QUICStreamDestroyEvent ( ) ) ;
228
229
this . logger . info ( `Destroyed ${ this . constructor . name } ` ) ;
229
230
}
@@ -234,13 +235,34 @@ class QUICStream
234
235
*/
235
236
@ready ( new errors . ErrorQUICStreamDestroyed ( ) , false , [ 'destroying' ] )
236
237
public read ( ) : void {
237
- // TODO: check if the readable has errored out?
238
- this . logger . info ( `finished read ${ this . conn . streamFinished ( this . streamId ) } ` ) ;
238
+ // After reading it's possible the writer had a state change.
239
+ try {
240
+ this . conn . streamWritable ( this . streamId , 0 )
241
+ this . logger . info ( 'writable still good' )
242
+ } catch ( e ) {
243
+ this . logger . info ( e . message ) ;
244
+ // const reason = await this.processSendStreamError(e, 'send');
245
+ // If the writable has ended, we need to close the writable.
246
+ this . logger . info ( 'writable has ended' )
247
+ this . sendFinishedProm . resolveP ( ) ;
248
+ if ( ! this . _sendClosed ) {
249
+ const err = Error ( 'reason' ) ;
250
+ this . writableController . error ( err )
251
+ void this . closeSend ( true , err ) ;
252
+ }
253
+ }
239
254
if ( this . conn . streamFinished ( this . streamId ) ) {
240
- this . resolveFinishedP ( ) ;
255
+ // Stream has finished
256
+ this . recvFinishedProm . resolveP ( ) ;
257
+ if ( ! this . _recvClosed ) {
258
+ const err = Error ( 'TMP ERROR' ) ;
259
+ this . readableController . error ( err )
260
+ void this . closeRecv ( true , err ) ;
261
+ }
241
262
}
242
263
if ( this . _recvPaused ) {
243
264
// Do nothing if we are paused
265
+ this . logger . info ( 'Skipping read, paused' ) ;
244
266
return ;
245
267
}
246
268
void this . streamRecv ( ) ;
@@ -252,18 +274,28 @@ class QUICStream
252
274
*/
253
275
@ready ( new errors . ErrorQUICStreamDestroyed ( ) , false , [ 'destroying' ] )
254
276
public write ( ) : void {
255
- this . logger . info ( `finished write ${ this . conn . streamFinished ( this . streamId ) } ` ) ;
256
- if ( this . conn . streamFinished ( this . streamId ) ) {
257
- this . resolveFinishedP ( ) ;
258
- }
259
277
try {
260
278
this . conn . streamWritable ( this . streamId , 0 )
261
279
} catch ( e ) {
262
280
this . logger . info ( e . message ) ;
263
281
// const reason = await this.processSendStreamError(e, 'send');
264
282
// If the writable has ended, we need to close the writable.
265
- this . writableController . error ( Error ( 'TMP ERROR' ) )
266
- void this . closeSend ( ) ;
283
+ this . logger . info ( 'writable has ended' )
284
+ this . sendFinishedProm . resolveP ( ) ;
285
+ if ( ! this . _sendClosed ) {
286
+ const err = Error ( 'TMP ERROR' ) ;
287
+ this . writableController . error ( err )
288
+ void this . closeSend ( true , err ) ;
289
+ }
290
+ }
291
+ if ( this . conn . streamFinished ( this . streamId ) ) {
292
+ // Stream has finished
293
+ this . recvFinishedProm . resolveP ( ) ;
294
+ if ( ! this . _recvClosed ) {
295
+ const err = Error ( 'TMP ERROR' ) ;
296
+ this . readableController . error ( err )
297
+ void this . closeRecv ( true , err ) ;
298
+ }
267
299
}
268
300
if ( this . resolveWritableP != null ) {
269
301
this . resolveWritableP ( ) ;
@@ -273,6 +305,7 @@ class QUICStream
273
305
protected async streamRecv ( ) : Promise < void > {
274
306
const buf = Buffer . alloc ( 1024 ) ;
275
307
let recvLength : number , fin : boolean ;
308
+ this . logger . info ( 'trying receiving' ) ;
276
309
try {
277
310
[ recvLength , fin ] = this . conn . streamRecv ( this . streamId , buf ) ;
278
311
} catch ( e ) {
@@ -285,18 +318,18 @@ class QUICStream
285
318
// or through an exception here where the stream reports an error
286
319
// Since we don't call this method unless it is readable
287
320
// This should never be reported... (this branch should be dead code)
288
- this . logger . debug ( 'Stream reported: done' ) ;
321
+ this . logger . info ( 'Stream reported: done' ) ;
289
322
return ;
290
323
} else {
291
- this . logger . debug ( 'Stream reported: error' ) ;
292
- const match = e . message . match ( / S t r e a m R e s e t \( ( .+ ) \) / ) ;
293
- if ( match != null ) {
324
+ this . logger . info ( 'Stream reported: error' ) ;
325
+ // Signal receiving has ended
326
+ this . recvFinishedProm . resolveP ( ) ;
327
+ const reason = await this . processSendStreamError ( e , 'recv' ) ;
328
+ if ( reason != null ) {
294
329
// If it is `StreamReset(u64)` error, then the peer has closed
295
330
// the stream, and we are receiving the error code
296
- const code = parseInt ( match [ 1 ] ) ;
297
- const reason = await this . codeToReason ( 'recv' , code ) ;
298
331
this . readableController . error ( reason ) ;
299
- await this . closeRecv ( ) ;
332
+ await this . closeRecv ( true , reason ) ;
300
333
} else {
301
334
// If it is not a `StreamReset(u64)`, then something else broke
302
335
// and we need to propagate the error up and down the stream
@@ -320,6 +353,8 @@ class QUICStream
320
353
this . logger . info ( 'Stream reported: fin' ) ;
321
354
if ( ! this . _recvClosed ) this . readableController . close ( ) ;
322
355
await this . closeRecv ( ) ;
356
+ // Signal receiving has ended
357
+ this . recvFinishedProm . resolveP ( ) ;
323
358
return ;
324
359
}
325
360
// Now we pause receiving if the queue is full
@@ -351,6 +386,8 @@ class QUICStream
351
386
// This ensures that we are always blocked below.
352
387
sentLength = - 1 ;
353
388
} else {
389
+ // Signal sending has ended
390
+ this . sendFinishedProm . resolveP ( ) ;
354
391
// We may receive a `StreamStopped(u64)` exception
355
392
// meaning the peer has signalled for us to stop writing
356
393
// If this occurs, we need to go back to the writable stream
@@ -360,7 +397,7 @@ class QUICStream
360
397
const reason = await this . processSendStreamError ( e , 'send' ) ;
361
398
if ( reason != null ) {
362
399
// We have to close the send side (but the stream is already closed)
363
- await this . closeSend ( ) ;
400
+ await this . closeSend ( true , e ) ;
364
401
// Throws the exception back to the writer
365
402
throw reason ;
366
403
} else {
@@ -410,13 +447,13 @@ class QUICStream
410
447
if ( e . message !== 'Done' ) throw e ;
411
448
}
412
449
await this . connection . send ( ) ;
450
+ QUICStream . logStreamState ( this . streamId , this . conn , this . logger ) ;
413
451
if ( this [ status ] !== 'destroying' && this . _recvClosed && this . _sendClosed ) {
414
452
// Only destroy if we are not already destroying
415
453
// and that both recv and send is closed
416
- await this . destroy ( ) ;
454
+ void this . destroy ( ) ;
417
455
}
418
456
this . logger . info ( `Closed Recv` ) ;
419
- this . logger . info ( `finished ${ this . conn . streamFinished ( this . streamId ) } ` ) ;
420
457
}
421
458
422
459
/**
@@ -448,10 +485,9 @@ class QUICStream
448
485
if ( this [ status ] !== 'destroying' && this . _recvClosed && this . _sendClosed ) {
449
486
// Only destroy if we are not already destroying
450
487
// and that both recv and send is closed
451
- await this . destroy ( ) ;
488
+ void this . destroy ( ) ;
452
489
}
453
490
this . logger . info ( `Closed Send` ) ;
454
- this . logger . info ( `finished ${ this . conn . streamFinished ( this . streamId ) } ` ) ;
455
491
}
456
492
457
493
protected async processSendStreamError ( e : Error , type : 'recv' | 'send' ) : Promise < any | null > {
@@ -464,6 +500,28 @@ class QUICStream
464
500
}
465
501
return null ;
466
502
}
503
+
504
+ public static logStreamState ( streamId : StreamId , conn : Connection , logger : Logger ) {
505
+ let message = 'STATE:' ;
506
+ try {
507
+ conn . streamWritable ( streamId , 0 ) ;
508
+ message += 'W'
509
+ } catch ( e ) {
510
+ message += '!W'
511
+ }
512
+ try {
513
+ if ( conn . streamReadable ( streamId ) ) message += 'R' ;
514
+ else message += '!R' ;
515
+ } catch ( e ) {
516
+ message += '!R'
517
+ }
518
+ if ( conn . streamFinished ( streamId ) ) {
519
+ message += 'F'
520
+ } else {
521
+ message += '!F'
522
+ }
523
+ logger . info ( message ) ;
524
+ }
467
525
}
468
526
469
527
export default QUICStream ;
0 commit comments