@@ -11,15 +11,15 @@ let textDecoder: TextDecoder | null;
1111
1212export class VSBuffer {
1313
14- public static alloc ( byteLength : number ) : VSBuffer {
14+ static alloc ( byteLength : number ) : VSBuffer {
1515 if ( hasBuffer ) {
1616 return new VSBuffer ( Buffer . allocUnsafe ( byteLength ) ) ;
1717 } else {
1818 return new VSBuffer ( new Uint8Array ( byteLength ) ) ;
1919 }
2020 }
2121
22- public static wrap ( actual : Uint8Array ) : VSBuffer {
22+ static wrap ( actual : Uint8Array ) : VSBuffer {
2323 if ( hasBuffer && ! ( Buffer . isBuffer ( actual ) ) ) {
2424 // https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
2525 // Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array
@@ -28,7 +28,7 @@ export class VSBuffer {
2828 return new VSBuffer ( actual ) ;
2929 }
3030
31- public static fromString ( source : string ) : VSBuffer {
31+ static fromString ( source : string ) : VSBuffer {
3232 if ( hasBuffer ) {
3333 return new VSBuffer ( Buffer . from ( source ) ) ;
3434 } else {
@@ -39,7 +39,7 @@ export class VSBuffer {
3939 }
4040 }
4141
42- public static concat ( buffers : VSBuffer [ ] , totalLength ?: number ) : VSBuffer {
42+ static concat ( buffers : VSBuffer [ ] , totalLength ?: number ) : VSBuffer {
4343 if ( typeof totalLength === 'undefined' ) {
4444 totalLength = 0 ;
4545 for ( let i = 0 , len = buffers . length ; i < len ; i ++ ) {
@@ -58,15 +58,15 @@ export class VSBuffer {
5858 return ret ;
5959 }
6060
61- public readonly buffer : Uint8Array ;
62- public readonly byteLength : number ;
61+ readonly buffer : Uint8Array ;
62+ readonly byteLength : number ;
6363
6464 private constructor ( buffer : Uint8Array ) {
6565 this . buffer = buffer ;
6666 this . byteLength = this . buffer . byteLength ;
6767 }
6868
69- public toString ( ) : string {
69+ toString ( ) : string {
7070 if ( hasBuffer ) {
7171 return this . buffer . toString ( ) ;
7272 } else {
@@ -77,30 +77,29 @@ export class VSBuffer {
7777 }
7878 }
7979
80- public slice ( start ?: number , end ?: number ) : VSBuffer {
80+ slice ( start ?: number , end ?: number ) : VSBuffer {
8181 return new VSBuffer ( this . buffer . slice ( start , end ) ) ;
8282 }
8383
84- public set ( array : VSBuffer , offset ?: number ) : void {
84+ set ( array : VSBuffer , offset ?: number ) : void {
8585 this . buffer . set ( array . buffer , offset ) ;
8686 }
8787
88- public readUint32BE ( offset : number ) : number {
88+ readUint32BE ( offset : number ) : number {
8989 return readUint32BE ( this . buffer , offset ) ;
9090 }
9191
92- public writeUint32BE ( value : number , offset : number ) : void {
92+ writeUint32BE ( value : number , offset : number ) : void {
9393 writeUint32BE ( this . buffer , value , offset ) ;
9494 }
9595
96- public readUint8 ( offset : number ) : number {
96+ readUint8 ( offset : number ) : number {
9797 return readUint8 ( this . buffer , offset ) ;
9898 }
9999
100- public writeUint8 ( value : number , offset : number ) : void {
100+ writeUint8 ( value : number , offset : number ) : void {
101101 writeUint8 ( this . buffer , value , offset ) ;
102102 }
103-
104103}
105104
106105function readUint32BE ( source : Uint8Array , offset : number ) : number {
@@ -139,6 +138,27 @@ export interface VSBufferReadable {
139138 read ( ) : VSBuffer | null ;
140139}
141140
141+ export interface VSBufferReadableStream {
142+
143+ /**
144+ * The 'data' event is emitted whenever the stream is
145+ * relinquishing ownership of a chunk of data to a consumer.
146+ */
147+ on ( event : 'data' , callback : ( chunk : VSBuffer ) => void ) : void ;
148+
149+ /**
150+ * Emitted when any error occurs.
151+ */
152+ on ( event : 'error' , callback : ( err : any ) => void ) : void ;
153+
154+ /**
155+ * The 'end' event is emitted when there is no more data
156+ * to be consumed from the stream. The 'end' event will
157+ * not be emitted unless the data is completely consumed.
158+ */
159+ on ( event : 'end' , callback : ( ) => void ) : void ;
160+ }
161+
142162/**
143163 * Helper to fully read a VSBuffer readable into a single buffer.
144164 */
@@ -158,6 +178,7 @@ export function readableToBuffer(readable: VSBufferReadable): VSBuffer {
158178 */
159179export function bufferToReadable ( buffer : VSBuffer ) : VSBufferReadable {
160180 let done = false ;
181+
161182 return {
162183 read : ( ) => {
163184 if ( done ) {
@@ -169,4 +190,215 @@ export function bufferToReadable(buffer: VSBuffer): VSBufferReadable {
169190 return buffer ;
170191 }
171192 } ;
193+ }
194+
195+ /**
196+ * Helper to fully read a VSBuffer stream into a single buffer.
197+ */
198+ export function streamToBuffer ( stream : VSBufferReadableStream ) : Promise < VSBuffer > {
199+ return new Promise ( ( resolve , reject ) => {
200+ const chunks : VSBuffer [ ] = [ ] ;
201+
202+ stream . on ( 'data' , chunk => chunks . push ( chunk ) ) ;
203+ stream . on ( 'error' , error => reject ( error ) ) ;
204+ stream . on ( 'end' , ( ) => resolve ( VSBuffer . concat ( chunks ) ) ) ;
205+ } ) ;
206+ }
207+
208+ /**
209+ * Helper to create a VSBufferStream from an existing VSBuffer.
210+ */
211+ export function bufferToStream ( buffer : VSBuffer ) : VSBufferReadableStream {
212+ const stream = writeableBufferStream ( ) ;
213+
214+ stream . end ( buffer ) ;
215+
216+ return stream ;
217+ }
218+
219+ /**
220+ * Helper to create a VSBufferStream that can be pushed
221+ * buffers to. Will only start to emit data when a listener
222+ * is added.
223+ */
224+ export function writeableBufferStream ( ) : VSBufferWriteableStream {
225+ return new VSBufferWriteableStreamImpl ( ) ;
226+ }
227+
228+ export interface VSBufferWriteableStream extends VSBufferReadableStream {
229+ data ( chunk : VSBuffer ) : void ;
230+ error ( error : Error ) : void ;
231+ end ( result ?: VSBuffer | Error ) : void ;
232+ }
233+
234+ class VSBufferWriteableStreamImpl implements VSBufferWriteableStream {
235+
236+ private readonly state = {
237+ flowing : false ,
238+ ended : false ,
239+ finished : false
240+ } ;
241+
242+ private readonly buffer = {
243+ data : [ ] as VSBuffer [ ] ,
244+ error : [ ] as Error [ ]
245+ } ;
246+
247+ private readonly listeners = {
248+ data : [ ] as { ( chunk : VSBuffer ) : void } [ ] ,
249+ error : [ ] as { ( error : Error ) : void } [ ] ,
250+ end : [ ] as { ( ) : void } [ ]
251+ } ;
252+
253+ data ( chunk : VSBuffer ) : void {
254+ if ( this . state . finished ) {
255+ return ;
256+ }
257+
258+ // flowing: directly send the data to listeners
259+ if ( this . state . flowing ) {
260+ this . listeners . data . forEach ( listener => listener ( chunk ) ) ;
261+ }
262+
263+ // not yet flowing: buffer data until flowing
264+ else {
265+ this . buffer . data . push ( chunk ) ;
266+ }
267+ }
268+
269+ error ( error : Error ) : void {
270+ if ( this . state . finished ) {
271+ return ;
272+ }
273+
274+ // flowing: directly send the error to listeners
275+ if ( this . state . flowing ) {
276+ this . listeners . error . forEach ( listener => listener ( error ) ) ;
277+ }
278+
279+ // not yet flowing: buffer errors until flowing
280+ else {
281+ this . buffer . error . push ( error ) ;
282+ }
283+ }
284+
285+ end ( result ?: VSBuffer | Error ) : void {
286+ if ( this . state . finished ) {
287+ return ;
288+ }
289+
290+ // end with data or error if provided
291+ if ( result instanceof Error ) {
292+ this . error ( result ) ;
293+ } else if ( result ) {
294+ this . data ( result ) ;
295+ }
296+
297+ // flowing: send end event to listeners
298+ if ( this . state . flowing ) {
299+ this . listeners . end . forEach ( listener => listener ( ) ) ;
300+
301+ this . finish ( ) ;
302+ }
303+
304+ // not yet flowing: remember state
305+ else {
306+ this . state . ended = true ;
307+ }
308+ }
309+
310+ on ( event : 'data' , callback : ( chunk : VSBuffer ) => void ) : void ;
311+ on ( event : 'error' , callback : ( err : any ) => void ) : void ;
312+ on ( event : 'end' , callback : ( ) => void ) : void ;
313+ on ( event : 'data' | 'error' | 'end' , callback : ( arg0 ?: any ) => void ) : void {
314+ if ( this . state . finished ) {
315+ return ;
316+ }
317+
318+ switch ( event ) {
319+ case 'data' :
320+ this . listeners . data . push ( callback ) ;
321+
322+ // switch into flowing mode as soon as the first 'data'
323+ // listener is added and we are not yet in flowing mode
324+ if ( ! this . state . flowing ) {
325+ this . state . flowing = true ;
326+
327+ // emit buffered events
328+ this . flowData ( ) ;
329+ this . flowErrors ( ) ;
330+ this . flowEnd ( ) ;
331+ }
332+
333+ break ;
334+
335+ case 'end' :
336+ this . listeners . end . push ( callback ) ;
337+
338+ // emit 'end' event directly if we are flowing
339+ // and the end has already been reached
340+ //
341+ // finish() when it went through
342+ if ( this . state . flowing && this . flowEnd ( ) ) {
343+ this . finish ( ) ;
344+ }
345+
346+ break ;
347+
348+ case 'error' :
349+ this . listeners . error . push ( callback ) ;
350+
351+ // emit buffered 'error' events unless done already
352+ // now that we know that we have at least one listener
353+ if ( this . state . flowing ) {
354+ this . flowErrors ( ) ;
355+ }
356+
357+ break ;
358+ }
359+ }
360+
361+ private flowData ( ) : void {
362+ if ( this . buffer . data . length > 0 ) {
363+ const fullDataBuffer = VSBuffer . concat ( this . buffer . data ) ;
364+
365+ this . listeners . data . forEach ( listener => listener ( fullDataBuffer ) ) ;
366+
367+ this . buffer . data . length = 0 ;
368+ }
369+ }
370+
371+ private flowErrors ( ) : void {
372+ if ( this . listeners . error . length > 0 ) {
373+ for ( const error of this . buffer . error ) {
374+ this . listeners . error . forEach ( listener => listener ( error ) ) ;
375+ }
376+
377+ this . buffer . error . length = 0 ;
378+ }
379+ }
380+
381+ private flowEnd ( ) : boolean {
382+ if ( this . state . ended ) {
383+ this . listeners . end . forEach ( listener => listener ( ) ) ;
384+
385+ return this . listeners . end . length > 0 ;
386+ }
387+
388+ return false ;
389+ }
390+
391+ private finish ( ) : void {
392+ if ( ! this . state . finished ) {
393+ this . state . finished = true ;
394+ this . state . ended = true ;
395+
396+ this . buffer . data . length = 0 ;
397+ this . buffer . error . length = 0 ;
398+
399+ this . listeners . data . length = 0 ;
400+ this . listeners . error . length = 0 ;
401+ this . listeners . end . length = 0 ;
402+ }
403+ }
172404}
0 commit comments