@@ -8,6 +8,7 @@ import { pushable } from 'it-pushable'
88import parallel from 'it-parallel'
99import { pipe } from 'it-pipe'
1010import map from 'it-map'
11+ import PQueue from 'p-queue'
1112
1213/**
1314 * @typedef {import('../../../types').ExporterOptions } ExporterOptions
@@ -19,14 +20,15 @@ import map from 'it-map'
1920/**
2021 * @param {Blockstore } blockstore
2122 * @param {PBNode | Uint8Array } node
22- * @param {import('it-pushable').Pushable<Uint8Array | undefined > } queue
23+ * @param {import('it-pushable').Pushable<Uint8Array> } queue
2324 * @param {number } streamPosition
2425 * @param {number } start
2526 * @param {number } end
27+ * @param {PQueue } walkQueue
2628 * @param {ExporterOptions } options
2729 * @returns {Promise<void> }
2830 */
29- async function walkDAG ( blockstore , node , queue , streamPosition , start , end , options ) {
31+ async function walkDAG ( blockstore , node , queue , streamPosition , start , end , walkQueue , options ) {
3032 // a `raw` node
3133 if ( node instanceof Uint8Array ) {
3234 queue . push ( extractDataFromBlock ( node , streamPosition , start , end ) )
@@ -100,19 +102,23 @@ async function walkDAG (blockstore, node, queue, streamPosition, start, end, opt
100102 } ) ,
101103 async ( source ) => {
102104 for await ( const { link, block, blockStart } of source ) {
105+ /** @type {PBNode | Uint8Array } */
103106 let child
104107 switch ( link . Hash . code ) {
105108 case dagPb . code :
106- child = await dagPb . decode ( block )
109+ child = dagPb . decode ( block )
107110 break
108111 case raw . code :
109112 child = block
110113 break
111114 default :
112- throw errCode ( new Error ( `Unsupported codec: ${ link . Hash . code } ` ) , 'ERR_NOT_UNIXFS' )
115+ queue . end ( errCode ( new Error ( `Unsupported codec: ${ link . Hash . code } ` ) , 'ERR_NOT_UNIXFS' ) )
116+ return
113117 }
114118
115- await walkDAG ( blockstore , child , queue , blockStart , start , end , options )
119+ walkQueue . add ( async ( ) => {
120+ await walkDAG ( blockstore , child , queue , blockStart , start , end , walkQueue , options )
121+ } )
116122 }
117123 }
118124 )
@@ -141,14 +147,20 @@ const fileContent = (cid, node, unixfs, path, resolve, depth, blockstore) => {
141147 return
142148 }
143149
144- const queue = pushable ( {
145- objectMode : true
150+ // use a queue to walk the DAG instead of recursion to ensure very deep DAGs
151+ // don't overflow the stack
152+ const walkQueue = new PQueue ( {
153+ concurrency : 1
146154 } )
155+ const queue = pushable ( )
147156
148- walkDAG ( blockstore , node , queue , 0 , offset , offset + length , options )
149- . catch ( err => {
150- queue . end ( err )
151- } )
157+ walkQueue . add ( async ( ) => {
158+ await walkDAG ( blockstore , node , queue , 0 , offset , offset + length , walkQueue , options )
159+ } )
160+
161+ walkQueue . on ( 'error' , error => {
162+ queue . end ( error )
163+ } )
152164
153165 let read = 0
154166
0 commit comments