11import SonicBoom from 'sonic-boom'
22
3+ /**
4+ * @typedef {object } SonicOptions
5+ * @property {number } [minLength=4096] min output buffer length
6+ * @property {number } [timeout=1000] flush timeout in ms
7+ */
8+
39const noop = ( ) => { }
410
11+ /**
12+ * @param {NodeJS.WriteStream } stream
13+ * @returns {{fd: number, path: string } }
14+ */
15+ const streamDescriptor = ( stream ) => {
16+ // @ts -expect-error
17+ const { fd, path } = typeof stream === 'string' ? { path : stream } : stream
18+ return { fd, path }
19+ }
20+
521export class Sonic {
22+ /**
23+ * @param {NodeJS.WriteStream } stream
24+ * @param {SonicOptions } opts
25+ */
626 constructor ( stream , opts = { } ) {
727 const { minLength = 4096 , timeout = 1000 } = opts
828 this . _timer = undefined
929 this . _timeout = timeout
1030
11- // @ts -expect-error
12- const { fd, path } = typeof stream === 'string'
13- ? { path : stream }
14- : stream
31+ const { fd, path } = streamDescriptor ( stream )
1532
1633 this . stream = new SonicBoom ( { fd, dest : path , minLength, sync : true } )
1734 this . stream . on ( 'error' , filterBrokenPipe . bind ( null , this . stream ) )
@@ -21,8 +38,12 @@ export class Sonic {
2138 } )
2239 }
2340
41+ /**
42+ * @param {string } data
43+ * @returns {boolean }
44+ */
2445 write ( data ) {
25- this . stream . write ( data )
46+ const isWritten = this . stream . write ( data )
2647
2748 if ( ! this . _timer ) {
2849 this . _timer = setTimeout ( ( ) => {
@@ -31,7 +52,7 @@ export class Sonic {
3152 } , this . _timeout )
3253 }
3354
34- return true
55+ return isWritten
3556 }
3657
3758 flush ( ) {
@@ -59,3 +80,48 @@ function filterBrokenPipe (stream, err) {
5980 }
6081 stream . removeListener ( 'error' , filterBrokenPipe )
6182}
83+
84+ /**
85+ * maintains sonic streams by stream and options
86+ */
87+ export class SonicStreams extends Map {
88+ /**
89+ * @param {Record<string,any> } opts
90+ * @returns {string }
91+ */
92+ static hash ( opts ) {
93+ return 'sonic!' + Object . keys ( opts || { } )
94+ . sort ( )
95+ . map ( ( key ) => `${ key } :${ opts [ key ] } ` )
96+ . join ( '!' )
97+ }
98+
99+ /**
100+ * @param {NodeJS.WriteStream } stream
101+ * @param {SonicOptions } [opts]
102+ * @returns {Sonic }
103+ */
104+ use ( stream , opts = { } ) {
105+ const streamHash = SonicStreams . hash ( streamDescriptor ( stream ) )
106+ const optsHash = SonicStreams . hash ( opts )
107+ let streamRecord = this . get ( streamHash )
108+ if ( streamRecord ) {
109+ const sonic = streamRecord . get ( optsHash )
110+ if ( sonic ) {
111+ return sonic
112+ }
113+ }
114+ streamRecord =
115+ streamRecord ||
116+ ( ( ) => {
117+ const map = new Map ( )
118+ this . set ( streamHash , map )
119+ return map
120+ } ) ( )
121+ const newSonic = new Sonic ( stream , opts )
122+ streamRecord . set ( optsHash , newSonic )
123+ return newSonic
124+ }
125+ }
126+
127+ export const sonicStreams = new SonicStreams ( )
0 commit comments