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

Commit 9b74841

Browse files
feat: Add promise based api
All methods return a promise when not passed a callback Closes #80
1 parent 934e869 commit 9b74841

23 files changed

+473
-35
lines changed

.travis.yml

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ node_js:
44
- '5'
55
- stable
66

7+
addons:
8+
firefox: 'latest'
9+
710
before_script:
811
- export DISPLAY=:99.0
912
- sh -e /etc/init.d/xvfb start

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ If you omit the host and port, the api will parse `window.host`, and use this in
4949
var ipfs = window.ipfsAPI()
5050
```
5151

52+
### Using Promises
53+
54+
If you do not pass in a callback all api functions will return a `Promise`, for example
55+
56+
```js
57+
ipfs.id()
58+
.then(function (id) {
59+
console.log('my id is: ', id)
60+
})
61+
```
62+
63+
This relies on a global `Promise` object. If you are in an environemnt where that is not
64+
yet available you need to bring your own polyfill.
65+
5266
#### Gotchas
5367

5468
When using the api from script tag for things that require buffers (`ipfs.add`, for example), you will have to use either the exposed `ipfs.Buffer`, that works just like a node buffer, or use this [browser buffer](https://github.com/feross/buffer).

src/api/dht.js

+22-7
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,38 @@ module.exports = send => {
1111
opts = null
1212
}
1313

14-
return send('dht/get', key, opts, null, (err, res) => {
15-
if (err) return cb(err)
16-
if (!res) return cb(new Error('empty response'))
17-
if (res.length === 0) return cb(new Error('no value returned for key'))
14+
const handleResult = (done, err, res) => {
15+
if (err) return done(err)
16+
if (!res) return done(new Error('empty response'))
17+
if (res.length === 0) return done(new Error('no value returned for key'))
1818

1919
// Inconsistent return values in the browser vs node
2020
if (Array.isArray(res)) {
2121
res = res[0]
2222
}
2323

2424
if (res.Type === 5) {
25-
cb(null, res.Extra)
25+
done(null, res.Extra)
2626
} else {
2727
let error = new Error('key was not found (type 6)')
28-
cb(error)
28+
done(error)
2929
}
30-
})
30+
}
31+
32+
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
33+
const done = (err, res) => {
34+
if (err) throw err
35+
return res
36+
}
37+
38+
return send('dht/get', key, opts)
39+
.then(
40+
res => handleResult(done, null, res),
41+
err => handleResult(done, err)
42+
)
43+
}
44+
45+
return send('dht/get', key, opts, null, handleResult.bind(null, cb))
3146
},
3247
put (key, value, opts, cb) {
3348
if (typeof (opts) === 'function' && !cb) {

src/api/log.js

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ const ndjson = require('ndjson')
55
module.exports = send => {
66
return {
77
tail (cb) {
8+
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
9+
return send('log/tail', null, {}, null, false)
10+
.then(res => res.pipe(ndjson.parse()))
11+
}
12+
813
return send('log/tail', null, {}, null, false, (err, res) => {
914
if (err) return cb(err)
1015
cb(null, res.pipe(ndjson.parse()))

src/api/ping.js

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
module.exports = send => {
44
return function ping (id, cb) {
5+
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
6+
return send('ping', id, {n: 1}, null)
7+
.then(res => res[1])
8+
}
9+
510
return send('ping', id, { n: 1 }, null, function (err, res) {
611
if (err) return cb(err, null)
712
cb(null, res[1])

src/request-api.js

+17-6
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,6 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
6363
if (args) qs.arg = args
6464
if (files && !Array.isArray(files)) files = [files]
6565

66-
if (typeof buffer === 'function') {
67-
cb = buffer
68-
buffer = false
69-
}
70-
7166
if (qs.r) {
7267
qs.recursive = qs.r
7368
delete qs.r // From IPFS 0.4.0, it throw an error when both r and recursive are passed
@@ -116,5 +111,21 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
116111
// -- Interface
117112

118113
exports = module.exports = function getRequestAPI (config) {
119-
return requestAPI.bind(null, config)
114+
return function (path, args, qs, files, buffer, cb) {
115+
if (typeof buffer === 'function') {
116+
cb = buffer
117+
buffer = false
118+
}
119+
120+
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
121+
return new Promise(function (resolve, reject) {
122+
requestAPI(config, path, args, qs, files, buffer, function (err, res) {
123+
if (err) return reject(err)
124+
resolve(res)
125+
})
126+
})
127+
}
128+
129+
return requestAPI(config, path, args, qs, files, buffer, cb)
130+
}
120131
}

test/api/add.spec.js

+11
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,15 @@ describe('.add', () => {
118118
done()
119119
})
120120
})
121+
122+
describe('promise', () => {
123+
it('add buffer', () => {
124+
let buf = new Buffer(testfile)
125+
return apiClients['a'].add(buf)
126+
.then(res => {
127+
expect(res).to.have.length(1)
128+
expect(res[0]).to.have.property('Hash', 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
129+
})
130+
})
131+
})
121132
})

test/api/block.spec.js

+30
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,34 @@ describe('.block', () => {
3434
done()
3535
})
3636
})
37+
38+
describe('promise', () => {
39+
it('block.put', () => {
40+
return apiClients['a'].block.put(blorb)
41+
.then(res => {
42+
expect(res).to.have.a.property('Key', 'QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
43+
})
44+
})
45+
46+
it('block.get', done => {
47+
return apiClients['a'].block.get(blorbKey)
48+
.then(res => {
49+
let buf = ''
50+
res
51+
.on('data', function (data) { buf += data })
52+
.on('end', function () {
53+
expect(buf).to.be.equal('blorb')
54+
done()
55+
})
56+
})
57+
})
58+
59+
it('block.stat', () => {
60+
return apiClients['a'].block.stat(blorbKey)
61+
.then(res => {
62+
expect(res).to.have.property('Key')
63+
expect(res).to.have.property('Size')
64+
})
65+
})
66+
})
3767
})

test/api/cat.spec.js

+16
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,20 @@ describe('.cat', () => {
4646
})
4747
})
4848
})
49+
50+
describe('promise', () => {
51+
it('cat', done => {
52+
return apiClients['a'].cat('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
53+
.then(res => {
54+
let buf = ''
55+
res
56+
.on('error', err => { throw err })
57+
.on('data', data => buf += data)
58+
.on('end', () => {
59+
expect(buf).to.be.equal(testfile.toString())
60+
done()
61+
})
62+
})
63+
})
64+
})
4965
})

test/api/commands.spec.js

+9
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,13 @@ describe('.commands', () => {
88
done()
99
})
1010
})
11+
12+
describe('promise', () => {
13+
it('lists commands', () => {
14+
return apiClients['a'].commands()
15+
.then(res => {
16+
expect(res).to.exist
17+
})
18+
})
19+
})
1120
})

test/api/config.spec.js

+33
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,37 @@ describe('.config', () => {
3434
done()
3535
})
3636
})
37+
38+
describe('promise', () => {
39+
it('.config.{set, get}', () => {
40+
const confKey = 'arbitraryKey'
41+
const confVal = 'arbitraryVal'
42+
43+
return apiClients['a'].config.set(confKey, confVal)
44+
.then(res => {
45+
return apiClients['a'].config.get(confKey)
46+
})
47+
.then(res => {
48+
expect(res).to.have.a.property('Value', confVal)
49+
})
50+
})
51+
52+
it('.config.show', () => {
53+
return apiClients['c'].config.show()
54+
.then(res => {
55+
expect(res).to.exist
56+
})
57+
})
58+
59+
it('.config.replace', () => {
60+
if (!isNode) {
61+
return
62+
}
63+
64+
return apiClients['c'].config.replace(__dirname + '/../r-config.json')
65+
.then(res => {
66+
expect(res).to.be.equal(null)
67+
})
68+
})
69+
})
3770
})

test/api/dht.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,27 @@ describe('.dht', () => {
3636
done()
3737
})
3838
})
39+
40+
describe('promise', () => {
41+
it('returns an error when getting a non-existent key from the DHT', () => {
42+
return apiClients['a'].dht.get('non-existent', {timeout: '100ms'})
43+
.catch(err => {
44+
expect(err).to.be.an.instanceof(Error)
45+
})
46+
})
47+
48+
it('puts a key value pair in the DHT', () => {
49+
return apiClients['a'].dht.put('scope', 'interplanetary')
50+
.then(res => {
51+
expect(res).to.be.an('array')
52+
})
53+
})
54+
55+
it('.dht.findprovs', () => {
56+
return apiClients['a'].dht.findprovs('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
57+
.then(res => {
58+
expect(res).to.be.an('array')
59+
})
60+
})
61+
})
3962
})

test/api/diag.spec.js

+18
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,22 @@ describe('.diag', () => {
1818
done()
1919
})
2020
})
21+
22+
describe('promise', () => {
23+
it('.diag.net', () => {
24+
return apiClients['a'].diag.net()
25+
.then(res => {
26+
expect(res).to.exist
27+
})
28+
})
29+
30+
it('.diag.sys', () => {
31+
return apiClients['a'].diag.sys()
32+
.then(res => {
33+
expect(res).to.exist
34+
expect(res).to.have.a.property('memory')
35+
expect(res).to.have.a.property('diskinfo')
36+
})
37+
})
38+
})
2139
})

test/api/id.spec.js

+10
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ describe('.id', () => {
99
done()
1010
})
1111
})
12+
13+
describe('promise', () => {
14+
it('id', () => {
15+
return apiClients['a'].id()
16+
.then(res => {
17+
expect(res).to.have.a.property('ID')
18+
expect(res).to.have.a.property('PublicKey')
19+
})
20+
})
21+
})
1222
})

test/api/log.spec.js

+12
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,16 @@ describe('.log', () => {
1313
})
1414
})
1515
})
16+
17+
describe('promise', () => {
18+
it('.log.tail', done => {
19+
return apiClients['a'].log.tail()
20+
.then(res => {
21+
res.once('data', obj => {
22+
expect(obj).to.be.an('object')
23+
done()
24+
})
25+
})
26+
})
27+
})
1628
})

test/api/ls.spec.js

+29
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,33 @@ describe('ls', function () {
3333
done()
3434
})
3535
})
36+
37+
describe('promise', () => {
38+
it('should correctly retrieve links', () => {
39+
if (!isNode) return
40+
41+
return apiClients['a'].ls('QmSzLpCVbWnEm3XoTWnv6DT6Ju5BsVoLhzvxKXZeQ2cmdg')
42+
.then(res => {
43+
expect(res).to.have.a.property('Objects')
44+
expect(res.Objects[0]).to.have.a.property('Links')
45+
expect(res.Objects[0]).to.have.property('Hash', 'QmSzLpCVbWnEm3XoTWnv6DT6Ju5BsVoLhzvxKXZeQ2cmdg')
46+
})
47+
})
48+
49+
it('should correctly handle a nonexisting hash', () => {
50+
return apiClients['a'].ls('surelynotavalidhashheh?')
51+
.catch(err => {
52+
expect(err).to.exist
53+
})
54+
})
55+
56+
it('should correctly handle a nonexisting path', () => {
57+
if (!isNode) return
58+
59+
return apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there')
60+
.catch(err => {
61+
expect(err).to.exist
62+
})
63+
})
64+
})
3665
})

0 commit comments

Comments
 (0)