@@ -15,6 +15,7 @@ import type { Sink } from 'it-stream-types'
15
15
import type { StreamMuxer , StreamMuxerInit } from '@libp2p/interface-stream-muxer'
16
16
import type { Stream } from '@libp2p/interface-connection'
17
17
import type { MplexInit } from './index.js'
18
+ import anySignal from 'any-signal'
18
19
19
20
const log = logger ( 'libp2p:mplex' )
20
21
@@ -55,6 +56,7 @@ export class MplexStreamMuxer implements StreamMuxer {
55
56
private readonly _streams : { initiators : Map < number , MplexStream > , receivers : Map < number , MplexStream > }
56
57
private readonly _init : MplexStreamMuxerInit
57
58
private readonly _source : { push : ( val : Message ) => void , end : ( err ?: Error ) => void }
59
+ private readonly closeController : AbortController
58
60
59
61
constructor ( components : Components , init ?: MplexStreamMuxerInit ) {
60
62
init = init ?? { }
@@ -83,12 +85,15 @@ export class MplexStreamMuxer implements StreamMuxer {
83
85
const source = this . _createSource ( )
84
86
this . _source = source
85
87
this . source = source
86
- }
87
-
88
- init ( components : Components ) {
89
88
89
+ /**
90
+ * Close controller
91
+ */
92
+ this . closeController = new AbortController ( )
90
93
}
91
94
95
+ init ( components : Components ) { }
96
+
92
97
/**
93
98
* Returns a Map of streams and their ids
94
99
*/
@@ -109,12 +114,29 @@ export class MplexStreamMuxer implements StreamMuxer {
109
114
* provided, the id of the stream will be used.
110
115
*/
111
116
newStream ( name ?: string ) : Stream {
117
+ if ( this . closeController . signal . aborted ) {
118
+ throw new Error ( 'Muxer already closed' )
119
+ }
112
120
const id = this . _streamId ++
113
121
name = name == null ? id . toString ( ) : name . toString ( )
114
122
const registry = this . _streams . initiators
115
123
return this . _newStream ( { id, name, type : 'initiator' , registry } )
116
124
}
117
125
126
+ /**
127
+ * Close or abort all tracked streams and stop the muxer
128
+ */
129
+ close ( err ?: Error | undefined ) : void {
130
+ if ( this . closeController . signal . aborted ) return
131
+
132
+ if ( err != null ) {
133
+ this . streams . forEach ( s => s . abort ( err ) )
134
+ } else {
135
+ this . streams . forEach ( s => s . close ( ) )
136
+ }
137
+ this . closeController . abort ( )
138
+ }
139
+
118
140
/**
119
141
* Called whenever an inbound stream is created
120
142
*/
@@ -177,9 +199,12 @@ export class MplexStreamMuxer implements StreamMuxer {
177
199
*/
178
200
_createSink ( ) {
179
201
const sink : Sink < Uint8Array > = async source => {
202
+ // see: https://github.com/jacobheun/any-signal/pull/18
203
+ const abortSignals = [ this . closeController . signal ]
180
204
if ( this . _init . signal != null ) {
181
- source = abortableSource ( source , this . _init . signal )
205
+ abortSignals . push ( this . _init . signal )
182
206
}
207
+ source = abortableSource ( source , anySignal ( abortSignals ) )
183
208
184
209
try {
185
210
await pipe (
@@ -209,22 +234,7 @@ export class MplexStreamMuxer implements StreamMuxer {
209
234
*/
210
235
_createSource ( ) {
211
236
const onEnd = ( err ?: Error ) => {
212
- const { initiators, receivers } = this . _streams
213
- // Abort all the things!
214
- for ( const s of initiators . values ( ) ) {
215
- if ( err != null ) {
216
- s . abort ( err )
217
- } else {
218
- s . close ( )
219
- }
220
- }
221
- for ( const s of receivers . values ( ) ) {
222
- if ( err != null ) {
223
- s . abort ( err )
224
- } else {
225
- s . close ( )
226
- }
227
- }
237
+ this . close ( err )
228
238
}
229
239
const source = pushableV < Message > ( {
230
240
objectMode : true ,
0 commit comments