11import { CID } from 'multiformats/cid'
22import { createUnsafe } from 'multiformats/block'
3- import { base58btc } from 'multiformats/bases/base58'
43import { CarWriter } from '@ipld/car/writer'
54import { withTimeoutOption } from 'ipfs-core-utils/with-timeout-option'
65import debug from 'debug'
76import * as raw from 'multiformats/codecs/raw'
87import * as json from 'multiformats/codecs/json'
8+ import { walk } from 'multiformats/traversal'
99
1010const log = debug ( 'ipfs:components:dag:import' )
1111
@@ -23,6 +23,11 @@ const NO_LINKS_CODECS = [
2323 * @typedef {import('ipfs-core-types/src/utils').AbortOptions } AbortOptions
2424 */
2525
26+ /**
27+ * @template T
28+ * @typedef {import('multiformats/block').Block<T> } Block
29+ */
30+
2631/**
2732 * @param {Object } config
2833 * @param {IPFSRepo } config.repo
@@ -53,12 +58,8 @@ export function createExport ({ repo, preload, codecs }) {
5358 let err = null
5459 ; ( async ( ) => {
5560 try {
56- await traverseWrite (
57- repo ,
58- { signal : options . signal , timeout : options . timeout } ,
59- cid ,
60- writer ,
61- codecs )
61+ const load = makeLoader ( repo , writer , { signal : options . signal , timeout : options . timeout } , codecs )
62+ await walk ( { cid, load } )
6263 writer . close ( )
6364 } catch ( e ) {
6465 err = e
@@ -80,52 +81,30 @@ export function createExport ({ repo, preload, codecs }) {
8081}
8182
8283/**
84+ * @template T
8385 * @param {IPFSRepo } repo
84- * @param {AbortOptions } options
85- * @param {CID } cid
8686 * @param {BlockWriter } writer
87- * @param {import('ipfs-core-utils/multicodecs').Multicodecs } codecs
88- * @param {Set<string> } seen
89- * @returns {Promise<void> }
90- */
91- async function traverseWrite ( repo , options , cid , writer , codecs , seen = new Set ( ) ) {
92- const b58Cid = cid . toString ( base58btc )
93- if ( seen . has ( b58Cid ) ) {
94- return
95- }
96-
97- const block = await getBlock ( repo , options , cid , codecs )
98-
99- log ( `Adding block ${ cid } to car` )
100- await writer . put ( block )
101- seen . add ( b58Cid )
102-
103- // recursive traversal of all links
104- for ( const link of block . links ) {
105- await traverseWrite ( repo , options , link , writer , codecs , seen )
106- }
107- }
108-
109- /**
110- * @param {IPFSRepo } repo
11187 * @param {AbortOptions } options
112- * @param {CID } cid
11388 * @param {import('ipfs-core-utils/multicodecs').Multicodecs } codecs
114- * @returns {Promise<{ cid:CID, bytes:Uint8Array, links:CID[]} > }
89+ * @returns {( cid:CID)=>Promise<Block<T> > }
11590 */
116- async function getBlock ( repo , options , cid , codecs ) {
117- const bytes = await repo . blocks . get ( cid , options )
118-
119- /** @type {CID[] } */
120- let links = [ ]
121- const codec = await codecs . getCodec ( cid . code )
91+ function makeLoader ( repo , writer , options , codecs ) {
92+ return async ( cid ) => {
93+ const bytes = await repo . blocks . get ( cid , options )
94+ const codec = await codecs . getCodec ( cid . code )
95+
96+ let block
97+ if ( codec ) {
98+ block = createUnsafe ( { bytes, cid, codec } )
99+ } else if ( NO_LINKS_CODECS . includes ( cid . code ) ) {
100+ // an opaque block with that will yield no links(), which is all walk() cares about
101+ block = createUnsafe ( { bytes, cid, value : null } )
102+ } else {
103+ throw new Error ( `Can't decode links in block with codec 0x${ cid . code . toString ( 16 ) } to form complete DAG` )
104+ }
122105
123- if ( codec ) {
124- const block = createUnsafe ( { bytes, cid, codec } )
125- links = [ ...block . links ( ) ] . map ( ( l ) => l [ 1 ] )
126- } else if ( ! NO_LINKS_CODECS . includes ( cid . code ) ) {
127- throw new Error ( `Can't decode links in block with codec 0x${ cid . code . toString ( 16 ) } to form complete DAG` )
106+ log ( `Adding block ${ cid } to car` )
107+ await writer . put ( block )
108+ return block
128109 }
129-
130- return { cid, bytes, links }
131110}
0 commit comments