1
1
import { AbortError } from 'ix/aborterror.js' ;
2
- import { AsyncSink } from 'ix/asynciterable/asynciterablex.js' ;
3
2
import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js' ;
3
+ import { LastValueSink } from './LastValueSink.js' ;
4
4
5
5
export interface DemultiplexerValue < T > {
6
6
/**
@@ -28,17 +28,16 @@ export type DemultiplexerSourceFactory<T> = (signal: AbortSignal) => Demultiplex
28
28
* 1. We only start subscribing when there is a downstream subscriber.
29
29
* 2. When all downstream subscriptions have ended, we end the source subscription.
30
30
*
31
- * The Demultiplexer does not handle backpressure. If subscribers are slow, a queue may build up
32
- * for each.
31
+ * For each subscriber, if backpressure builds up, we only keep the _last_ value.
33
32
*/
34
33
export class Demultiplexer < T > {
35
- private subscribers : Map < string , Set < AsyncSink < T > > > | undefined = undefined ;
34
+ private subscribers : Map < string , Set < LastValueSink < T > > > | undefined = undefined ;
36
35
private abortController : AbortController | undefined = undefined ;
37
36
private currentSource : DemultiplexerSource < T > | undefined = undefined ;
38
37
39
38
constructor ( private source : DemultiplexerSourceFactory < T > ) { }
40
39
41
- private start ( filter : string , sink : AsyncSink < T > ) {
40
+ private start ( filter : string , sink : LastValueSink < T > ) {
42
41
const abortController = new AbortController ( ) ;
43
42
const listeners = new Map ( ) ;
44
43
listeners . set ( filter , new Set ( [ sink ] ) ) ;
@@ -55,7 +54,7 @@ export class Demultiplexer<T> {
55
54
private async loop (
56
55
source : DemultiplexerSource < T > ,
57
56
abortController : AbortController ,
58
- sinks : Map < string , Set < AsyncSink < T > > >
57
+ sinks : Map < string , Set < LastValueSink < T > > >
59
58
) {
60
59
try {
61
60
for await ( let doc of source . iterator ) {
@@ -98,7 +97,7 @@ export class Demultiplexer<T> {
98
97
}
99
98
}
100
99
101
- private removeSink ( key : string , sink : AsyncSink < T > ) {
100
+ private removeSink ( key : string , sink : LastValueSink < T > ) {
102
101
const existing = this . subscribers ?. get ( key ) ;
103
102
if ( existing == null ) {
104
103
return ;
@@ -118,7 +117,7 @@ export class Demultiplexer<T> {
118
117
}
119
118
}
120
119
121
- private addSink ( key : string , sink : AsyncSink < T > ) {
120
+ private addSink ( key : string , sink : LastValueSink < T > ) {
122
121
if ( this . currentSource == null ) {
123
122
return this . start ( key , sink ) ;
124
123
} else {
@@ -139,7 +138,7 @@ export class Demultiplexer<T> {
139
138
* @param signal
140
139
*/
141
140
async * subscribe ( key : string , signal : AbortSignal ) : AsyncIterable < T > {
142
- const sink = new AsyncSink < T > ( ) ;
141
+ const sink = new LastValueSink < T > ( undefined ) ;
143
142
// Important that we register the sink before calling getFirstValue().
144
143
const source = this . addSink ( key , sink ) ;
145
144
try {
0 commit comments