Skip to content
This repository was archived by the owner on Mar 10, 2020. It is now read-only.

Commit ff667a7

Browse files
authored
Merge pull request #337 from ipfs/feat/ipfs.files.get
feat/ipfs.files.get
2 parents a0ec626 + 248cd13 commit ff667a7

16 files changed

+260
-27
lines changed

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,12 @@
3030
"url": "https://github.com/ipfs/js-ipfs-api"
3131
},
3232
"devDependencies": {
33-
"aegir": "^5.0.1",
33+
"aegir": "^6.0.0",
3434
"chai": "^3.5.0",
3535
"gulp": "^3.9.1",
36-
"interface-ipfs-core": "^0.5.0",
36+
"interface-ipfs-core": "^0.6.0",
3737
"ipfsd-ctl": "^0.14.0",
38+
"passthrough-counter": "^1.0.0",
3839
"pre-commit": "^1.1.3",
3940
"stream-equal": "^0.1.8",
4041
"stream-http": "^2.3.1",

src/add-to-dagnode-transform.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module.exports = function (err, res, send, done) {
88
if (err) {
99
return done(err)
1010
}
11+
1112
async.map(res, function map (entry, next) {
1213
getDagNode(send, entry.Hash, function (err, node) {
1314
if (err) {

src/api/add-files.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict'
22

3+
const isNode = require('detect-node')
34
const addToDagNodesTransform = require('../add-to-dagnode-transform')
45

56
module.exports = (send) => {
@@ -9,6 +10,10 @@ module.exports = (send) => {
910
opts = {}
1011
}
1112

13+
if (!isNode) {
14+
return cb(new Error('Recursive uploads are not supported in the browser'))
15+
}
16+
1217
if (typeof (path) !== 'string') {
1318
return cb(new Error('"path" must be a string'))
1419
}

src/api/cat.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
'use strict'
22

3-
const bs58 = require('bs58')
4-
const isIPFS = require('is-ipfs')
53
const promisify = require('promisify-es6')
4+
const cleanMultihash = require('../clean-multihash')
65

76
module.exports = (send) => {
87
const cat = promisify((multihash, callback) => {
@@ -15,13 +14,3 @@ module.exports = (send) => {
1514
})
1615
return cat
1716
}
18-
19-
function cleanMultihash (multihash) {
20-
if (!isIPFS.multihash(multihash)) {
21-
throw new Error('not valid multihash')
22-
}
23-
if (Buffer.isBuffer(multihash)) {
24-
return bs58.encode(multihash)
25-
}
26-
return multihash
27-
}

src/api/get.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict'
2+
3+
const tarStreamToObjects = require('../tar-stream-to-objects')
4+
const cleanMultihash = require('../clean-multihash')
5+
const promisify = require('promisify-es6')
6+
7+
module.exports = (send) => {
8+
return promisify(function get (path, opts, cb) {
9+
if (typeof opts === 'function' && !cb) {
10+
cb = opts
11+
opts = {}
12+
}
13+
14+
// opts is the real callback -- 'cb' is being injected by promisify
15+
if (typeof opts === 'function' && typeof cb === 'function') {
16+
cb = opts
17+
opts = {}
18+
}
19+
20+
try {
21+
path = cleanMultihash(path)
22+
} catch (err) {
23+
return cb(err)
24+
}
25+
26+
var sendWithTransform = send.withTransform(tarStreamToObjects)
27+
28+
return sendWithTransform('get', path, opts, null, cb)
29+
})
30+
}

src/clean-multihash.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict'
2+
3+
const bs58 = require('bs58')
4+
const isIPFS = require('is-ipfs')
5+
6+
module.exports = function (multihash) {
7+
if (!isIPFS.multihash(multihash)) {
8+
throw new Error('not valid multihash')
9+
}
10+
if (Buffer.isBuffer(multihash)) {
11+
return bs58.encode(multihash)
12+
}
13+
return multihash
14+
}
15+

src/load-commands.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function requireCommands () {
1313
dht: require('./api/dht'),
1414
diag: require('./api/diag'),
1515
id: require('./api/id'),
16+
get: require('./api/get'),
1617
log: require('./api/log'),
1718
ls: require('./api/ls'),
1819
mount: require('./api/mount'),
@@ -33,6 +34,12 @@ function requireCommands () {
3334
const files = require('./api/files')(send)
3435
files.add = require('./api/add')(send)
3536
files.createAddStream = require('./api/add-stream.js')(send)
37+
files.get = require('./api/get')(send)
38+
39+
// aliases
40+
cmds.add = files.add
41+
cmds.createAddStream = files.createAddStream
42+
cmds.get = files.get
3643

3744
return files
3845
}

src/request-api.js

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,27 @@ const Wreck = require('wreck')
44
const Qs = require('qs')
55
const ndjson = require('ndjson')
66
const getFilesStream = require('./get-files-stream')
7+
const Counter = require('passthrough-counter')
78

89
const isNode = require('detect-node')
910

1011
// -- Internal
1112

1213
function parseChunkedJson (res, cb) {
1314
const parsed = []
15+
const c = new Counter()
1416
res
17+
.pipe(c)
1518
.pipe(ndjson.parse())
16-
.on('data', parsed.push.bind(parsed))
17-
.on('end', () => cb(null, parsed))
19+
.on('data', (obj) => {
20+
parsed.push(obj)
21+
})
22+
.on('end', () => {
23+
cb(null, parsed)
24+
})
1825
}
1926

20-
function onRes (buffer, cb) {
27+
function onRes (buffer, cb, uri) {
2128
return (err, res) => {
2229
if (err) {
2330
return cb(err)
@@ -42,10 +49,14 @@ function onRes (buffer, cb) {
4249
})
4350
}
4451

45-
if (stream && !buffer) return cb(null, res)
52+
if (stream && !buffer) {
53+
return cb(null, res)
54+
}
4655

4756
if (chunkedObjects) {
48-
if (isJson) return parseChunkedJson(res, cb)
57+
if (isJson) {
58+
return parseChunkedJson(res, cb)
59+
}
4960

5061
return Wreck.read(res, null, cb)
5162
}
@@ -56,6 +67,11 @@ function onRes (buffer, cb) {
5667

5768
function requestAPI (config, path, args, qs, files, buffer, cb) {
5869
qs = qs || {}
70+
71+
if (Array.isArray(files)) {
72+
qs.recursive = true
73+
}
74+
5975
if (Array.isArray(path)) path = path.join('/')
6076
if (args && !Array.isArray(args)) args = [args]
6177
if (args) qs.arg = args
@@ -67,10 +83,6 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
6783
delete qs.r
6884
}
6985

70-
if (!isNode && qs.recursive && path === 'add') {
71-
return cb(new Error('Recursive uploads are not supported in the browser'))
72-
}
73-
7486
qs['stream-channels'] = true
7587

7688
let stream
@@ -104,7 +116,7 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
104116
opts.payload = stream
105117
}
106118

107-
return Wreck.request(opts.method, opts.uri, opts, onRes(buffer, cb))
119+
return Wreck.request(opts.method, opts.uri, opts, onRes(buffer, cb, opts.uri))
108120
}
109121

110122
// -- Interface
@@ -128,9 +140,9 @@ exports = module.exports = function getRequestAPI (config) {
128140
return requestAPI(config, path, args, qs, files, buffer, cb)
129141
}
130142

131-
// Wraps the 'send' function such that an asynchronous transform may be
132-
// applied to its result before passing it on to either its callback or
133-
// promise.
143+
// Wraps the 'send' function such that an asynchronous
144+
// transform may be applied to its result before
145+
// passing it on to either its callback or promise.
134146
send.withTransform = function (transform) {
135147
return function (path, args, qs, files, buffer, cb) {
136148
if (typeof buffer === 'function') {

src/tar-stream-to-objects.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict'
2+
3+
const tar = require('tar-stream')
4+
const Readable = require('readable-stream')
5+
6+
// transform tar stream into readable stream of
7+
// { path: 'string', content: Readable }
8+
module.exports = function (err, res, send, done) {
9+
if (err) {
10+
return done(err)
11+
}
12+
13+
var ex = tar.extract()
14+
res.pipe(ex)
15+
16+
var objStream = new Readable({ objectMode: true })
17+
objStream._read = function noop () {}
18+
19+
ex.on('entry', function (header, stream, next) {
20+
objStream.push({
21+
path: header.name,
22+
content: header.type !== 'directory' ? stream : null
23+
})
24+
next()
25+
})
26+
ex.on('finish', () => {
27+
objStream.push(null)
28+
})
29+
30+
done(null, objStream)
31+
}
32+

tasks/daemons.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict'
2+
/* eslint max-nested-callbacks: ["error", 8] */ // TODO reduce nesteness
23

34
const gulp = require('gulp')
45
const fs = require('fs')

test/api/block.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-env mocha */
2+
/* eslint max-nested-callbacks: ["error", 8] */
23
/* globals apiClients */
34
'use strict'
45

test/api/bootstrap.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-env mocha */
2+
/* eslint max-nested-callbacks: ["error", 8] */
23
/* globals apiClients */
34
'use strict'
45

test/api/config.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-env mocha */
2+
/* eslint max-nested-callbacks: ["error", 8] */
23
/* globals apiClients */
34
'use strict'
45

test/api/files.spec.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-env mocha */
2+
/* eslint max-nested-callbacks: ["error", 8] */
23
/* globals apiClients */
34
'use strict'
45

0 commit comments

Comments
 (0)