diff --git a/SPEC/BITSWAP.md b/SPEC/BITSWAP.md index 00bc5fc1d..28949c005 100644 --- a/SPEC/BITSWAP.md +++ b/SPEC/BITSWAP.md @@ -4,13 +4,58 @@ * [bitswap.unwant](#bitswapunwant) * [bitswap.stat](#bitswapstat) -#### `bitswap.wantlist` +#### `bitswap.unwant` -(not spec'ed yet) +> Removes a given block from your wantlist -#### `bitswap.unwant` +##### `Go` **WIP** + +##### `JavaScript` - ipfs.bitswap.unwant(cid, [callback]) + +`cid` is a [cid][cid] which can be passed as: + +- CID, a CID instance +- String, the base58 encoded version of the multihash + +`callback` must follow `function (err) {}` signature, where `err` is an error if the operation was not successful. + + **Example:** + + ```JavaScript + ipfs.bitswap.unwant('QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', (err) => { + if (err) throw err + console.log('Done') + }) + ``` + +##### `Go` **WIP** + +### `bitswap.wantlist` + +> Returns the wantlist, optionally filtered by peer ID -(not spec'ed yet) +#### `Go` **WIP** + +#### `JavaScript` - ipfs.bitswap.wantlist([peerId], [callback]) + +`callback` must follow `function (err, list) {}` signature, where `err` is an error if the operation was not successful. `list` is an Object containing the following keys: + +- `Keys` An array of objects containing the following keys: + - `/` A string multihash + +If no `callback` is passed, a promise is returned. + +**Example:** + +```JavaScript +ipfs.bitswap.wantlist((err, list) => console.log(list)) + +// { Keys: [{ '/': 'QmHash' }] } + +ipfs.bitswap.wantlist(peerId, (err, list) => console.log(list)) + +// { Keys: [{ '/': 'QmHash' }] } +``` #### `bitswap.stat` diff --git a/js/src/bitswap.js b/js/src/bitswap.js new file mode 100644 index 000000000..0999e9da4 --- /dev/null +++ b/js/src/bitswap.js @@ -0,0 +1,159 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const series = require('async/series') +const expect = chai.expect +const statsTests = require('./utils/stats') +const spawn = require('./utils/spawn') +chai.use(dirtyChai) +const CID = require('cids') + +module.exports = (common) => { + describe('.bitswap online', () => { + let ipfsA + let ipfsB + let withGo + let ipfsBId + const key = 'QmUBdnXXPyoDFXj3Hj39dNJ5VkN3QFRskXxcGaYFBB8CNR' + + before(function (done) { + // CI takes longer to instantiate the daemon, so we need to increase the + // timeout for the before step + this.timeout(60 * 250) + + common.setup((err, factory) => { + expect(err).to.not.exist() + series([ + (cb) => spawn.spawnNodeWithId(factory, (err, node) => { + expect(err).to.not.exist() + ipfsA = node + withGo = node.peerId.agentVersion.startsWith('go-ipfs') + cb() + }), + (cb) => spawn.spawnNodeWithId(factory, (err, node) => { + expect(err).to.not.exist() + ipfsB = node + ipfsBId = node.peerId + ipfsB.block.get(new CID(key)) + .then(() => {}) + .catch(() => {}) + ipfsA.swarm.connect(ipfsBId.addresses[0], (err) => { + expect(err).to.not.exist() + setTimeout(cb, 350) + }) + }) + ], done) + }) + }) + + after((done) => common.teardown(done)) + + it('.stat', (done) => { + ipfsB.bitswap.stat((err, stats) => { + expect(err).to.not.exist() + statsTests.expectIsBitswap(err, stats) + done() + }) + }) + + it('.wantlist', (done) => { + ipfsB.bitswap.wantlist((err, list) => { + expect(err).to.not.exist() + expect(list.Keys).to.have.length(1) + expect(list.Keys[0]['/']).to.equal(key) + done() + }) + }) + + it('.wantlist peerid', (done) => { + ipfsA.bitswap.wantlist(ipfsBId.id, (err, list) => { + expect(err).to.not.exist() + expect(list.Keys[0]['/']).to.equal(key) + done() + }) + }) + + it('.unwant', function (done) { + if (withGo) { + this.skip() + } + ipfsB.bitswap.unwant(key, (err) => { + expect(err).to.not.exist() + ipfsB.bitswap.wantlist((err, list) => { + expect(err).to.not.exist() + expect(list.Keys).to.be.empty() + done() + }) + }) + }) + }) + + describe('.bitswap offline', () => { + let ipfs + + before(function (done) { + // CI takes longer to instantiate the daemon, so we need to increase the + // timeout for the before step + this.timeout(60 * 1000) + + common.setup((err, factory) => { + expect(err).to.not.exist() + factory.spawnNode((err, node) => { + expect(err).to.not.exist() + ipfs = node + ipfs.id((err, id) => { + expect(err).to.not.exist() + ipfs.stop((err) => { + // TODO: go-ipfs returns an error, https://github.com/ipfs/go-ipfs/issues/4078 + if (!id.agentVersion.startsWith('go-ipfs')) { + expect(err).to.not.exist() + } + done() + }) + }) + }) + }) + }) + + it('.stat gives error while offline', (done) => { + ipfs.bitswap.stat((err, stats) => { + expect(err).to.exist() + // When run against core we get our expected error, when run + // as part of the http tests we get a connection refused + if (err.code !== 'ECONNREFUSED') { + expect(err).to.match(/online mode/) + } + expect(stats).to.not.exist() + done() + }) + }) + + it('.wantlist gives error if offline', (done) => { + ipfs.bitswap.wantlist((err, list) => { + expect(err).to.exist() + // When run against core we get our expected error, when run + // as part of the http tests we get a connection refused + if (err.code !== 'ECONNREFUSED') { + expect(err).to.match(/online mode/) + } + expect(list).to.not.exist() + done() + }) + }) + + it('.unwant gives error if offline', (done) => { + const key = 'QmUBdnXXPyoDFXj3Hj39dNJ5VkN3QFRskXxcGaYFBB8CNR' + ipfs.bitswap.unwant(key, (err) => { + expect(err).to.exist() + // When run against core we get our expected error, when run + // as part of the http tests we get a connection refused + if (err.code !== 'ECONNREFUSED') { + expect(err).to.match(/online mode/) + } + done() + }) + }) + }) +} diff --git a/js/src/index.js b/js/src/index.js index dd2012e9f..07904c431 100644 --- a/js/src/index.js +++ b/js/src/index.js @@ -19,3 +19,4 @@ exports.repo = require('./repo') exports.bootstrap = require('./bootstrap') exports.types = require('./types') exports.util = require('./util') +exports.bitswap = require('./bitswap')