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

feat: Add promise based api #200

Merged
merged 1 commit into from
Feb 8, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ node_js:
- '5'
- stable

addons:
firefox: 'latest'

before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ If you omit the host and port, the api will parse `window.host`, and use this in
var ipfs = window.ipfsAPI()
```

### Using Promises

If you do not pass in a callback all api functions will return a `Promise`, for example

```js
ipfs.id()
.then(function (id) {
console.log('my id is: ', id)
})
```

This relies on a global `Promise` object. If you are in an environemnt where that is not
yet available you need to bring your own polyfill.

#### Gotchas

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).
Expand Down
29 changes: 22 additions & 7 deletions src/api/dht.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,38 @@ module.exports = send => {
opts = null
}

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

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

if (res.Type === 5) {
cb(null, res.Extra)
done(null, res.Extra)
} else {
let error = new Error('key was not found (type 6)')
cb(error)
done(error)
}
})
}

if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
const done = (err, res) => {
if (err) throw err
return res
}

return send('dht/get', key, opts)
.then(
res => handleResult(done, null, res),
err => handleResult(done, err)
)
}

return send('dht/get', key, opts, null, handleResult.bind(null, cb))
},
put (key, value, opts, cb) {
if (typeof (opts) === 'function' && !cb) {
Expand Down
5 changes: 5 additions & 0 deletions src/api/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ const ndjson = require('ndjson')
module.exports = send => {
return {
tail (cb) {
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
return send('log/tail', null, {}, null, false)
.then(res => res.pipe(ndjson.parse()))
}

return send('log/tail', null, {}, null, false, (err, res) => {
if (err) return cb(err)
cb(null, res.pipe(ndjson.parse()))
Expand Down
5 changes: 5 additions & 0 deletions src/api/ping.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

module.exports = send => {
return function ping (id, cb) {
if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
return send('ping', id, {n: 1}, null)
.then(res => res[1])
}

return send('ping', id, { n: 1 }, null, function (err, res) {
if (err) return cb(err, null)
cb(null, res[1])
Expand Down
23 changes: 17 additions & 6 deletions src/request-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
if (args) qs.arg = args
if (files && !Array.isArray(files)) files = [files]

if (typeof buffer === 'function') {
cb = buffer
buffer = false
}

if (qs.r) {
qs.recursive = qs.r
delete qs.r // From IPFS 0.4.0, it throw an error when both r and recursive are passed
Expand Down Expand Up @@ -116,5 +111,21 @@ function requestAPI (config, path, args, qs, files, buffer, cb) {
// -- Interface

exports = module.exports = function getRequestAPI (config) {
return requestAPI.bind(null, config)
return function (path, args, qs, files, buffer, cb) {
if (typeof buffer === 'function') {
cb = buffer
buffer = false
}

if (typeof cb !== 'function' && typeof Promise !== 'undefined') {
return new Promise(function (resolve, reject) {
requestAPI(config, path, args, qs, files, buffer, function (err, res) {
if (err) return reject(err)
resolve(res)
})
})
}

return requestAPI(config, path, args, qs, files, buffer, cb)
}
}
11 changes: 11 additions & 0 deletions test/api/add.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,15 @@ describe('.add', () => {
done()
})
})

describe('promise', () => {
it('add buffer', () => {
let buf = new Buffer(testfile)
return apiClients['a'].add(buf)
.then(res => {
expect(res).to.have.length(1)
expect(res[0]).to.have.property('Hash', 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
})
})
})
})
30 changes: 30 additions & 0 deletions test/api/block.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,34 @@ describe('.block', () => {
done()
})
})

describe('promise', () => {
it('block.put', () => {
return apiClients['a'].block.put(blorb)
.then(res => {
expect(res).to.have.a.property('Key', 'QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ')
})
})

it('block.get', done => {
return apiClients['a'].block.get(blorbKey)
.then(res => {
let buf = ''
res
.on('data', function (data) { buf += data })
.on('end', function () {
expect(buf).to.be.equal('blorb')
done()
})
})
})

it('block.stat', () => {
return apiClients['a'].block.stat(blorbKey)
.then(res => {
expect(res).to.have.property('Key')
expect(res).to.have.property('Size')
})
})
})
})
16 changes: 16 additions & 0 deletions test/api/cat.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,20 @@ describe('.cat', () => {
})
})
})

describe('promise', () => {
it('cat', done => {
return apiClients['a'].cat('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
.then(res => {
let buf = ''
res
.on('error', err => { throw err })
.on('data', data => buf += data)
.on('end', () => {
expect(buf).to.be.equal(testfile.toString())
done()
})
})
})
})
})
9 changes: 9 additions & 0 deletions test/api/commands.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ describe('.commands', () => {
done()
})
})

describe('promise', () => {
it('lists commands', () => {
return apiClients['a'].commands()
.then(res => {
expect(res).to.exist
})
})
})
})
33 changes: 33 additions & 0 deletions test/api/config.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,37 @@ describe('.config', () => {
done()
})
})

describe('promise', () => {
it('.config.{set, get}', () => {
const confKey = 'arbitraryKey'
const confVal = 'arbitraryVal'

return apiClients['a'].config.set(confKey, confVal)
.then(res => {
return apiClients['a'].config.get(confKey)
})
.then(res => {
expect(res).to.have.a.property('Value', confVal)
})
})

it('.config.show', () => {
return apiClients['c'].config.show()
.then(res => {
expect(res).to.exist
})
})

it('.config.replace', () => {
if (!isNode) {
return
}

return apiClients['c'].config.replace(__dirname + '/../r-config.json')
.then(res => {
expect(res).to.be.equal(null)
})
})
})
})
23 changes: 23 additions & 0 deletions test/api/dht.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,27 @@ describe('.dht', () => {
done()
})
})

describe('promise', () => {
it('returns an error when getting a non-existent key from the DHT', () => {
return apiClients['a'].dht.get('non-existent', {timeout: '100ms'})
.catch(err => {
expect(err).to.be.an.instanceof(Error)
})
})

it('puts a key value pair in the DHT', () => {
return apiClients['a'].dht.put('scope', 'interplanetary')
.then(res => {
expect(res).to.be.an('array')
})
})

it('.dht.findprovs', () => {
return apiClients['a'].dht.findprovs('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
.then(res => {
expect(res).to.be.an('array')
})
})
})
})
18 changes: 18 additions & 0 deletions test/api/diag.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,22 @@ describe('.diag', () => {
done()
})
})

describe('promise', () => {
it('.diag.net', () => {
return apiClients['a'].diag.net()
.then(res => {
expect(res).to.exist
})
})

it('.diag.sys', () => {
return apiClients['a'].diag.sys()
.then(res => {
expect(res).to.exist
expect(res).to.have.a.property('memory')
expect(res).to.have.a.property('diskinfo')
})
})
})
})
10 changes: 10 additions & 0 deletions test/api/id.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,14 @@ describe('.id', () => {
done()
})
})

describe('promise', () => {
it('id', () => {
return apiClients['a'].id()
.then(res => {
expect(res).to.have.a.property('ID')
expect(res).to.have.a.property('PublicKey')
})
})
})
})
12 changes: 12 additions & 0 deletions test/api/log.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,16 @@ describe('.log', () => {
})
})
})

describe('promise', () => {
it('.log.tail', done => {
return apiClients['a'].log.tail()
.then(res => {
res.once('data', obj => {
expect(obj).to.be.an('object')
done()
})
})
})
})
})
29 changes: 29 additions & 0 deletions test/api/ls.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,33 @@ describe('ls', function () {
done()
})
})

describe('promise', () => {
it('should correctly retrieve links', () => {
if (!isNode) return

return apiClients['a'].ls('QmSzLpCVbWnEm3XoTWnv6DT6Ju5BsVoLhzvxKXZeQ2cmdg')
.then(res => {
expect(res).to.have.a.property('Objects')
expect(res.Objects[0]).to.have.a.property('Links')
expect(res.Objects[0]).to.have.property('Hash', 'QmSzLpCVbWnEm3XoTWnv6DT6Ju5BsVoLhzvxKXZeQ2cmdg')
})
})

it('should correctly handle a nonexisting hash', () => {
return apiClients['a'].ls('surelynotavalidhashheh?')
.catch(err => {
expect(err).to.exist
})
})

it('should correctly handle a nonexisting path', () => {
if (!isNode) return

return apiClients['a'].ls('QmTDH2RXGn8XyDAo9YyfbZAUXwL1FCr44YJCN9HBZmL9Gj/folder_that_isnt_there')
.catch(err => {
expect(err).to.exist
})
})
})
})
Loading