33const  debug  =  require ( 'debug' ) 
44const  log  =  debug ( 'exporter' ) 
55log . err  =  debug ( 'exporter:error' ) 
6+ const  isIPFS  =  require ( 'is-ipfs' ) 
7+ const  bs58  =  require ( 'bs58' ) 
68const  UnixFS  =  require ( 'ipfs-unixfs' ) 
79const  series  =  require ( 'run-series' ) 
8- const  async  =  require ( 'async' ) 
910const  Readable  =  require ( 'readable-stream' ) . Readable 
1011const  pathj  =  require ( 'path' ) 
1112const  util  =  require ( 'util' ) 
13+ const  fieldtrip  =  require ( 'field-trip' ) 
1214
1315exports  =  module . exports  =  Exporter 
1416
@@ -19,21 +21,29 @@ function Exporter (hash, dagService, options) {
1921    return  new  Exporter ( hash ,  dagService ,  options ) 
2022  } 
2123
24+   // Sanitize hash. 
25+   if  ( ! isIPFS . multihash ( hash ) )  { 
26+     throw  new  Error ( 'not valid multihash' ) 
27+   } 
28+   if  ( Buffer . isBuffer ( hash ) )  { 
29+     hash  =  bs58 . encode ( hash ) 
30+   } 
31+ 
2232  Readable . call ( this ,  {  objectMode : true  } ) 
2333
2434  this . options  =  options  ||  { } 
2535
2636  this . _read  =  ( n )  =>  { } 
2737
28-   let  fileExporter  =  ( node ,  name ,  callback )  =>  { 
29-     let  init 
38+   let  fileExporter  =  ( node ,  name ,  done )  =>  { 
39+     let  init   =   false 
3040
31-     if  ( ! callback )   {   callback   =   function   noop   ( )   { }   } 
41+     if  ( ! done )   throw   new   Error ( 'done must be set' ) 
3242
43+     // Logic to export a single (possibly chunked) unixfs file. 
3344    var  rs  =  new  Readable ( ) 
3445    if  ( node . links . length  ===  0 )  { 
3546      const  unmarshaledData  =  UnixFS . unmarshal ( node . data ) 
36-       init  =  false 
3747      rs . _read  =  ( )  =>  { 
3848        if  ( init )  { 
3949          return 
@@ -43,10 +53,8 @@ function Exporter (hash, dagService, options) {
4353        rs . push ( null ) 
4454      } 
4555      this . push ( {  content : rs ,  path : name  } ) 
46-       callback ( ) 
47-       return 
56+       done ( ) 
4857    }  else  { 
49-       init  =  false 
5058      rs . _read  =  ( )  =>  { 
5159        if  ( init )  { 
5260          return 
@@ -57,7 +65,7 @@ function Exporter (hash, dagService, options) {
5765          return  ( cb )  =>  { 
5866            dagService . get ( link . hash ,  ( err ,  res )  =>  { 
5967              if  ( err )  { 
60-                 cb ( err ) 
68+                 return   cb ( err ) 
6169              } 
6270              var  unmarshaledData  =  UnixFS . unmarshal ( res . data ) 
6371              rs . push ( unmarshaledData . data ) 
@@ -67,80 +75,64 @@ function Exporter (hash, dagService, options) {
6775        } ) 
6876        series ( array ,  ( err ,  res )  =>  { 
6977          if  ( err )  { 
70-             callback ( ) 
78+             rs . emit ( 'error' ,   err ) 
7179            return 
7280          } 
7381          rs . push ( null ) 
74-           callback ( ) 
7582          return 
7683        } ) 
7784      } 
7885      this . push ( {  content : rs ,  path : name  } ) 
79-       callback ( ) 
80-       return 
86+       done ( ) 
8187    } 
8288  } 
8389
84-   let  dirExporter  =  ( node ,  name ,  callback )  =>  { 
85-     let  init 
90+   // Logic to export a unixfs directory. 
91+   let  dirExporter  =  ( node ,  name ,  add ,  done )  =>  { 
92+     if  ( ! add )  throw  new  Error ( 'add must be set' ) 
93+     if  ( ! done )  throw  new  Error ( 'done must be set' ) 
8694
87-     if   ( ! callback )   {   callback   =   function   noop   ( )   { }   } 
95+     this . push ( { content :  null ,   path :  name } ) 
8896
89-     var  rs  =  new  Readable ( ) 
90-     if  ( node . links . length  ===  0 )  { 
91-       init  =  false 
92-       rs . _read  =  ( )  =>  { 
93-         if  ( init )  { 
94-           return 
95-         } 
96-         init  =  true 
97-         rs . push ( node . data ) 
98-         rs . push ( null ) 
99-       } 
100-       this . push ( { content : null ,  path : name } ) 
101-       callback ( ) 
102-       return 
103-     }  else  { 
104-       async . forEachSeries ( node . links ,  ( link ,  callback )  =>  { 
105-         dagService . get ( link . hash ,  ( err ,  res )  =>  { 
106-           if  ( err )  { 
107-             callback ( err ) 
108-           } 
109-           var  unmarshaledData  =  UnixFS . unmarshal ( res . data ) 
110-           if  ( unmarshaledData . type  ===  'file' )  { 
111-             return  ( fileExporter ( res ,  pathj . join ( name ,  link . name ) ,  callback ) ) 
112-           } 
113-           if  ( unmarshaledData . type  ===  'directory' )  { 
114-             return  ( dirExporter ( res ,  pathj . join ( name ,  link . name ) ,  callback ) ) 
115-           } 
116-           callback ( ) 
117-         } ) 
118-       } ,  ( err )  =>  { 
119-         if  ( err )  { 
120-           callback ( ) 
121-           return 
122-         } 
123-         callback ( ) 
124-         return 
97+     // Directory has links 
98+     if  ( node . links . length  >  0 )  { 
99+       node . links . forEach ( ( link )  =>  { 
100+         add ( {  path : pathj . join ( name ,  link . name ) ,  hash : link . hash  } ) 
125101      } ) 
126102    } 
103+     done ( ) 
127104  } 
128105
129-   dagService . get ( hash ,  ( err ,  fetchedNode )  =>  { 
106+   // Traverse the DAG asynchronously 
107+   var  self  =  this 
108+   fieldtrip ( [ {  path : hash ,  hash : hash  } ] ,  visit ,  ( err )  =>  { 
130109    if  ( err )  { 
131-       this . emit ( 'error' ,  err ) 
110+       self . emit ( 'error' ,  err ) 
132111      return 
133112    } 
134-     const  data  =  UnixFS . unmarshal ( fetchedNode . data ) 
135-     const  type  =  data . type 
136- 
137-     if  ( type  ===  'directory' )  { 
138-       dirExporter ( fetchedNode ,  hash ) 
139-     } 
140-     if  ( type  ===  'file' )  { 
141-       fileExporter ( fetchedNode ,  hash ) 
142-     } 
113+     self . push ( null ) 
143114  } ) 
144115
116+   // Visit function: called once per node in the exported graph 
117+   function  visit  ( item ,  add ,  done )  { 
118+     dagService . get ( item . hash ,  ( err ,  fetchedNode )  =>  { 
119+       if  ( err )  { 
120+         self . emit ( 'error' ,  err ) 
121+         return 
122+       } 
123+ 
124+       const  data  =  UnixFS . unmarshal ( fetchedNode . data ) 
125+       const  type  =  data . type 
126+ 
127+       if  ( type  ===  'directory' )  { 
128+         dirExporter ( fetchedNode ,  item . path ,  add ,  done ) 
129+       } 
130+ 
131+       if  ( type  ===  'file' )  { 
132+         fileExporter ( fetchedNode ,  item . path ,  done ) 
133+       } 
134+     } ) 
135+   } 
136+ 
145137  return  this 
146138} 
0 commit comments