1
1
'use strict'
2
2
3
3
const bs58 = require ( 'bs58' )
4
- const ndjson = require ( 'ndjson' )
5
4
const multipart = require ( 'ipfs-multipart' )
6
5
const debug = require ( 'debug' )
7
6
const tar = require ( 'tar-stream' )
8
7
const log = debug ( 'http-api:files' )
9
8
log . error = debug ( 'http-api:files:error' )
10
- const async = require ( 'async' )
9
+ const pull = require ( 'pull-stream' )
10
+ const toStream = require ( 'pull-stream-to-stream' )
11
+ const toPull = require ( 'stream-to-pull-stream' )
12
+ const pushable = require ( 'pull-pushable' )
13
+ const EOL = require ( 'os' ) . EOL
11
14
12
15
exports = module . exports
13
16
@@ -37,15 +40,23 @@ exports.cat = {
37
40
// main route handler which is called after the above `parseArgs`, but only if the args were valid
38
41
handler : ( request , reply ) => {
39
42
const key = request . pre . args . key
43
+ const ipfs = request . server . app . ipfs
40
44
41
- request . server . app . ipfs . files . cat ( key , ( err , stream ) => {
45
+ ipfs . files . cat ( key , ( err , stream ) => {
42
46
if ( err ) {
43
47
log . error ( err )
44
48
return reply ( {
45
49
Message : 'Failed to cat file: ' + err ,
46
50
Code : 0
47
51
} ) . code ( 500 )
48
52
}
53
+
54
+ // hapi is not very clever and throws if no
55
+ // - _read method
56
+ // - _readableState object
57
+ // are there :(
58
+ stream . _read = ( ) => { }
59
+ stream . _readableState = { }
49
60
return reply ( stream ) . header ( 'X-Stream-Output' , '1' )
50
61
} )
51
62
}
@@ -58,45 +69,44 @@ exports.get = {
58
69
// main route handler which is called after the above `parseArgs`, but only if the args were valid
59
70
handler : ( request , reply ) => {
60
71
const key = request . pre . args . key
61
-
62
- request . server . app . ipfs . files . get ( key , ( err , stream ) => {
63
- if ( err ) {
64
- log . error ( err )
65
- return reply ( {
66
- Message : 'Failed to get file: ' + err ,
67
- Code : 0
68
- } ) . code ( 500 )
69
- }
70
- var pack = tar . pack ( )
71
- const files = [ ]
72
- stream . on ( 'data' , ( data ) => {
73
- files . push ( data )
74
- } )
75
- const processFile = ( file ) => {
76
- return ( callback ) => {
77
- if ( ! file . content ) { // is directory
78
- pack . entry ( { name : file . path , type : 'directory' } )
79
- callback ( )
80
- } else { // is file
81
- const fileContents = [ ]
82
- file . content . on ( 'data' , ( data ) => {
83
- fileContents . push ( data )
84
- } )
85
- file . content . on ( 'end' , ( ) => {
86
- pack . entry ( { name : file . path } , Buffer . concat ( fileContents ) )
87
- callback ( )
88
- } )
72
+ const ipfs = request . server . app . ipfs
73
+ const pack = tar . pack ( )
74
+
75
+ ipfs . files . getPull ( key , ( err , stream ) => {
76
+ if ( err ) return handleError ( err )
77
+
78
+ pull (
79
+ stream ,
80
+ pull . asyncMap ( ( file , cb ) => {
81
+ const header = { name : file . path }
82
+
83
+ if ( ! file . content ) {
84
+ header . type = 'directory'
85
+ pack . entry ( header )
86
+ cb ( )
87
+ } else {
88
+ header . size = file . size
89
+ toStream . source ( file . content )
90
+ . pipe ( pack . entry ( header , cb ) )
89
91
}
90
- }
91
- }
92
- stream . on ( 'end' , ( ) => {
93
- const callbacks = files . map ( processFile )
94
- async . series ( callbacks , ( ) => {
92
+ } ) ,
93
+ pull . onEnd ( ( err ) => {
94
+ if ( err ) return handleError ( err )
95
+
95
96
pack . finalize ( )
96
97
reply ( pack ) . header ( 'X-Stream-Output' , '1' )
97
98
} )
98
- } )
99
+ )
99
100
} )
101
+
102
+ function handleError ( err ) {
103
+ log . error ( err )
104
+
105
+ reply ( {
106
+ Message : 'Failed to get file: ' + err ,
107
+ Code : 0
108
+ } ) . code ( 500 )
109
+ }
100
110
}
101
111
}
102
112
@@ -106,67 +116,66 @@ exports.add = {
106
116
return reply ( 'Array, Buffer, or String is required.' ) . code ( 400 ) . takeover ( )
107
117
}
108
118
119
+ const ipfs = request . server . app . ipfs
120
+ // TODO: make pull-multipart
109
121
const parser = multipart . reqParser ( request . payload )
122
+ let filesParsed = false
110
123
111
- var filesParsed = false
112
- var filesAdded = 0
124
+ const fileAdder = pushable ( )
113
125
114
- var serialize = ndjson . serialize ( )
115
- // hapi doesn't permit object streams: http://hapijs.com/api#replyerr-result
116
- serialize . _readableState . objectMode = false
117
-
118
- request . server . app . ipfs . files . createAddStream ( ( err , fileAdder ) => {
119
- if ( err ) {
120
- return reply ( {
121
- Message : err ,
122
- Code : 0
123
- } ) . code ( 500 )
126
+ parser . on ( 'file' , ( fileName , fileStream ) => {
127
+ const filePair = {
128
+ path : fileName ,
129
+ content : toPull ( fileStream )
124
130
}
131
+ filesParsed = true
132
+ fileAdder . push ( filePair )
133
+ } )
125
134
126
- fileAdder . on ( 'data' , ( file ) => {
127
- const filePath = file . path ? file . path : file . hash
128
- serialize . write ( {
129
- Name : filePath ,
130
- Hash : file . hash
131
- } )
132
- filesAdded ++
135
+ parser . on ( 'directory' , ( directory ) => {
136
+ fileAdder . push ( {
137
+ path : directory ,
138
+ content : ''
133
139
} )
140
+ } )
141
+
142
+ parser . on ( 'end' , ( ) => {
143
+ if ( ! filesParsed ) {
144
+ return reply ( "File argument 'data' is required." )
145
+ . code ( 400 ) . takeover ( )
146
+ }
147
+ fileAdder . end ( )
148
+ } )
134
149
135
- fileAdder . on ( 'end' , ( ) => {
136
- if ( filesAdded === 0 && filesParsed ) {
150
+ pull (
151
+ fileAdder ,
152
+ ipfs . files . createAddPullStream ( ) ,
153
+ pull . map ( ( file ) => {
154
+ return {
155
+ Name : file . path ? file . path : file . hash ,
156
+ Hash : file . hash
157
+ }
158
+ } ) ,
159
+ pull . map ( ( file ) => JSON . stringify ( file ) + EOL ) ,
160
+ pull . collect ( ( err , files ) => {
161
+ if ( err ) {
137
162
return reply ( {
138
- Message : 'Failed to add files.' ,
163
+ Message : err ,
139
164
Code : 0
140
165
} ) . code ( 500 )
141
- } else {
142
- serialize . end ( )
143
- return reply ( serialize )
144
- . header ( 'x-chunked-output' , '1' )
145
- . header ( 'content-type' , 'application/json' )
146
166
}
147
- } )
148
167
149
- parser . on ( 'file' , ( fileName , fileStream ) => {
150
- var filePair = {
151
- path : fileName ,
152
- content : fileStream
168
+ if ( files . length === 0 && filesParsed ) {
169
+ return reply ( {
170
+ Message : 'Failed to add files.' ,
171
+ Code : 0
172
+ } ) . code ( 500 )
153
173
}
154
- filesParsed = true
155
- fileAdder . write ( filePair )
156
- } )
157
- parser . on ( 'directory' , ( directory ) => {
158
- fileAdder . write ( {
159
- path : directory ,
160
- content : ''
161
- } )
162
- } )
163
174
164
- parser . on ( 'end' , ( ) => {
165
- if ( ! filesParsed ) {
166
- return reply ( "File argument 'data' is required." ) . code ( 400 ) . takeover ( )
167
- }
168
- fileAdder . end ( )
175
+ reply ( files . join ( '' ) )
176
+ . header ( 'x-chunked-output' , '1' )
177
+ . header ( 'content-type' , 'application/json' )
169
178
} )
170
- } )
179
+ )
171
180
}
172
181
}
0 commit comments