From 9c2920d3abe12f319382e56764f8c29f63c820ee Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2019 11:59:10 +0000 Subject: [PATCH 01/24] chore: update merge-options to version 2.0.0 (#1131) From 7007e5a3349f5b67398335c64b0c86f4d14733f0 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2019 11:59:45 +0000 Subject: [PATCH 02/24] chore: update ky to version 0.15.0 (#1118) From c9a0e57f983e34f017a21c96b88c2600d2b9cd27 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 5 Nov 2019 09:44:16 +0000 Subject: [PATCH 03/24] docs: add kebab case breaking change (#1138) resolves #1137 --- CHANGELOG.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3634fa56d..049e2b123 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,16 +51,15 @@ ### BREAKING CHANGES -* ```javascript -Promise<{oldCfg, newCfg}> ipfs.config.profile(name, opts) +* Configuration profiles API has changed: + ```javascript + Promise<{oldCfg, newCfg}> ipfs.config.profile(name, opts) -// is now -Promise<{old, new}> ipfs.config.profiles.apply(name, opts) -``` - -Possibly contentious; + // is now + Promise<{old, new}> ipfs.config.profiles.apply(name, opts) + ``` -Adds `callbackify` as a dependency, see https://github.com/ipfs/js-ipfs/issues/2506 +* Possibly contentious; Adds `callbackify` as a dependency, see https://github.com/ipfs/js-ipfs/issues/2506 for discussion. @@ -138,7 +137,9 @@ for discussion. # [35.0.0](https://github.com/ipfs/js-ipfs-http-client/compare/v34.0.0...v35.0.0) (2019-09-04) +### BREAKING CHANGES +Kebab case options (e.g. `wrap-with-directory`) are no longer supported in `ipfs.add`. Use camel case instead (e.g. `wrapWithDirectory`). # [34.0.0](https://github.com/ipfs/js-ipfs-http-client/compare/v33.1.1...v34.0.0) (2019-08-29) From da7dae73e08a7ef929fd9580714b6aeee5c60fc0 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 5 Nov 2019 10:10:06 +0000 Subject: [PATCH 04/24] chore(package): update aegir to version 20.4.1 (#1140) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5bd10d59b..b1d65cf42 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "through2": "^3.0.1" }, "devDependencies": { - "aegir": "^20.3.1", + "aegir": "^20.4.1", "browser-process-platform": "~0.1.1", "cross-env": "^6.0.0", "go-ipfs-dep": "^0.4.22", From 57bdc394c8cb92be675845f50ea593f149d18214 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 5 Nov 2019 10:30:09 +0000 Subject: [PATCH 05/24] chore(package): update nock to version 11.4.0 (#1141) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b1d65cf42..2b7a24ba9 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "go-ipfs-dep": "^0.4.22", "interface-ipfs-core": "^0.117.2", "ipfsd-ctl": "^0.47.1", - "nock": "^11.3.2", + "nock": "^11.4.0", "stream-equal": "^1.1.1" }, "engines": { From 29b3b4d387ea4e56b53bb1bbf984486d1593bcfd Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 5 Nov 2019 11:26:41 +0000 Subject: [PATCH 06/24] chore(package): update it-glob to version 0.0.6 (#1142) Closes #1108 From 9b1589c23946ace07483e5004d35880114bde729 Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2019 12:16:17 +0000 Subject: [PATCH 07/24] chore: update multiaddr to version 7.2.0 (#1136) * fix(package): update multiaddr to version 7.2.0 * fix: tests --- package.json | 2 +- test/constructor.spec.js | 2 +- test/node/swarm.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 2b7a24ba9..a45e2e32e 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "ky-universal": "^0.3.0", "lru-cache": "^5.1.1", "merge-options": "^2.0.0", - "multiaddr": "^6.0.6", + "multiaddr": "^7.2.0", "multibase": "~0.6.0", "multicodec": "~0.5.1", "multihashes": "~0.4.14", diff --git a/test/constructor.spec.js b/test/constructor.spec.js index e4a7eb1aa..c728c94c1 100644 --- a/test/constructor.spec.js +++ b/test/constructor.spec.js @@ -134,7 +134,7 @@ async function clientWorks (client) { function expectConfig (ipfs, { host, port, protocol, apiPath }) { const conf = ipfs.getEndpointConfig() expect(conf.host).to.be.oneOf([host, 'localhost', '']) - expect(conf.port).to.be.oneOf([port, '5001', 80]) + expect(conf.port.toString()).to.be.oneOf([port, '5001', '80']) expect(conf.protocol).to.equal(protocol || 'http') expect(conf['api-path']).to.equal(apiPath || '/api/v0/') } diff --git a/test/node/swarm.js b/test/node/swarm.js index 27d377904..b54690dc0 100644 --- a/test/node/swarm.js +++ b/test/node/swarm.js @@ -30,7 +30,7 @@ describe('.swarm.peers', function () { }) it('handles a go-ipfs <= 0.4.4 peer response', async () => { - const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] } + const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/p2p/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] } const scope = nock(apiUrl) .post('/api/v0/swarm/peers') @@ -42,7 +42,7 @@ describe('.swarm.peers', function () { expect(res).to.be.a('array') expect(res.length).to.equal(1) expect(res[0].error).to.not.exist() - expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') + expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/p2p/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') expect(res[0].peer.toB58String()).to.equal('QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') expect(scope.isDone()).to.equal(true) }) From 4131d09f9734e7d477aabb8a0873a2d3a40d18b1 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 6 Nov 2019 12:36:33 +0000 Subject: [PATCH 08/24] revert: chore: update multiaddr to version 7.2.0 (#1136) (#1143) This reverts commit 9b1589c23946ace07483e5004d35880114bde729. License: MIT Signed-off-by: Alan Shaw --- package.json | 2 +- test/constructor.spec.js | 2 +- test/node/swarm.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index a45e2e32e..2b7a24ba9 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "ky-universal": "^0.3.0", "lru-cache": "^5.1.1", "merge-options": "^2.0.0", - "multiaddr": "^7.2.0", + "multiaddr": "^6.0.6", "multibase": "~0.6.0", "multicodec": "~0.5.1", "multihashes": "~0.4.14", diff --git a/test/constructor.spec.js b/test/constructor.spec.js index c728c94c1..e4a7eb1aa 100644 --- a/test/constructor.spec.js +++ b/test/constructor.spec.js @@ -134,7 +134,7 @@ async function clientWorks (client) { function expectConfig (ipfs, { host, port, protocol, apiPath }) { const conf = ipfs.getEndpointConfig() expect(conf.host).to.be.oneOf([host, 'localhost', '']) - expect(conf.port.toString()).to.be.oneOf([port, '5001', '80']) + expect(conf.port).to.be.oneOf([port, '5001', 80]) expect(conf.protocol).to.equal(protocol || 'http') expect(conf['api-path']).to.equal(apiPath || '/api/v0/') } diff --git a/test/node/swarm.js b/test/node/swarm.js index b54690dc0..27d377904 100644 --- a/test/node/swarm.js +++ b/test/node/swarm.js @@ -30,7 +30,7 @@ describe('.swarm.peers', function () { }) it('handles a go-ipfs <= 0.4.4 peer response', async () => { - const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/p2p/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] } + const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] } const scope = nock(apiUrl) .post('/api/v0/swarm/peers') @@ -42,7 +42,7 @@ describe('.swarm.peers', function () { expect(res).to.be.a('array') expect(res.length).to.equal(1) expect(res[0].error).to.not.exist() - expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/p2p/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') + expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') expect(res[0].peer.toB58String()).to.equal('QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') expect(scope.isDone()).to.equal(true) }) From 4acd43ecd58964eb505b0043b97f6c66324285ab Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Thu, 7 Nov 2019 15:14:49 +0000 Subject: [PATCH 09/24] chore(package): update form-data to version 3.0.0 (#1146) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2b7a24ba9..bbcb012b7 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "event-iterator": "^1.2.0", "explain-error": "^1.0.4", "flatmap": "0.0.3", - "form-data": "^2.5.1", + "form-data": "^3.0.0", "fs-extra": "^8.1.0", "glob": "^7.1.3", "ipfs-block": "~0.8.1", From 2d9afc8ce8487b340ece5d5f1091300b1f5278b4 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Thu, 7 Nov 2019 23:53:36 +0100 Subject: [PATCH 10/24] feat: support name.resolve of peerid as cid (#1145) * feat: support name.resolve of peerid as cid This is a hacky way to support CIDs when API is go-ipfs 0.4.22 or older (convert toBase58btc before sending) License: MIT Signed-off-by: Marcin Rataj --- package.json | 2 +- test/interface.spec.js | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index bbcb012b7..70cee49f2 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "browser-process-platform": "~0.1.1", "cross-env": "^6.0.0", "go-ipfs-dep": "^0.4.22", - "interface-ipfs-core": "^0.117.2", + "interface-ipfs-core": "^0.118.0", "ipfsd-ctl": "^0.47.1", "nock": "^11.4.0", "stream-equal": "^1.1.1" diff --git a/test/interface.spec.js b/test/interface.spec.js index 090246822..760962b38 100644 --- a/test/interface.spec.js +++ b/test/interface.spec.js @@ -176,7 +176,15 @@ describe('interface-ipfs-core tests', () => { spawnOptions: { args: ['--offline'] } - })) + }), { + skip: [ + // stop + { + name: 'should resolve a record from peerid as cidv1 in base32', + reason: 'TODO not implemented in go-ipfs yet: https://github.com/ipfs/go-ipfs/issues/5287' + } + ] + }) // TODO: uncomment after https://github.com/ipfs/interface-ipfs-core/pull/361 being merged and a new release tests.namePubsub(CommonFactory.create({ From c05c5ec407a43b4b0594720a16c6148b51cac017 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 8 Nov 2019 15:38:19 +0000 Subject: [PATCH 11/24] refactor: convert bitswap to async/await (#1149) --- src/bitswap/index.js | 16 ++++++--------- src/bitswap/stat.js | 31 +++++++++++++++++----------- src/bitswap/unwant.js | 38 ++++++++++++++++++----------------- src/bitswap/wantlist.js | 41 +++++++++++++++++++------------------- src/utils/load-commands.js | 4 ++-- 5 files changed, 67 insertions(+), 63 deletions(-) diff --git a/src/bitswap/index.js b/src/bitswap/index.js index 62f9fb58a..fb47d4da0 100644 --- a/src/bitswap/index.js +++ b/src/bitswap/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - wantlist: require('./wantlist')(send), - stat: require('./stat')(send), - unwant: require('./unwant')(send) - } -} +module.exports = (config) => ({ + wantlist: callbackify.variadic(require('./wantlist')(config)), + stat: callbackify.variadic(require('./stat')(config)), + unwant: callbackify.variadic(require('./unwant')(config)) +}) diff --git a/src/bitswap/stat.js b/src/bitswap/stat.js index f0770d47d..3795327bb 100644 --- a/src/bitswap/stat.js +++ b/src/bitswap/stat.js @@ -1,10 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') const Big = require('bignumber.js') -const transform = function (res, callback) { - callback(null, { +module.exports = configure(({ ky }) => { + return async (options) => { + options = options || {} + + const res = await ky.get('bitswap/stat', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() + + return toCoreInterface(res) + } +}) + +function toCoreInterface (res) { + return { provideBufLen: res.ProvideBufLen, wantlist: res.Wantlist || [], peers: res.Peers || [], @@ -14,13 +29,5 @@ const transform = function (res, callback) { dataSent: new Big(res.DataSent), dupBlksReceived: new Big(res.DupBlksReceived), dupDataReceived: new Big(res.DupDataReceived) - }) -} - -module.exports = (send) => { - return promisify((callback) => { - send.andTransform({ - path: 'bitswap/stat' - }, transform, callback) - }) + } } diff --git a/src/bitswap/unwant.js b/src/bitswap/unwant.js index 865fbc27b..9b2044d00 100644 --- a/src/bitswap/unwant.js +++ b/src/bitswap/unwant.js @@ -1,25 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') const CID = require('cids') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((cid, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return async (cid, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) - try { - cid = new CID(cid) - } catch (err) { - return callback(err) + if (typeof cid === 'string') { + searchParams.set('arg', cid) + } else { + searchParams.set('arg', new CID(cid).toString()) } - send({ - path: 'bitswap/unwant', - args: cid.toBaseEncodedString(), - qs: opts - }, callback) - }) -} + const res = await ky.get('bitswap/unwant', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res + } +}) diff --git a/src/bitswap/wantlist.js b/src/bitswap/wantlist.js index 6cd1e3868..3235de8a9 100644 --- a/src/bitswap/wantlist.js +++ b/src/bitswap/wantlist.js @@ -1,30 +1,29 @@ 'use strict' -const promisify = require('promisify-es6') const CID = require('cids') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((peerId, opts, callback) => { - if (typeof (peerId) === 'function') { - callback = peerId - opts = {} - peerId = null - } else if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return async (peerId, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) if (peerId) { - try { - opts.peer = new CID(peerId).toBaseEncodedString() - } catch (err) { - return callback(err) + if (typeof peerId === 'string') { + searchParams.set('peer', peerId) + } else { + searchParams.set('peer', new CID(peerId).toString()) } } - send({ - path: 'bitswap/wantlist', - qs: opts - }, callback) - }) -} + const res = await ky.get('bitswap/wantlist', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res + } +}) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 710b8396f..81948a54e 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -3,7 +3,8 @@ function requireCommands (send, config) { const cmds = { ...require('../files-regular')(config), - getEndpointConfig: require('../get-endpoint-config')(config) + getEndpointConfig: require('../get-endpoint-config')(config), + bitswap: require('../bitswap')(config) } const subCmds = { @@ -12,7 +13,6 @@ function requireCommands (send, config) { // Block block: require('../block'), - bitswap: require('../bitswap'), // Graph dag: require('../dag'), From 2275c2a09e6317f366d31a1ef54036d326bb50fb Mon Sep 17 00:00:00 2001 From: "greenkeeper[bot]" <23040076+greenkeeper[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2019 09:59:57 +0000 Subject: [PATCH 12/24] chore(package): update interface-ipfs-core to version 0.119.0 (#1151) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70cee49f2..1908c7de1 100644 --- a/package.json +++ b/package.json @@ -108,7 +108,7 @@ "browser-process-platform": "~0.1.1", "cross-env": "^6.0.0", "go-ipfs-dep": "^0.4.22", - "interface-ipfs-core": "^0.118.0", + "interface-ipfs-core": "^0.119.0", "ipfsd-ctl": "^0.47.1", "nock": "^11.4.0", "stream-equal": "^1.1.1" From 559a97d89b84e6bbb7d1c5cf41a7b8bf853a68da Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 12 Nov 2019 11:15:10 +0000 Subject: [PATCH 13/24] refactor: move files to root level (#1150) Moves remaining files that contain root level commands to the root of the src directory. This makes it easier for new contributors to find things. It also renames the `files-mfs` dir to `files` to reflect the fact that it lives in the "files" namespace currently. BREAKING CHANGE: files in `src/files-regular` have moved to `src`. The `src/files-mfs` directory has been renamed to `src/files`. If you were previously requiring files from these directories e.g. `require('ipfs-http-client/src/files-regular/add')` then please be aware that they have moved. License: MIT Signed-off-by: Alan Shaw --- src/files-regular/index.js | 100 ------------------ src/files-regular/refs.js | 63 ----------- src/{files-mfs => files}/cp.js | 0 src/{files-mfs => files}/flush.js | 0 src/{files-mfs => files}/index.js | 0 src/{files-mfs => files}/ls-pull-stream.js | 0 .../ls-readable-stream.js | 0 src/{files-mfs => files}/ls.js | 0 src/{files-mfs => files}/mkdir.js | 0 src/{files-mfs => files}/mv.js | 0 src/{files-mfs => files}/read-pull-stream.js | 0 .../read-readable-stream.js | 0 src/{files-mfs => files}/read.js | 0 src/{files-mfs => files}/rm.js | 0 src/{files-mfs => files}/stat.js | 0 src/{files-mfs => files}/write.js | 0 src/{files-regular => }/get.js | 6 +- src/{files-regular => }/ls.js | 4 +- src/refs/index.js | 69 ++++++++++++ .../refs-local.js => refs/local.js} | 0 src/utils/load-commands.js | 96 ++++++++++++++++- test/sub-modules.spec.js | 22 ++-- 22 files changed, 179 insertions(+), 181 deletions(-) delete mode 100644 src/files-regular/index.js delete mode 100644 src/files-regular/refs.js rename src/{files-mfs => files}/cp.js (100%) rename src/{files-mfs => files}/flush.js (100%) rename src/{files-mfs => files}/index.js (100%) rename src/{files-mfs => files}/ls-pull-stream.js (100%) rename src/{files-mfs => files}/ls-readable-stream.js (100%) rename src/{files-mfs => files}/ls.js (100%) rename src/{files-mfs => files}/mkdir.js (100%) rename src/{files-mfs => files}/mv.js (100%) rename src/{files-mfs => files}/read-pull-stream.js (100%) rename src/{files-mfs => files}/read-readable-stream.js (100%) rename src/{files-mfs => files}/read.js (100%) rename src/{files-mfs => files}/rm.js (100%) rename src/{files-mfs => files}/stat.js (100%) rename src/{files-mfs => files}/write.js (100%) rename src/{files-regular => }/get.js (85%) rename src/{files-regular => }/ls.js (94%) create mode 100644 src/refs/index.js rename src/{files-regular/refs-local.js => refs/local.js} (100%) diff --git a/src/files-regular/index.js b/src/files-regular/index.js deleted file mode 100644 index 3381102d5..000000000 --- a/src/files-regular/index.js +++ /dev/null @@ -1,100 +0,0 @@ -'use strict' - -const nodeify = require('promise-nodeify') -const callbackify = require('callbackify') -const all = require('async-iterator-all') -const { concatify, collectify, pullify, streamify } = require('../lib/converters') -const toPullStream = require('async-iterator-to-pull-stream') -const pull = require('pull-stream/pull') -const map = require('pull-stream/throughs/map') - -module.exports = (config) => { - const add = require('../add')(config) - const addFromFs = require('../add-from-fs')(config) - const addFromURL = require('../add-from-url')(config) - const cat = require('../cat')(config) - const get = require('./get')(config) - const ls = require('./ls')(config) - const refs = require('./refs')(config) - const refsLocal = require('./refs-local')(config) - - const api = { - add: (input, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(add)(input, options), callback) - }, - addReadableStream: streamify.transform(add), - addPullStream: pullify.transform(add), - addFromFs: (path, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(addFromFs)(path, options), callback) - }, - addFromURL: (url, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(addFromURL)(url, options), callback) - }, - addFromStream: (input, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(add)(input, options), callback) - }, - _addAsyncIterator: add, - cat: callbackify.variadic((path, options) => concatify(cat)(path, options)), - catReadableStream: streamify.readable(cat), - catPullStream: pullify.source(cat), - _catAsyncIterator: cat, - get: callbackify.variadic(async (path, options) => { - const output = [] - - for await (const entry of get(path, options)) { - if (entry.content) { - entry.content = Buffer.concat(await all(entry.content)) - } - - output.push(entry) - } - - return output - }), - getReadableStream: streamify.readable(get), - getPullStream: (path, options) => { - return pull( - toPullStream(get(path, options)), - map(file => { - if (file.content) { - file.content = toPullStream(file.content) - } - - return file - }) - ) - }, - _getAsyncIterator: get, - ls: callbackify.variadic((path, options) => collectify(ls)(path, options)), - lsReadableStream: streamify.readable(ls), - lsPullStream: pullify.source(ls), - _lsAsyncIterator: ls, - refs: callbackify.variadic((path, options) => collectify(refs)(path, options)), - refsReadableStream: streamify.readable(refs), - refsPullStream: pullify.source(refs), - _refsAsyncIterator: refs - } - - api.refs.local = callbackify.variadic((options) => collectify(refsLocal)(options)) - api.refs.localReadableStream = streamify.readable(refsLocal) - api.refs.localPullStream = pullify.source(refsLocal) - api.refs._localAsyncIterator = refsLocal - - return api -} diff --git a/src/files-regular/refs.js b/src/files-regular/refs.js deleted file mode 100644 index c6136ede5..000000000 --- a/src/files-regular/refs.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -const configure = require('../lib/configure') -const cleanCID = require('../utils/clean-cid') -const IsIpfs = require('is-ipfs') -const ndjson = require('iterable-ndjson') -const toIterable = require('../lib/stream-to-iterable') -const toCamel = require('../lib/object-to-camel') - -module.exports = configure(({ ky }) => { - return async function * refs (args, options) { - options = options || {} - - const searchParams = new URLSearchParams() - - if (options.format !== undefined) { - searchParams.set('format', options.format) - } - - if (options.edges !== undefined) { - searchParams.set('edges', options.edges) - } - - if (options.unique !== undefined) { - searchParams.set('unique', options.unique) - } - - if (options.recursive !== undefined) { - searchParams.set('recursive', options.recursive) - } - - if (options.maxDepth !== undefined) { - searchParams.set('max-depth', options.maxDepth) - } - - if (!Array.isArray(args)) { - args = [args] - } - - for (let arg of args) { - try { - arg = cleanCID(arg) - } catch (err) { - if (!IsIpfs.ipfsPath(arg)) { - throw err - } - } - - searchParams.append('arg', arg.toString()) - } - - const res = await ky.get('refs', { - timeout: options.timeout, - signal: options.signal, - headers: options.headers, - searchParams - }) - - for await (const file of ndjson(toIterable(res.body))) { - yield toCamel(file) - } - } -}) diff --git a/src/files-mfs/cp.js b/src/files/cp.js similarity index 100% rename from src/files-mfs/cp.js rename to src/files/cp.js diff --git a/src/files-mfs/flush.js b/src/files/flush.js similarity index 100% rename from src/files-mfs/flush.js rename to src/files/flush.js diff --git a/src/files-mfs/index.js b/src/files/index.js similarity index 100% rename from src/files-mfs/index.js rename to src/files/index.js diff --git a/src/files-mfs/ls-pull-stream.js b/src/files/ls-pull-stream.js similarity index 100% rename from src/files-mfs/ls-pull-stream.js rename to src/files/ls-pull-stream.js diff --git a/src/files-mfs/ls-readable-stream.js b/src/files/ls-readable-stream.js similarity index 100% rename from src/files-mfs/ls-readable-stream.js rename to src/files/ls-readable-stream.js diff --git a/src/files-mfs/ls.js b/src/files/ls.js similarity index 100% rename from src/files-mfs/ls.js rename to src/files/ls.js diff --git a/src/files-mfs/mkdir.js b/src/files/mkdir.js similarity index 100% rename from src/files-mfs/mkdir.js rename to src/files/mkdir.js diff --git a/src/files-mfs/mv.js b/src/files/mv.js similarity index 100% rename from src/files-mfs/mv.js rename to src/files/mv.js diff --git a/src/files-mfs/read-pull-stream.js b/src/files/read-pull-stream.js similarity index 100% rename from src/files-mfs/read-pull-stream.js rename to src/files/read-pull-stream.js diff --git a/src/files-mfs/read-readable-stream.js b/src/files/read-readable-stream.js similarity index 100% rename from src/files-mfs/read-readable-stream.js rename to src/files/read-readable-stream.js diff --git a/src/files-mfs/read.js b/src/files/read.js similarity index 100% rename from src/files-mfs/read.js rename to src/files/read.js diff --git a/src/files-mfs/rm.js b/src/files/rm.js similarity index 100% rename from src/files-mfs/rm.js rename to src/files/rm.js diff --git a/src/files-mfs/stat.js b/src/files/stat.js similarity index 100% rename from src/files-mfs/stat.js rename to src/files/stat.js diff --git a/src/files-mfs/write.js b/src/files/write.js similarity index 100% rename from src/files-mfs/write.js rename to src/files/write.js diff --git a/src/files-regular/get.js b/src/get.js similarity index 85% rename from src/files-regular/get.js rename to src/get.js index 6c942648b..62adfd1e9 100644 --- a/src/files-regular/get.js +++ b/src/get.js @@ -1,9 +1,9 @@ 'use strict' -const configure = require('../lib/configure') -const tarStreamToObjects = require('../utils/tar-stream-to-objects') +const configure = require('./lib/configure') +const tarStreamToObjects = require('./utils/tar-stream-to-objects') const IsIpfs = require('is-ipfs') -const cleanCID = require('../utils/clean-cid') +const cleanCID = require('./utils/clean-cid') module.exports = configure(({ ky }) => { return async function * get (path, options) { diff --git a/src/files-regular/ls.js b/src/ls.js similarity index 94% rename from src/files-regular/ls.js rename to src/ls.js index 0f13f556d..fc9921963 100644 --- a/src/files-regular/ls.js +++ b/src/ls.js @@ -1,8 +1,8 @@ 'use strict' const IsIpfs = require('is-ipfs') -const cleanCID = require('../utils/clean-cid') -const configure = require('../lib/configure') +const cleanCID = require('./utils/clean-cid') +const configure = require('./lib/configure') module.exports = configure(({ ky }) => { return async function * ls (path, options) { diff --git a/src/refs/index.js b/src/refs/index.js new file mode 100644 index 000000000..d86944eb2 --- /dev/null +++ b/src/refs/index.js @@ -0,0 +1,69 @@ +'use strict' + +const configure = require('../lib/configure') +const cleanCID = require('../utils/clean-cid') +const IsIpfs = require('is-ipfs') +const ndjson = require('iterable-ndjson') +const toIterable = require('../lib/stream-to-iterable') +const toCamel = require('../lib/object-to-camel') + +module.exports = config => { + const refs = (configure(({ ky }) => { + return async function * refs (args, options) { + options = options || {} + + const searchParams = new URLSearchParams() + + if (options.format !== undefined) { + searchParams.set('format', options.format) + } + + if (options.edges !== undefined) { + searchParams.set('edges', options.edges) + } + + if (options.unique !== undefined) { + searchParams.set('unique', options.unique) + } + + if (options.recursive !== undefined) { + searchParams.set('recursive', options.recursive) + } + + if (options.maxDepth !== undefined) { + searchParams.set('max-depth', options.maxDepth) + } + + if (!Array.isArray(args)) { + args = [args] + } + + for (let arg of args) { + try { + arg = cleanCID(arg) + } catch (err) { + if (!IsIpfs.ipfsPath(arg)) { + throw err + } + } + + searchParams.append('arg', arg.toString()) + } + + const res = await ky.get('refs', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const file of ndjson(toIterable(res.body))) { + yield toCamel(file) + } + } + }))(config) + + refs.local = require('./local')(config) + + return refs +} diff --git a/src/files-regular/refs-local.js b/src/refs/local.js similarity index 100% rename from src/files-regular/refs-local.js rename to src/refs/local.js diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 81948a54e..d4295205c 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -1,15 +1,107 @@ 'use strict' +const nodeify = require('promise-nodeify') +const callbackify = require('callbackify') +const all = require('async-iterator-all') +const { concatify, collectify, pullify, streamify } = require('../lib/converters') +const toPullStream = require('async-iterator-to-pull-stream') +const pull = require('pull-stream/pull') +const map = require('pull-stream/throughs/map') + function requireCommands (send, config) { + const add = require('../add')(config) + const addFromFs = require('../add-from-fs')(config) + const addFromURL = require('../add-from-url')(config) + const cat = require('../cat')(config) + const get = require('../get')(config) + const ls = require('../ls')(config) + const refs = require('../refs')(config) + const cmds = { - ...require('../files-regular')(config), + add: (input, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(add)(input, options), callback) + }, + addReadableStream: streamify.transform(add), + addPullStream: pullify.transform(add), + addFromFs: (path, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(addFromFs)(path, options), callback) + }, + addFromURL: (url, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(addFromURL)(url, options), callback) + }, + addFromStream: (input, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(add)(input, options), callback) + }, + _addAsyncIterator: add, + cat: callbackify.variadic((path, options) => concatify(cat)(path, options)), + catReadableStream: streamify.readable(cat), + catPullStream: pullify.source(cat), + _catAsyncIterator: cat, + get: callbackify.variadic(async (path, options) => { + const output = [] + + for await (const entry of get(path, options)) { + if (entry.content) { + entry.content = Buffer.concat(await all(entry.content)) + } + + output.push(entry) + } + + return output + }), + getReadableStream: streamify.readable(get), + getPullStream: (path, options) => { + return pull( + toPullStream(get(path, options)), + map(file => { + if (file.content) { + file.content = toPullStream(file.content) + } + + return file + }) + ) + }, + _getAsyncIterator: get, + ls: callbackify.variadic((path, options) => collectify(ls)(path, options)), + lsReadableStream: streamify.readable(ls), + lsPullStream: pullify.source(ls), + _lsAsyncIterator: ls, + refs: callbackify.variadic((path, options) => collectify(refs)(path, options)), + refsReadableStream: streamify.readable(refs), + refsPullStream: pullify.source(refs), + _refsAsyncIterator: refs, getEndpointConfig: require('../get-endpoint-config')(config), bitswap: require('../bitswap')(config) } + Object.assign(cmds.refs, { + local: callbackify.variadic(options => collectify(refs.local)(options)), + localReadableStream: streamify.readable(refs.local), + localPullStream: pullify.source(refs.local), + _localAsyncIterator: refs.local + }) + const subCmds = { // Files MFS (Mutable Filesystem) - files: require('../files-mfs'), + files: require('../files'), // Block block: require('../block'), diff --git a/test/sub-modules.spec.js b/test/sub-modules.spec.js index fbecfe637..62d05ce8e 100644 --- a/test/sub-modules.spec.js +++ b/test/sub-modules.spec.js @@ -165,7 +165,7 @@ describe('submodules', () => { }) it('files regular API', () => { - const filesRegular = require('../src/files-regular')(config) + const filesRegular = require('../src')(config) expect(filesRegular.add).to.be.a('function') expect(filesRegular.addReadableStream).to.be.a('function') @@ -191,16 +191,16 @@ describe('submodules', () => { }) it('files MFS API', () => { - const filesMFS = require('../src/files-mfs')(config) - - expect(filesMFS.cp).to.be.a('function') - expect(filesMFS.ls).to.be.a('function') - expect(filesMFS.mkdir).to.be.a('function') - expect(filesMFS.stat).to.be.a('function') - expect(filesMFS.rm).to.be.a('function') - expect(filesMFS.read).to.be.a('function') - expect(filesMFS.write).to.be.a('function') - expect(filesMFS.mv).to.be.a('function') + const files = require('../src/files')(config) + + expect(files.cp).to.be.a('function') + expect(files.ls).to.be.a('function') + expect(files.mkdir).to.be.a('function') + expect(files.stat).to.be.a('function') + expect(files.rm).to.be.a('function') + expect(files.read).to.be.a('function') + expect(files.write).to.be.a('function') + expect(files.mv).to.be.a('function') }) it('commands', () => { From 72fdc8c6b6130ef40acdaacf64f784bd038b4e90 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 12 Nov 2019 19:57:26 +0000 Subject: [PATCH 14/24] refactor: convert block API to async await (#1153) * refactor: convert block API to async/await depends on: * [ ] https://github.com/ipfs/js-ipfs-http-client/pull/1150 License: MIT Signed-off-by: Alan Shaw * feat: support the version param License: MIT Signed-off-by: Alan Shaw * refactor: convert DAG API to async/await License: MIT Signed-off-by: Alan Shaw * fix: add util to convert a single buffer to a form data object License: MIT Signed-off-by: Alan Shaw * fix: exported function --- package.json | 3 +- src/block/get.js | 71 ++++------------ src/block/index.js | 11 ++- src/block/put.js | 110 ++++++++++++------------- src/block/stat.js | 45 +++++----- src/dag/get.js | 74 ++++++----------- src/dag/index.js | 15 ++-- src/dag/put.js | 92 +++++++++------------ src/dag/resolve.js | 31 +++++++ src/lib/buffer-to-form-data.browser.js | 8 ++ src/lib/buffer-to-form-data.js | 17 ++++ src/utils/load-commands.js | 8 +- 12 files changed, 220 insertions(+), 265 deletions(-) create mode 100644 src/dag/resolve.js create mode 100644 src/lib/buffer-to-form-data.browser.js create mode 100644 src/lib/buffer-to-form-data.js diff --git a/package.json b/package.json index 1908c7de1..acd90bb63 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "stream": "readable-stream", "ky-universal": "ky/umd", "./src/add/form-data.js": "./src/add/form-data.browser.js", - "./src/add-from-fs/index.js": "./src/add-from-fs/index.browser.js" + "./src/add-from-fs/index.js": "./src/add-from-fs/index.browser.js", + "./src/lib/buffer-to-form-data.js": "./src/lib/buffer-to-form-data.browser.js" }, "repository": "github:ipfs/js-ipfs-http-client", "scripts": { diff --git a/src/block/get.js b/src/block/get.js index 327b9e7ff..6e28643f3 100644 --- a/src/block/get.js +++ b/src/block/get.js @@ -1,62 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') const Block = require('ipfs-block') const CID = require('cids') -const streamToValue = require('../utils/stream-to-value') +const { Buffer } = require('buffer') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return async (cid, options) => { + cid = new CID(cid) + options = options || {} - // TODO this needs to be adjusted with the new go-ipfs http-api - let cid - try { - if (CID.isCID(args)) { - cid = args - args = cid.toBaseEncodedString() - } else if (Buffer.isBuffer(args)) { - cid = new CID(args) - args = cid.toBaseEncodedString() - } else if (typeof args === 'string') { - cid = new CID(args) - } else { - return callback(new Error('invalid argument')) - } - } catch (err) { - return callback(err) - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${cid}`) - // Transform the response from Buffer or a Stream to a Block - const transform = (res, callback) => { - if (Buffer.isBuffer(res)) { - callback(null, new Block(res, cid)) - // For empty blocks, concat-stream can't infer the encoding so we are - // passed back an empty array - } else if (Array.isArray(res) && res.length === 0) { - callback(null, new Block(Buffer.alloc(0), cid)) - } else { - streamToValue(res, (err, data) => { - if (err) { - return callback(err) - } - // For empty blocks, concat-stream can't infer the encoding so we are - // passed back an empty array - if (!data.length) data = Buffer.alloc(0) - callback(null, new Block(data, cid)) - }) - } - } + const data = await ky.get('block/get', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).arrayBuffer() - const request = { - path: 'block/get', - args: args, - qs: opts - } - - send.andTransform(request, transform, callback) - }) -} + return new Block(Buffer.from(data), cid) + } +}) diff --git a/src/block/index.js b/src/block/index.js index 645f47df6..8c683dd83 100644 --- a/src/block/index.js +++ b/src/block/index.js @@ -1,17 +1,16 @@ 'use strict' const nodeify = require('promise-nodeify') -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') const { collectify } = require('../lib/converters') -module.exports = (arg, config) => { - const send = moduleConfig(arg) +module.exports = config => { const rm = require('./rm-async-iterator')(config) return { - get: require('./get')(send), - stat: require('./stat')(send), - put: require('./put')(send), + get: callbackify.variadic(require('./get')(config)), + stat: callbackify.variadic(require('./stat')(config)), + put: callbackify.variadic(require('./put')(config)), rm: (input, options, callback) => { if (typeof options === 'function') { callback = options diff --git a/src/block/put.js b/src/block/put.js index 03f6824db..39e3b6f1a 100644 --- a/src/block/put.js +++ b/src/block/put.js @@ -1,74 +1,68 @@ 'use strict' -const promisify = require('promisify-es6') const Block = require('ipfs-block') const CID = require('cids') const multihash = require('multihashes') -const SendOneFile = require('../utils/send-one-file') - -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'block/put') - - return promisify((block, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } +const configure = require('../lib/configure') +const toFormData = require('../lib/buffer-to-form-data') +module.exports = configure(({ ky }) => { + async function put (data, options) { options = options || {} - if (Array.isArray(block)) { - return callback(new Error('block.put accepts only one block')) - } - - if (Buffer.isBuffer(block)) { - block = { data: block } - } - - if (!block || !block.data) { - return callback(new Error('invalid block arg')) + if (Block.isBlock(data)) { + const { name, length } = multihash.decode(data.cid.multihash) + options = { + ...options, + format: data.cid.codec, + mhtype: name, + mhlen: length, + version: data.cid.version + } + data = data.data + } else if (options.cid) { + const cid = new CID(options.cid) + const { name, length } = multihash.decode(cid.multihash) + options = { + ...options, + format: cid.codec, + mhtype: name, + mhlen: length, + version: cid.version + } + delete options.cid } - const qs = {} + const searchParams = new URLSearchParams(options.searchParams) + if (options.format) searchParams.set('format', options.format) + if (options.mhtype) searchParams.set('mhtype', options.mhtype) + if (options.mhlen) searchParams.set('mhlen', options.mhlen) + if (options.pin != null) searchParams.set('pin', options.pin) + if (options.version != null) searchParams.set('version', options.version) - if (block.cid || options.cid) { - let cid - - try { - cid = new CID(block.cid || options.cid) - } catch (err) { - return callback(err) + let res + try { + res = await ky.post('block/put', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(data) + }).json() + } catch (err) { + // Retry with "protobuf"/"cbor" format for go-ipfs + // TODO: remove when https://github.com/ipfs/go-cid/issues/75 resolved + if (options.format === 'dag-pb') { + return put(data, { ...options, format: 'protobuf' }) + } else if (options.format === 'dag-cbor') { + return put(data, { ...options, format: 'cbor' }) } - const { name, length } = multihash.decode(cid.multihash) - - qs.format = cid.codec - qs.mhtype = name - qs.mhlen = length - qs.version = cid.version - } else { - if (options.format) qs.format = options.format - if (options.mhtype) qs.mhtype = options.mhtype - if (options.mhlen) qs.mhlen = options.mhlen - if (options.version != null) qs.version = options.version + throw err } - sendOneFile(block.data, { qs }, (err, result) => { - if (err) { - // Retry with "protobuf"/"cbor" format for go-ipfs - // TODO: remove when https://github.com/ipfs/go-cid/issues/75 resolved - if (qs.format === 'dag-pb' || qs.format === 'dag-cbor') { - qs.format = qs.format === 'dag-pb' ? 'protobuf' : 'cbor' - return sendOneFile(block.data, { qs }, (err, result) => { - if (err) return callback(err) - callback(null, new Block(block.data, new CID(result.Key))) - }) - } - - return callback(err) - } + return new Block(data, new CID(res.Key)) + } - callback(null, new Block(block.data, new CID(result.Key))) - }) - }) -} + return put +}) diff --git a/src/block/stat.js b/src/block/stat.js index 9d44ac9f8..4d0b82787 100644 --- a/src/block/stat.js +++ b/src/block/stat.js @@ -1,35 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') const CID = require('cids') -const multihash = require('multihashes') +const { Buffer } = require('buffer') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -module.exports = (send) => { - return promisify((args, opts, callback) => { - // TODO this needs to be adjusted with the new go-ipfs http-api - if (args && CID.isCID(args)) { - args = multihash.toB58String(args.multihash) - } +module.exports = configure(({ ky }) => { + return async (cid, options) => { + options = options || {} - if (typeof (opts) === 'function') { - callback = opts - opts = {} + if (Buffer.isBuffer(cid)) { + cid = new CID(cid) } - const request = { - path: 'block/stat', - args: args, - qs: opts - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${cid}`) - // Transform the response from { Key, Size } objects to { key, size } objects - const transform = (stats, callback) => { - callback(null, { - key: stats.Key, - size: stats.Size - }) - } + const res = await ky.get('block/stat', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send.andTransform(request, transform, callback) - }) -} + return toCamel(res) + } +}) diff --git a/src/dag/get.js b/src/dag/get.js index 771c38bf4..93847b2e6 100644 --- a/src/dag/get.js +++ b/src/dag/get.js @@ -3,10 +3,7 @@ const dagPB = require('ipld-dag-pb') const dagCBOR = require('ipld-dag-cbor') const raw = require('ipld-raw') -const promisify = require('promisify-es6') -const CID = require('cids') -const waterfall = require('async/waterfall') -const block = require('../block') +const configure = require('../lib/configure') const resolvers = { 'dag-cbor': dagCBOR.resolver, @@ -14,56 +11,31 @@ const resolvers = { raw: raw.resolver } -module.exports = (send) => { - return promisify((cid, path, options, callback) => { - if (typeof path === 'function') { - callback = path - path = undefined - } - - if (typeof options === 'function') { - callback = options - options = {} - } +module.exports = config => { + const getBlock = require('../block/get')(config) + const dagResolve = require('./resolve')(config) - options = options || {} - path = path || '' - - if (CID.isCID(cid)) { - cid = cid.toBaseEncodedString() - } - - waterfall([ - cb => { - send({ - path: 'dag/resolve', - args: cid + '/' + path, - qs: options - }, cb) - }, - (resolved, cb) => { - block(send).get(new CID(resolved.Cid['/']), (err, ipfsBlock) => { - cb(err, ipfsBlock, resolved.RemPath) - }) - }, - (ipfsBlock, path, cb) => { - const dagResolver = resolvers[ipfsBlock.cid.codec] + return configure(({ ky }) => { + return async (cid, path, options) => { + if (typeof path === 'object') { + options = path + path = null + } - if (!dagResolver) { - const error = new Error(`Missing IPLD format "${ipfsBlock.cid.codec}"`) - error.missingMulticodec = ipfsBlock.cid.codec - return cb(error) - } + options = options || {} - let res - try { - res = dagResolver.resolve(ipfsBlock.data, path) - } catch (err) { - return cb(err) - } + const resolved = await dagResolve(cid, path, options) + const block = await getBlock(resolved.cid, options) + const dagResolver = resolvers[block.cid.codec] - cb(null, res) + if (!dagResolver) { + throw Object.assign( + new Error(`Missing IPLD format "${block.cid.codec}"`), + { missingMulticodec: cid.codec } + ) } - ], callback) - }) + + return dagResolver.resolve(block.data, resolved.remPath) + } + })(config) } diff --git a/src/dag/index.js b/src/dag/index.js index bb6b1333c..06194e4a8 100644 --- a/src/dag/index.js +++ b/src/dag/index.js @@ -1,12 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - get: require('./get')(send), - put: require('./put')(send) - } -} +module.exports = config => ({ + get: callbackify.variadic(require('./get')(config)), + put: callbackify.variadic(require('./put')(config)), + resolve: callbackify.variadic(require('./resolve')(config)) +}) diff --git a/src/dag/put.js b/src/dag/put.js index 36da9376a..d26f8ba9e 100644 --- a/src/dag/put.js +++ b/src/dag/put.js @@ -1,19 +1,13 @@ 'use strict' const dagCBOR = require('ipld-dag-cbor') -const promisify = require('promisify-es6') const CID = require('cids') const multihash = require('multihashes') -const SendOneFile = require('../utils/send-one-file') - -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'dag/put') - - return promisify((dagNode, options, callback) => { - if (typeof options === 'function') { - callback = options - } +const configure = require('../lib/configure') +const toFormData = require('../lib/buffer-to-form-data') +module.exports = configure(({ ky }) => { + return async (dagNode, options) => { options = options || {} if (options.hash) { @@ -22,65 +16,53 @@ module.exports = (send) => { } if (options.cid && (options.format || options.hashAlg)) { - return callback(new Error('Can\'t put dag node. Please provide either `cid` OR `format` and `hash` options.')) + throw new Error('Failed to put DAG node. Provide either `cid` OR `format` and `hashAlg` options') } else if ((options.format && !options.hashAlg) || (!options.format && options.hashAlg)) { - return callback(new Error('Can\'t put dag node. Please provide `format` AND `hash` options.')) + throw new Error('Failed to put DAG node. Provide `format` AND `hashAlg` options') } if (options.cid) { - let cid - - try { - cid = new CID(options.cid) - } catch (err) { - return callback(err) + const cid = new CID(options.cid) + options = { + ...options, + format: cid.codec, + hashAlg: multihash.decode(cid.multihash).name } - - options.format = cid.codec - options.hashAlg = multihash.decode(cid.multihash).name delete options.cid } - const optionDefaults = { + options = { format: 'dag-cbor', hashAlg: 'sha2-256', - inputEnc: 'raw' + inputEnc: 'raw', + ...options } - options = Object.assign(optionDefaults, options) - let serialized - try { - if (options.format === 'dag-cbor') { - serialized = dagCBOR.util.serialize(dagNode) - } else if (options.format === 'dag-pb') { - serialized = dagNode.serialize() - } else { - // FIXME Hopefully already serialized...can we use IPLD to serialise instead? - serialized = dagNode - } - } catch (err) { - return callback(err) + if (options.format === 'dag-cbor') { + serialized = dagCBOR.util.serialize(dagNode) + } else if (options.format === 'dag-pb') { + serialized = dagNode.serialize() + } else { + // FIXME Hopefully already serialized...can we use IPLD to serialise instead? + serialized = dagNode } - const sendOptions = { - qs: { - hash: options.hashAlg, - format: options.format, - 'input-enc': options.inputEnc - } - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('format', options.format) + searchParams.set('hash', options.hashAlg) + searchParams.set('input-enc', options.inputEnc) + if (options.pin != null) searchParams.set('pin', options.pin) - sendOneFile(serialized, sendOptions, (err, result) => { - if (err) { - return callback(err) - } - if (result.Cid) { - return callback(null, new CID(result.Cid['/'])) - } else { - return callback(result) - } - }) - }) -} + const res = await ky.post('dag/put', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(serialized) + }).json() + + return new CID(res.Cid['/']) + } +}) diff --git a/src/dag/resolve.js b/src/dag/resolve.js new file mode 100644 index 000000000..f0a83d69d --- /dev/null +++ b/src/dag/resolve.js @@ -0,0 +1,31 @@ +'use strict' + +const CID = require('cids') +const configure = require('../lib/configure') + +module.exports = configure(({ ky }) => { + return async (cid, path, options) => { + if (typeof path === 'object') { + options = path + path = null + } + + options = options || {} + + const cidPath = path + ? [cid, path].join(path.startsWith('/') ? '' : '/') + : `${cid}` + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', cidPath) + + const res = await ky.get('dag/resolve', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return { cid: new CID(res.Cid['/']), remPath: res.RemPath } + } +}) diff --git a/src/lib/buffer-to-form-data.browser.js b/src/lib/buffer-to-form-data.browser.js new file mode 100644 index 000000000..dab8da9ce --- /dev/null +++ b/src/lib/buffer-to-form-data.browser.js @@ -0,0 +1,8 @@ +'use strict' +/* eslint-env browser */ + +module.exports = buf => { + const formData = new FormData() + formData.append('file', new Blob([buf], { type: 'application/octet-stream' })) + return formData +} diff --git a/src/lib/buffer-to-form-data.js b/src/lib/buffer-to-form-data.js new file mode 100644 index 000000000..41f03383e --- /dev/null +++ b/src/lib/buffer-to-form-data.js @@ -0,0 +1,17 @@ +'use strict' + +const FormData = require('form-data') +const { isElectronRenderer } = require('ipfs-utils/src/env') + +module.exports = buf => { + const formData = new FormData() + formData.append('file', buf) + return formData +} + +// TODO remove this when upstream fix for ky-universal is merged +// https://github.com/sindresorhus/ky-universal/issues/9 +// also this should only be necessary when nodeIntegration is false in electron renderer +if (isElectronRenderer) { + module.exports = require('./buffer-to-form-data.browser') +} diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index d4295205c..242b52463 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -89,7 +89,9 @@ function requireCommands (send, config) { refsPullStream: pullify.source(refs), _refsAsyncIterator: refs, getEndpointConfig: require('../get-endpoint-config')(config), - bitswap: require('../bitswap')(config) + bitswap: require('../bitswap')(config), + block: require('../block')(config), + dag: require('../dag')(config) } Object.assign(cmds.refs, { @@ -103,11 +105,7 @@ function requireCommands (send, config) { // Files MFS (Mutable Filesystem) files: require('../files'), - // Block - block: require('../block'), - // Graph - dag: require('../dag'), object: require('../object'), pin: require('../pin'), From 14c5b9efdc1ba1dd08f2ce4e6bc3f4210648fdc5 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 14 Nov 2019 13:24:42 +0000 Subject: [PATCH 15/24] refactor: convert bootstrap API to async/await (#1154) License: MIT Signed-off-by: Alan Shaw --- src/bootstrap/add.js | 46 +++++++++++++++++--------------------- src/bootstrap/index.js | 16 +++++-------- src/bootstrap/list.js | 28 ++++++++++++----------- src/bootstrap/rm.js | 46 +++++++++++++++++--------------------- src/utils/load-commands.js | 2 +- 5 files changed, 64 insertions(+), 74 deletions(-) diff --git a/src/bootstrap/add.js b/src/bootstrap/add.js index 978a3eeda..29dd46cc3 100644 --- a/src/bootstrap/add.js +++ b/src/bootstrap/add.js @@ -1,32 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') +const Multiaddr = require('multiaddr') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof opts === 'function' && - !callback) { - callback = opts - opts = {} +module.exports = configure(({ ky }) => { + return async (addr, options) => { + if (addr && typeof addr === 'object' && !Multiaddr.isMultiaddr(addr)) { + options = addr + addr = null } - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && - typeof callback === 'function') { - callback = opts - opts = {} - } + options = options || {} - if (args && typeof args === 'object') { - opts = args - args = undefined - } + const searchParams = new URLSearchParams(options.searchParams) + if (addr) searchParams.set('arg', `${addr}`) + if (options.default != null) searchParams.set('default', options.default) + + const res = await ky.post('bootstrap/add', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send({ - path: 'bootstrap/add', - args: args, - qs: opts - }, callback) - }) -} + return res + } +}) diff --git a/src/bootstrap/index.js b/src/bootstrap/index.js index 31cb3fa2f..032265803 100644 --- a/src/bootstrap/index.js +++ b/src/bootstrap/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - add: require('./add')(send), - rm: require('./rm')(send), - list: require('./list')(send) - } -} +module.exports = config => ({ + add: callbackify.variadic(require('./add')(config)), + rm: callbackify.variadic(require('./rm')(config)), + list: callbackify.variadic(require('./list')(config)) +}) diff --git a/src/bootstrap/list.js b/src/bootstrap/list.js index 79690ef19..2a20f5d05 100644 --- a/src/bootstrap/list.js +++ b/src/bootstrap/list.js @@ -1,16 +1,18 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'bootstrap/list', - qs: opts - }, callback) - }) -} +module.exports = configure(({ ky }) => { + return async (options) => { + options = options || {} + + const res = await ky.get('bootstrap/list', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() + + return res + } +}) diff --git a/src/bootstrap/rm.js b/src/bootstrap/rm.js index c7f55368b..4c2597d1d 100644 --- a/src/bootstrap/rm.js +++ b/src/bootstrap/rm.js @@ -1,32 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') +const Multiaddr = require('multiaddr') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof opts === 'function' && - !callback) { - callback = opts - opts = {} +module.exports = configure(({ ky }) => { + return async (addr, options) => { + if (addr && typeof addr === 'object' && !Multiaddr.isMultiaddr(addr)) { + options = addr + addr = null } - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && - typeof callback === 'function') { - callback = opts - opts = {} - } + options = options || {} - if (args && typeof args === 'object') { - opts = args - args = undefined - } + const searchParams = new URLSearchParams(options.searchParams) + if (addr) searchParams.set('arg', `${addr}`) + if (options.all != null) searchParams.set('all', options.all) + + const res = await ky.post('bootstrap/rm', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send({ - path: 'bootstrap/rm', - args: args, - qs: opts - }, callback) - }) -} + return res + } +}) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 242b52463..9e9db2cf5 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -91,6 +91,7 @@ function requireCommands (send, config) { getEndpointConfig: require('../get-endpoint-config')(config), bitswap: require('../bitswap')(config), block: require('../block')(config), + bootstrap: require('../bootstrap')(config), dag: require('../dag')(config) } @@ -110,7 +111,6 @@ function requireCommands (send, config) { pin: require('../pin'), // Network - bootstrap: require('../bootstrap'), dht: require('../dht'), name: require('../name'), ping: require('../ping'), From 621973c99916b4829e59aaf0fb67101284facfae Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 14 Nov 2019 13:48:17 +0000 Subject: [PATCH 16/24] refactor: convert config API to async await (#1155) BREAKING CHANGE: Errors returned from request failures are now all [`HTTPError`](https://github.com/sindresorhus/ky/blob/c0d9d2bb07e4c122a08f019b39e9c55a4c9324f3/index.js#L117-L123)s which carry a `response` property. This is a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) that can be used to inspect _all_ information relating to the HTTP response. This means that the `err.status` or `err.statusCode` property should now be accessed via `err.response.status`. License: MIT Signed-off-by: Alan Shaw --- src/config/get.js | 54 +++++++++++++--------------------- src/config/index.js | 19 +++++------- src/config/profiles/apply.js | 21 ++++++------- src/config/profiles/index.js | 8 +++++ src/config/profiles/list.js | 15 ++++------ src/config/replace.js | 36 ++++++++++------------- src/config/set.js | 45 ++++++++++++++-------------- src/lib/error-handler.js | 12 ++++++-- src/utils/load-commands.js | 2 +- test/lib.error-handler.spec.js | 3 +- test/request-api.spec.js | 7 ++--- 11 files changed, 106 insertions(+), 116 deletions(-) create mode 100644 src/config/profiles/index.js diff --git a/src/config/get.js b/src/config/get.js index 882efe3df..b8a42a2e3 100644 --- a/src/config/get.js +++ b/src/config/get.js @@ -1,39 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -const toObject = function (res, callback) { - if (Buffer.isBuffer(res)) { - callback(null, JSON.parse(res.toString())) - } else { - callback(null, res) - } -} - -module.exports = (send) => { - return promisify((key, callback) => { - if (typeof key === 'function') { - callback = key - key = undefined +module.exports = configure(({ ky }) => { + return async (key, options) => { + if (key && typeof key === 'object') { + options = key + key = null } - if (!key) { - send.andTransform({ - path: 'config/show', - buffer: true - }, toObject, callback) - return - } + options = options || {} - send.andTransform({ - path: 'config', - args: key, - buffer: true - }, toObject, (err, response) => { - if (err) { - return callback(err) - } - callback(null, response.Value) - }) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + if (key) searchParams.set('arg', key) + + const url = key ? 'config' : 'config/show' + const data = await ky.get(url, { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return key ? data.Value : data + } +}) diff --git a/src/config/index.js b/src/config/index.js index e88c195b5..36621fd39 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -1,13 +1,10 @@ 'use strict' -module.exports = (send, config) => { - return { - get: require('./get')(send), - set: require('./set')(send), - replace: require('./replace')(send), - profiles: { - apply: require('./profiles/apply')(config), - list: require('./profiles/list')(config) - } - } -} +const callbackify = require('callbackify') + +module.exports = config => ({ + get: callbackify.variadic(require('./get')(config)), + set: callbackify.variadic(require('./set')(config)), + replace: callbackify.variadic(require('./replace')(config)), + profiles: require('./profiles')(config) +}) diff --git a/src/config/profiles/apply.js b/src/config/profiles/apply.js index e4b05560b..deac884fe 100644 --- a/src/config/profiles/apply.js +++ b/src/config/profiles/apply.js @@ -1,27 +1,24 @@ 'use strict' -const callbackify = require('callbackify') const configure = require('../../lib/configure') module.exports = configure(({ ky }) => { - return callbackify.variadic(async (profile, options) => { + return async (profile, options) => { options = options || {} + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', profile) + if (options.dryRun != null) searchParams.set('dry-run', options.dryRun) + const res = await ky.post('config/profile/apply', { timeout: options.timeout, signal: options.signal, headers: options.headers, - searchParams: { - arg: profile, - // can only pass strings or numbers as values https://github.com/sindresorhus/ky/issues/182 - 'dry-run': options.dryRun ? 'true' : 'false' - } - }) - - const parsed = await res.json() + searchParams + }).json() return { - original: parsed.OldCfg, updated: parsed.NewCfg + original: res.OldCfg, updated: res.NewCfg } - }) + } }) diff --git a/src/config/profiles/index.js b/src/config/profiles/index.js new file mode 100644 index 000000000..57cd1ad7f --- /dev/null +++ b/src/config/profiles/index.js @@ -0,0 +1,8 @@ +'use strict' + +const callbackify = require('callbackify') + +module.exports = config => ({ + apply: callbackify.variadic(require('./apply')(config)), + list: callbackify.variadic(require('./list')(config)) +}) diff --git a/src/config/profiles/list.js b/src/config/profiles/list.js index dbfa579cf..1e3f44308 100644 --- a/src/config/profiles/list.js +++ b/src/config/profiles/list.js @@ -1,22 +1,19 @@ 'use strict' -const callbackify = require('callbackify') const configure = require('../../lib/configure') const toCamel = require('../../lib/object-to-camel') module.exports = configure(({ ky }) => { - return callbackify.variadic(async (options) => { + return async (options) => { options = options || {} const res = await ky.get('config/profile/list', { timeout: options.timeout, signal: options.signal, - headers: options.headers - }) + headers: options.headers, + searchParams: options.searchParams + }).json() - const parsed = await res.json() - - return parsed - .map(profile => toCamel(profile)) - }) + return res.map(profile => toCamel(profile)) + } }) diff --git a/src/config/replace.js b/src/config/replace.js index 971c61ee0..ccca80beb 100644 --- a/src/config/replace.js +++ b/src/config/replace.js @@ -1,25 +1,21 @@ 'use strict' -const { Readable } = require('readable-stream') -const promisify = require('promisify-es6') -const SendOneFile = require('../utils/send-one-file') +const { Buffer } = require('buffer') +const configure = require('../lib/configure') +const toFormData = require('../lib/buffer-to-form-data') -function toStream (input) { - return new Readable({ - read () { - this.push(input) - this.push(null) - } - }) -} +module.exports = configure(({ ky }) => { + return async (config, options) => { + options = options || {} -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'config/replace') - return promisify((config, callback) => { - if (typeof config === 'object') { - config = toStream(Buffer.from(JSON.stringify(config))) - } + const res = await ky.post('config/replace', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams, + body: toFormData(Buffer.from(JSON.stringify(config))) + }).text() - sendOneFile(config, {}, callback) - }) -} + return res + } +}) diff --git a/src/config/set.js b/src/config/set.js index 0fa933565..f9e3309f2 100644 --- a/src/config/set.js +++ b/src/config/set.js @@ -1,35 +1,36 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') + +module.exports = configure(({ ky }) => { + return async (key, value, options) => { + options = options || {} -module.exports = (send) => { - return promisify((key, value, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } if (typeof key !== 'string') { - return callback(new Error('Invalid key type')) + throw new Error('Invalid key type') } - if (value === undefined || Buffer.isBuffer(value)) { - return callback(new Error('Invalid value type')) - } + const searchParams = new URLSearchParams(options.searchParams) if (typeof value === 'boolean') { + searchParams.set('bool', true) value = value.toString() - opts = { bool: true } } else if (typeof value !== 'string') { + searchParams.set('json', true) value = JSON.stringify(value) - opts = { json: true } } - send({ - path: 'config', - args: [key, value], - qs: opts, - files: undefined, - buffer: true - }, callback) - }) -} + searchParams.set('arg', key) + searchParams.append('arg', value) + + const res = await ky.post('config', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/lib/error-handler.js b/src/lib/error-handler.js index 032a6acc8..3aae8a41c 100644 --- a/src/lib/error-handler.js +++ b/src/lib/error-handler.js @@ -35,9 +35,15 @@ module.exports = async function errorHandler (input, options, response) { } catch (err) { log('Failed to parse error response', err) // Failed to extract/parse error message from response - throw new HTTPError(response) + msg = err.message } - if (!msg) throw new HTTPError(response) - throw Object.assign(new Error(msg), { status: response.status }) + const error = new HTTPError(response) + + // If we managed to extract a message from the response, use it + if (msg) { + error.message = msg + } + + throw error } diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 9e9db2cf5..34a7591e5 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -92,6 +92,7 @@ function requireCommands (send, config) { bitswap: require('../bitswap')(config), block: require('../block')(config), bootstrap: require('../bootstrap')(config), + config: require('../config')(config), dag: require('../dag')(config) } @@ -122,7 +123,6 @@ function requireCommands (send, config) { // Miscellaneous commands: require('../commands'), - config: require('../config'), diag: require('../diag'), id: require('../id'), key: require('../key'), diff --git a/test/lib.error-handler.spec.js b/test/lib.error-handler.spec.js index bdc0fc8a3..c39e3040d 100644 --- a/test/lib.error-handler.spec.js +++ b/test/lib.error-handler.spec.js @@ -21,8 +21,9 @@ describe('lib/error-handler', () => { const err = await throwsAsync(errorHandler(null, null, res)) + expect(err instanceof HTTPError).to.be.true() expect(err.message).to.eql('boom') - expect(err.status).to.eql(500) + expect(err.response.status).to.eql(500) }) it('should gracefully fail on parse json', async () => { diff --git a/test/request-api.spec.js b/test/request-api.spec.js index 1b0858786..c213193bb 100644 --- a/test/request-api.spec.js +++ b/test/request-api.spec.js @@ -81,7 +81,7 @@ describe('error handling', () => { server.listen(6001, () => { ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { expect(err).to.exist() - expect(err.statusCode).to.equal(403) + expect(err.response.status).to.equal(403) expect(err.message).to.equal('ipfs method not allowed') server.close(done) }) @@ -105,9 +105,8 @@ describe('error handling', () => { server.listen(6001, () => { ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { expect(err).to.exist() - expect(err.statusCode).to.equal(400) + expect(err.response.status).to.equal(400) expect(err.message).to.equal('client error') - expect(err.code).to.equal(1) server.close(done) }) }) @@ -130,7 +129,7 @@ describe('error handling', () => { server.listen(6001, () => { ipfsClient('/ip4/127.0.0.1/tcp/6001').config.replace('test/fixtures/r-config.json', (err) => { expect(err).to.exist() - expect(err.message).to.include('Invalid JSON') + expect(err.message).to.include('Unexpected token M in JSON at position 2') server.close(done) }) }) From 5110423663f19eb8259de9718be909e2f3921de4 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 14 Nov 2019 18:57:34 +0000 Subject: [PATCH 17/24] refactor: convert dht API to async/await (#1156) --- src/dht/find-peer.js | 37 +++++++++++++++ src/dht/find-provs.js | 38 ++++++++++++++++ src/dht/findpeer.js | 63 -------------------------- src/dht/findprovs.js | 63 -------------------------- src/dht/get.js | 62 +++++++++---------------- src/dht/index.js | 31 +++++++++---- src/dht/provide.js | 63 ++++++++++++++------------ src/dht/put.js | 56 +++++++++++++++-------- src/dht/query.js | 57 +++++++++-------------- src/lib/encode-buffer-uri-component.js | 25 ++++++++++ src/pubsub/publish.js | 24 +--------- src/utils/load-commands.js | 4 +- 12 files changed, 238 insertions(+), 285 deletions(-) create mode 100644 src/dht/find-peer.js create mode 100644 src/dht/find-provs.js delete mode 100644 src/dht/findpeer.js delete mode 100644 src/dht/findprovs.js create mode 100644 src/lib/encode-buffer-uri-component.js diff --git a/src/dht/find-peer.js b/src/dht/find-peer.js new file mode 100644 index 000000000..953e9fc78 --- /dev/null +++ b/src/dht/find-peer.js @@ -0,0 +1,37 @@ +'use strict' + +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') +const multiaddr = require('multiaddr') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') + +module.exports = configure(({ ky }) => { + return (peerId, options) => (async function * () { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${peerId}`) + if (options.verbose != null) searchParams.set('verbose', options.verbose) + + const res = await ky.get('dht/findpeer', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const message of ndjson(toIterable(res.body))) { + // 2 = FinalPeer + // https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18 + if (message.Type === 2 && message.Responses) { + for (const { ID, Addrs } of message.Responses) { + const peerInfo = new PeerInfo(PeerId.createFromB58String(ID)) + if (Addrs) Addrs.forEach(a => peerInfo.multiaddrs.add(multiaddr(a))) + yield peerInfo + } + } + } + })() +}) diff --git a/src/dht/find-provs.js b/src/dht/find-provs.js new file mode 100644 index 000000000..b04d001d8 --- /dev/null +++ b/src/dht/find-provs.js @@ -0,0 +1,38 @@ +'use strict' + +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') +const multiaddr = require('multiaddr') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') + +module.exports = configure(({ ky }) => { + return (cid, options) => (async function * () { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${cid}`) + if (options.numProviders) searchParams.set('num-providers', options.numProviders) + if (options.verbose != null) searchParams.set('verbose', options.verbose) + + const res = await ky.get('dht/findprovs', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const message of ndjson(toIterable(res.body))) { + // 4 = Provider + // https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L20 + if (message.Type === 4 && message.Responses) { + for (const { ID, Addrs } of message.Responses) { + const peerInfo = new PeerInfo(PeerId.createFromB58String(ID)) + if (Addrs) Addrs.forEach(a => peerInfo.multiaddrs.add(multiaddr(a))) + yield peerInfo + } + } + } + })() +}) diff --git a/src/dht/findpeer.js b/src/dht/findpeer.js deleted file mode 100644 index 8bcc80fb5..000000000 --- a/src/dht/findpeer.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const streamToValueWithTransformer = require('../utils/stream-to-value-with-transformer') - -const multiaddr = require('multiaddr') -const PeerId = require('peer-id') -const PeerInfo = require('peer-info') -const errcode = require('err-code') - -module.exports = (send) => { - return promisify((peerId, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } - - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } - - const handleResult = (res, callback) => { - // Inconsistent return values in the browser - if (Array.isArray(res)) { - res = res.find(r => r.Type === 2) - } - - // Type 2 keys - // 2 = FinalPeer - // https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L18 - if (!res || res.Type !== 2) { - const errMsg = 'key was not found (type 4)' - return callback(errcode(new Error(errMsg), 'ERR_KEY_TYPE_4_NOT_FOUND')) - } - - const responseReceived = res.Responses[0] - const peerInfo = new PeerInfo(PeerId.createFromB58String(responseReceived.ID)) - - responseReceived.Addrs.forEach((addr) => { - const ma = multiaddr(addr) - - peerInfo.multiaddrs.add(ma) - }) - - callback(null, peerInfo) - } - - send({ - path: 'dht/findpeer', - args: peerId.toString(), - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } - - streamToValueWithTransformer(result, handleResult, callback) - }) - }) -} diff --git a/src/dht/findprovs.js b/src/dht/findprovs.js deleted file mode 100644 index 695ef04df..000000000 --- a/src/dht/findprovs.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const streamToValueWithTransformer = require('../utils/stream-to-value-with-transformer') - -const multiaddr = require('multiaddr') -const PeerId = require('peer-id') -const PeerInfo = require('peer-info') - -module.exports = (send) => { - return promisify((cid, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } - - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } - - const handleResult = (res, callback) => { - // Inconsistent return values in the browser vs node - if (!Array.isArray(res)) { - res = [res] - } - - const responses = [] - res.forEach(result => { - // 4 = Provider - if (result.Type !== 4) return - result.Responses.forEach(response => { - const peerInfo = new PeerInfo(PeerId.createFromB58String(response.ID)) - - if (response.Addrs) { - response.Addrs.forEach((addr) => { - const ma = multiaddr(addr) - peerInfo.multiaddrs.add(ma) - }) - } - - responses.push(peerInfo) - }) - }) - - callback(null, responses) - } - - send({ - path: 'dht/findprovs', - args: cid.toString(), - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } - - streamToValueWithTransformer(result, handleResult, callback) - }) - }) -} diff --git a/src/dht/get.js b/src/dht/get.js index ab64fa892..8a7b8c6a3 100644 --- a/src/dht/get.js +++ b/src/dht/get.js @@ -1,48 +1,30 @@ 'use strict' -const promisify = require('promisify-es6') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -module.exports = (send) => { - return promisify((key, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } - - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return (key, options) => (async function * () { + options = options || {} - function 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')) - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${key}`) + if (options.verbose != null) searchParams.set('verbose', options.verbose) - // Inconsistent return values in the browser vs node - if (Array.isArray(res)) { - res = res[0] - } + const res = await ky.get('dht/get', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) - if (res.Type === 5) { - done(null, res.Extra) - } else { - done(new Error('key was not found (type 6)')) + for await (const message of ndjson(toIterable(res.body))) { + // 5 = Value + // https://github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L21 + if (message.Type === 5) { + yield message.Extra } } - - send({ - path: 'dht/get', - args: key, - qs: opts - }, handleResult.bind(null, callback)) - }) -} + })() +}) diff --git a/src/dht/index.js b/src/dht/index.js index b4ab8c640..5478876ff 100644 --- a/src/dht/index.js +++ b/src/dht/index.js @@ -1,17 +1,30 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') +const errCode = require('err-code') +const { collectify } = require('../lib/converters') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = config => { + const get = require('./get')(config) + const findPeer = require('./find-peer')(config) return { - get: require('./get')(send), - put: require('./put')(send), - findProvs: require('./findprovs')(send), - findPeer: require('./findpeer')(send), - provide: require('./provide')(send), + get: callbackify.variadic(async (key, options) => { + for await (const value of get(key, options)) { + return value + } + throw errCode(new Error('value not found'), 'ERR_TYPE_5_NOT_FOUND') + }), + put: callbackify.variadic(collectify(require('./put')(config))), + findProvs: callbackify.variadic(collectify(require('./find-provs')(config))), + findPeer: callbackify.variadic(async (peerId, options) => { + for await (const peerInfo of findPeer(peerId, options)) { + return peerInfo + } + throw errCode(new Error('final peer not found'), 'ERR_TYPE_2_NOT_FOUND') + }), + provide: callbackify.variadic(collectify(require('./provide')(config))), // find closest peerId to given peerId - query: require('./query')(send) + query: callbackify.variadic(collectify(require('./query')(config))) } } diff --git a/src/dht/provide.js b/src/dht/provide.js index 08bcad6d7..1f05710ec 100644 --- a/src/dht/provide.js +++ b/src/dht/provide.js @@ -1,37 +1,40 @@ 'use strict' -const promisify = require('promisify-es6') -const CID = require('cids') +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') +const multiaddr = require('multiaddr') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') +const toCamel = require('../lib/object-to-camel') -module.exports = (send) => { - return promisify((cids, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return (cids, options) => (async function * () { + cids = Array.isArray(cids) ? cids : [cids] + options = options || {} - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + cids.forEach(cid => searchParams.append('arg', `${cid}`)) + if (options.recursive != null) searchParams.set('recursive', options.recursive) + if (options.verbose != null) searchParams.set('verbose', options.verbose) - if (!Array.isArray(cids)) { - cids = [cids] - } + const res = await ky.get('dht/provide', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) - // Validate CID(s) and serialize - try { - cids = cids.map(cid => new CID(cid).toBaseEncodedString('base58btc')) - } catch (err) { - return callback(err) + for await (let message of ndjson(toIterable(res.body))) { + message = toCamel(message) + if (message.responses) { + message.responses = message.responses.map(({ ID, Addrs }) => { + const peerInfo = new PeerInfo(PeerId.createFromB58String(ID)) + if (Addrs) Addrs.forEach(a => peerInfo.multiaddrs.add(multiaddr(a))) + return peerInfo + }) + } + yield message } - - send({ - path: 'dht/provide', - args: cids, - qs: opts - }, callback) - }) -} + })() +}) diff --git a/src/dht/put.js b/src/dht/put.js index c0937d158..50137e528 100644 --- a/src/dht/put.js +++ b/src/dht/put.js @@ -1,25 +1,41 @@ 'use strict' -const promisify = require('promisify-es6') +const PeerId = require('peer-id') +const PeerInfo = require('peer-info') +const multiaddr = require('multiaddr') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') +const encodeBufferURIComponent = require('../lib/encode-buffer-uri-component') +const toCamel = require('../lib/object-to-camel') -module.exports = (send) => { - return promisify((key, value, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return (key, value, options) => (async function * () { + options = options || {} - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + if (options.verbose != null) searchParams.set('verbose', options.verbose) + + key = Buffer.isBuffer(key) ? encodeBufferURIComponent(key) : encodeURIComponent(key) + value = Buffer.isBuffer(value) ? encodeBufferURIComponent(value) : encodeURIComponent(value) - send({ - path: 'dht/put', - args: [key, value], - qs: opts - }, callback) - }) -} + const url = `dht/put?arg=${key}&arg=${value}&${searchParams}` + const res = await ky.get(url, { + timeout: options.timeout, + signal: options.signal, + headers: options.headers + }) + + for await (let message of ndjson(toIterable(res.body))) { + message = toCamel(message) + if (message.responses) { + message.responses = message.responses.map(({ ID, Addrs }) => { + const peerInfo = new PeerInfo(PeerId.createFromB58String(ID)) + if (Addrs) Addrs.forEach(a => peerInfo.multiaddrs.add(multiaddr(a))) + return peerInfo + }) + } + yield message + } + })() +}) diff --git a/src/dht/query.js b/src/dht/query.js index 2dbc62a47..8ebca71f7 100644 --- a/src/dht/query.js +++ b/src/dht/query.js @@ -1,41 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') -const streamToValueWithTransformer = require('../utils/stream-to-value-with-transformer') - const PeerId = require('peer-id') const PeerInfo = require('peer-info') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') + +module.exports = configure(({ ky }) => { + return (peerId, options) => (async function * () { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${peerId}`) + if (options.verbose != null) searchParams.set('verbose', options.verbose) + + const res = await ky.get('dht/query', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) -module.exports = (send) => { - return promisify((peerId, opts, callback) => { - if (typeof opts === 'function' && !callback) { - callback = opts - opts = {} - } - - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && typeof callback === 'function') { - callback = opts - opts = {} - } - - const handleResult = (res, callback) => { - const peerIds = res.map((r) => (new PeerInfo(PeerId.createFromB58String(r.ID)))) - - callback(null, peerIds) + for await (const message of ndjson(toIterable(res.body))) { + yield new PeerInfo(PeerId.createFromB58String(message.ID)) } - - send({ - path: 'dht/query', - args: peerId, - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } - - streamToValueWithTransformer(result, handleResult, callback) - }) - }) -} + })() +}) diff --git a/src/lib/encode-buffer-uri-component.js b/src/lib/encode-buffer-uri-component.js new file mode 100644 index 000000000..c231970cb --- /dev/null +++ b/src/lib/encode-buffer-uri-component.js @@ -0,0 +1,25 @@ +'use strict' + +// https://github.com/ipfs/js-ipfs-http-client/issues/569 +module.exports = function encodeBuffer (buf) { + let uriEncoded = '' + for (const byte of buf) { + // https://tools.ietf.org/html/rfc3986#page-14 + // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), + // underscore (%5F), or tilde (%7E) + if ( + (byte >= 0x41 && byte <= 0x5A) || + (byte >= 0x61 && byte <= 0x7A) || + (byte >= 0x30 && byte <= 0x39) || + (byte === 0x2D) || + (byte === 0x2E) || + (byte === 0x5F) || + (byte === 0x7E) + ) { + uriEncoded += String.fromCharCode(byte) + } else { + uriEncoded += `%${byte.toString(16).padStart(2, '0')}` + } + } + return uriEncoded +} diff --git a/src/pubsub/publish.js b/src/pubsub/publish.js index a41c8fba0..10a5017cc 100644 --- a/src/pubsub/publish.js +++ b/src/pubsub/publish.js @@ -2,6 +2,7 @@ const { Buffer } = require('buffer') const configure = require('../lib/configure') +const encodeBuffer = require('../lib/encode-buffer-uri-component') module.exports = configure(({ ky }) => { return async (topic, data, options) => { @@ -20,26 +21,3 @@ module.exports = configure(({ ky }) => { return res } }) - -function encodeBuffer (buf) { - let uriEncoded = '' - for (const byte of buf) { - // https://tools.ietf.org/html/rfc3986#page-14 - // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), - // underscore (%5F), or tilde (%7E) - if ( - (byte >= 0x41 && byte <= 0x5A) || - (byte >= 0x61 && byte <= 0x7A) || - (byte >= 0x30 && byte <= 0x39) || - (byte === 0x2D) || - (byte === 0x2E) || - (byte === 0x5F) || - (byte === 0x7E) - ) { - uriEncoded += String.fromCharCode(byte) - } else { - uriEncoded += `%${byte.toString(16).padStart(2, '0')}` - } - } - return uriEncoded -} diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 34a7591e5..fae44d26c 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -93,7 +93,8 @@ function requireCommands (send, config) { block: require('../block')(config), bootstrap: require('../bootstrap')(config), config: require('../config')(config), - dag: require('../dag')(config) + dag: require('../dag')(config), + dht: require('../dht')(config) } Object.assign(cmds.refs, { @@ -112,7 +113,6 @@ function requireCommands (send, config) { pin: require('../pin'), // Network - dht: require('../dht'), name: require('../name'), ping: require('../ping'), pingReadableStream: require('../ping-readable-stream'), From 0e011873747f9d8754d26ca21792df865fda8b1e Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Thu, 14 Nov 2019 20:41:21 +0000 Subject: [PATCH 18/24] refactor: convert diag API to async/await (#1157) License: MIT Signed-off-by: Alan Shaw --- src/diag/cmds.js | 28 +++++++++++++++------------- src/diag/index.js | 16 ++++++---------- src/diag/net.js | 25 ++++++++++++------------- src/diag/sys.js | 25 ++++++++++++------------- src/utils/load-commands.js | 4 ++-- 5 files changed, 47 insertions(+), 51 deletions(-) diff --git a/src/diag/cmds.js b/src/diag/cmds.js index e717604fa..68f20ca04 100644 --- a/src/diag/cmds.js +++ b/src/diag/cmds.js @@ -1,17 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return options => { + options = options || {} - send({ - path: 'diag/cmds', - qs: opts - }, callback) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + if (options.verbose != null) searchParams.set('verbose', options.verbose) + + return ky.get('diag/cmds', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + } +}) diff --git a/src/diag/index.js b/src/diag/index.js index b24f7af53..7e48d576d 100644 --- a/src/diag/index.js +++ b/src/diag/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - net: require('./net')(send), - sys: require('./sys')(send), - cmds: require('./cmds')(send) - } -} +module.exports = config => ({ + net: callbackify.variadic(require('./net')(config)), + sys: callbackify.variadic(require('./sys')(config)), + cmds: callbackify.variadic(require('./cmds')(config)) +}) diff --git a/src/diag/net.js b/src/diag/net.js index 9c84988d1..a7404b802 100644 --- a/src/diag/net.js +++ b/src/diag/net.js @@ -1,17 +1,16 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return options => { + options = options || {} - send({ - path: 'diag/net', - qs: opts - }, callback) - }) -} + return ky.get('diag/net', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() + } +}) diff --git a/src/diag/sys.js b/src/diag/sys.js index c06968942..a8cd91b6f 100644 --- a/src/diag/sys.js +++ b/src/diag/sys.js @@ -1,17 +1,16 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return options => { + options = options || {} - send({ - path: 'diag/sys', - qs: opts - }, callback) - }) -} + return ky.get('diag/sys', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() + } +}) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index fae44d26c..14545b564 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -94,7 +94,8 @@ function requireCommands (send, config) { bootstrap: require('../bootstrap')(config), config: require('../config')(config), dag: require('../dag')(config), - dht: require('../dht')(config) + dht: require('../dht')(config), + diag: require('../diag')(config) } Object.assign(cmds.refs, { @@ -123,7 +124,6 @@ function requireCommands (send, config) { // Miscellaneous commands: require('../commands'), - diag: require('../diag'), id: require('../id'), key: require('../key'), log: require('../log'), From 12b7a2e6a98569d6a9ca4c3c01c6c74646a50102 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Mon, 18 Nov 2019 15:51:40 +0000 Subject: [PATCH 19/24] refactor: switch tar-stream for it-tar (#1161) This switches out `tar-stream` for [`it-tar`](https://www.npmjs.com/package/it-tar), which is a fork that uses pure async iterables. This removes `readable-stream` from this branch of the tree (which will allow us to drop it entirely in the future) and allows us to drop the `event-iterator` dependency. --- package.json | 3 +- src/get.js | 18 ++++++- src/utils/load-commands.js | 24 +++++++-- src/utils/tar-stream-to-objects.js | 85 ------------------------------ 4 files changed, 38 insertions(+), 92 deletions(-) delete mode 100644 src/utils/tar-stream-to-objects.js diff --git a/package.json b/package.json index acd90bb63..bfc80c569 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "detect-node": "^2.0.4", "end-of-stream": "^1.4.1", "err-code": "^2.0.0", - "event-iterator": "^1.2.0", "explain-error": "^1.0.4", "flatmap": "0.0.3", "form-data": "^3.0.0", @@ -74,6 +73,7 @@ "iso-stream-http": "~0.1.2", "iso-url": "~0.4.6", "it-glob": "0.0.6", + "it-tar": "^1.1.0", "it-to-stream": "^0.1.1", "iterable-ndjson": "^1.1.0", "just-kebab-case": "^1.1.0", @@ -101,7 +101,6 @@ "qs": "^6.5.2", "readable-stream": "^3.1.1", "stream-to-pull-stream": "^1.7.2", - "tar-stream": "^2.0.1", "through2": "^3.0.1" }, "devDependencies": { diff --git a/src/get.js b/src/get.js index 62adfd1e9..c06fc6d36 100644 --- a/src/get.js +++ b/src/get.js @@ -1,8 +1,9 @@ 'use strict' const configure = require('./lib/configure') -const tarStreamToObjects = require('./utils/tar-stream-to-objects') +const Tar = require('it-tar') const IsIpfs = require('is-ipfs') +const toIterable = require('./lib/stream-to-iterable') const cleanCID = require('./utils/clean-cid') module.exports = configure(({ ky }) => { @@ -43,6 +44,19 @@ module.exports = configure(({ ky }) => { searchParams }) - yield * tarStreamToObjects(res.body) + const extractor = Tar.extract() + + for await (const { header, body } of extractor(toIterable(res.body))) { + if (header.type === 'directory') { + yield { + path: header.name + } + } else { + yield { + path: header.name, + content: body + } + } + } } }) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 14545b564..3e51acdb2 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -7,6 +7,8 @@ const { concatify, collectify, pullify, streamify } = require('../lib/converters const toPullStream = require('async-iterator-to-pull-stream') const pull = require('pull-stream/pull') const map = require('pull-stream/throughs/map') +const toStream = require('it-to-stream') +const BufferList = require('bl/BufferList') function requireCommands (send, config) { const add = require('../add')(config) @@ -58,7 +60,7 @@ function requireCommands (send, config) { for await (const entry of get(path, options)) { if (entry.content) { - entry.content = Buffer.concat(await all(entry.content)) + entry.content = new BufferList(await all(entry.content)).slice() } output.push(entry) @@ -66,13 +68,29 @@ function requireCommands (send, config) { return output }), - getReadableStream: streamify.readable(get), + getReadableStream: streamify.readable((path, options) => (async function * () { + for await (const file of get(path, options)) { + if (file.content) { + const { content } = file + file.content = toStream((async function * () { + for await (const chunk of content) { + yield chunk.slice() // Convert bl to Buffer + } + })()) + } + + yield file + } + })()), getPullStream: (path, options) => { return pull( toPullStream(get(path, options)), map(file => { if (file.content) { - file.content = toPullStream(file.content) + file.content = pull( + toPullStream(file.content), + map(chunk => chunk.slice()) // Convert bl to Buffer + ) } return file diff --git a/src/utils/tar-stream-to-objects.js b/src/utils/tar-stream-to-objects.js deleted file mode 100644 index 7241b3445..000000000 --- a/src/utils/tar-stream-to-objects.js +++ /dev/null @@ -1,85 +0,0 @@ -'use strict' - -const tar = require('tar-stream') -const { EventIterator } = require('event-iterator') - -function pipe (reader, writable) { - reader.read() - .then(({ done, value }) => { - if (done) { - writable.end() - - return - } - - if (value) { - const beneathHighWaterMark = writable.write(value) - - if (beneathHighWaterMark) { - pipe(reader, writable) - } else { - writable.once('drain', () => { - pipe(reader, writable) - }) - } - } - }, (err) => { - writable.emit('error', err) - }) -} - -/* - Transform a tar readable stream into an async iterator of objects: - - Output format: - { path: 'string', content: AsyncIterator } -*/ -async function * tarStreamToObjects (inputStream) { - const extractStream = tar.extract() - let onEntry - - const tarStream = new EventIterator( - (push, stop, fail) => { - onEntry = (header, stream, next) => { - push({ header, stream }) - - next() - } - - extractStream.addListener('entry', onEntry) - extractStream.addListener('finish', stop) - extractStream.addListener('error', fail) - }, - (push, stop, fail) => { - extractStream.removeListener('entry', onEntry) - extractStream.removeListener('finish', stop) - extractStream.removeListener('error', fail) - extractStream.destroy() - } - ) - - if (inputStream.pipe) { - // node stream - inputStream.pipe(extractStream) - } else if (inputStream.getReader) { - // browser readable stream - pipe(inputStream.getReader(), extractStream) - } else { - throw new Error('Unknown stream type') - } - - for await (const { header, stream } of tarStream) { - if (header.type === 'directory') { - yield { - path: header.name - } - } else { - yield { - path: header.name, - content: stream - } - } - } -} - -module.exports = tarStreamToObjects From 8b48d57a106968b3d766939cb1ed3b6bc3365d14 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Tue, 19 Nov 2019 22:46:14 +0000 Subject: [PATCH 20/24] refactor: convert pin API to async/await (#1168) License: MIT Signed-off-by: Alan Shaw --- src/pin/add.js | 38 ++++++++++++++-------------- src/pin/index.js | 16 +++++------- src/pin/ls.js | 52 +++++++++++++++++--------------------- src/pin/rm.js | 38 ++++++++++++++-------------- src/utils/load-commands.js | 4 +-- 5 files changed, 69 insertions(+), 79 deletions(-) diff --git a/src/pin/add.js b/src/pin/add.js index 7ef730eec..74eb47a2d 100644 --- a/src/pin/add.js +++ b/src/pin/add.js @@ -1,22 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((hash, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = null - } - send({ - path: 'pin/add', - args: hash, - qs: opts - }, (err, res) => { - if (err) { - return callback(err) - } - callback(null, res.Pins.map((hash) => ({ hash: hash }))) - }) - }) -} +module.exports = configure(({ ky }) => { + return async (path, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${path}`) + if (options.recursive != null) searchParams.set('recursive', options.recursive) + + const res = await ky.post('pin/add', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return (res.Pins || []).map(hash => ({ hash })) + } +}) diff --git a/src/pin/index.js b/src/pin/index.js index 859052e2c..c62d3a46a 100644 --- a/src/pin/index.js +++ b/src/pin/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - add: require('./add')(send), - rm: require('./rm')(send), - ls: require('./ls')(send) - } -} +module.exports = config => ({ + add: callbackify.variadic(require('./add')(config)), + rm: callbackify.variadic(require('./rm')(config)), + ls: callbackify.variadic(require('./ls')(config)) +}) diff --git a/src/pin/ls.js b/src/pin/ls.js index c8ad26a4b..bf1746d63 100644 --- a/src/pin/ls.js +++ b/src/pin/ls.js @@ -1,33 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((hash, opts, callback) => { - if (typeof hash === 'function') { - callback = hash - opts = null - hash = null +module.exports = configure(({ ky }) => { + return async (path, options) => { + if (path && path.type) { + options = path + path = null } - if (typeof opts === 'function') { - callback = opts - opts = null - } - if (hash && hash.type) { - opts = hash - hash = null - } - send({ - path: 'pin/ls', - args: hash, - qs: opts - }, (err, res) => { - if (err) { - return callback(err) - } - callback(null, Object.keys(res.Keys).map(hash => ( - { hash, type: res.Keys[hash].Type } - ))) - }) - }) -} + + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + if (path) searchParams.set('arg', `${path}`) + if (options.type) searchParams.set('type', options.type) + + const { Keys } = await ky.get('pin/ls', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return Object.keys(Keys).map(hash => ({ hash, type: Keys[hash].Type })) + } +}) diff --git a/src/pin/rm.js b/src/pin/rm.js index 05aada109..9f75307ff 100644 --- a/src/pin/rm.js +++ b/src/pin/rm.js @@ -1,22 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((hash, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = null - } - send({ - path: 'pin/rm', - args: hash, - qs: opts - }, (err, res) => { - if (err) { - return callback(err) - } - callback(null, res.Pins.map((hash) => ({ hash: hash }))) - }) - }) -} +module.exports = configure(({ ky }) => { + return async (path, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${path}`) + if (options.recursive != null) searchParams.set('recursive', options.recursive) + + const res = await ky.post('pin/rm', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return (res.Pins || []).map(hash => ({ hash })) + } +}) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 3e51acdb2..933241a0b 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -113,7 +113,8 @@ function requireCommands (send, config) { config: require('../config')(config), dag: require('../dag')(config), dht: require('../dht')(config), - diag: require('../diag')(config) + diag: require('../diag')(config), + pin: require('../pin')(config) } Object.assign(cmds.refs, { @@ -129,7 +130,6 @@ function requireCommands (send, config) { // Graph object: require('../object'), - pin: require('../pin'), // Network name: require('../name'), From fc73da74496621abb264bc45f933333b2eda4a0f Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Wed, 20 Nov 2019 17:16:45 +0000 Subject: [PATCH 21/24] refactor: convert object.* and files.* API methods to async/await (#1160) License: MIT Signed-off-by: Alan Shaw --- package.json | 14 +--- src/files/cp.js | 37 +++++---- src/files/flush.js | 31 +++++--- src/files/index.js | 34 ++++---- src/files/ls-pull-stream.js | 12 --- src/files/ls-readable-stream.js | 62 --------------- src/files/ls.js | 65 ++++++++------- src/files/mkdir.js | 36 +++++---- src/files/mv.js | 37 +++++---- src/files/read-pull-stream.js | 26 ------ src/files/read-readable-stream.js | 26 ------ src/files/read.js | 38 +++++---- src/files/rm.js | 38 ++++----- src/files/stat.js | 55 ++++++------- src/{utils/find-sources.js => files/utils.js} | 14 ++-- src/files/write.js | 70 +++++++--------- src/lib/configure.js | 8 +- src/object/addLink.js | 35 -------- src/object/appendData.js | 35 -------- src/object/data.js | 63 +++++---------- src/object/get.js | 79 ++++++------------- src/object/index.js | 30 +++---- src/object/links.js | 63 ++++----------- src/object/new.js | 38 +++++---- src/object/patch/add-link.js | 25 ++++++ src/object/patch/append-data.js | 25 ++++++ src/object/patch/index.js | 10 +++ src/object/patch/rm-link.js | 24 ++++++ src/object/patch/set-data.js | 25 ++++++ src/object/put.js | 56 ++++++------- src/object/rmLink.js | 35 -------- src/object/setData.js | 34 -------- src/object/stat.js | 41 +++++----- src/utils/load-commands.js | 8 +- test/files-mfs.spec.js | 4 +- 35 files changed, 495 insertions(+), 738 deletions(-) delete mode 100644 src/files/ls-pull-stream.js delete mode 100644 src/files/ls-readable-stream.js delete mode 100644 src/files/read-pull-stream.js delete mode 100644 src/files/read-readable-stream.js rename src/{utils/find-sources.js => files/utils.js} (50%) delete mode 100644 src/object/addLink.js delete mode 100644 src/object/appendData.js create mode 100644 src/object/patch/add-link.js create mode 100644 src/object/patch/append-data.js create mode 100644 src/object/patch/index.js create mode 100644 src/object/patch/rm-link.js create mode 100644 src/object/patch/set-data.js delete mode 100644 src/object/rmLink.js delete mode 100644 src/object/setData.js diff --git a/package.json b/package.json index bfc80c569..4b305550a 100644 --- a/package.json +++ b/package.json @@ -53,14 +53,11 @@ "cids": "~0.7.1", "concat-stream": "github:hugomrdias/concat-stream#feat/smaller", "debug": "^4.1.0", - "delay": "^4.3.0", "detect-node": "^2.0.4", - "end-of-stream": "^1.4.1", "err-code": "^2.0.0", "explain-error": "^1.0.4", "flatmap": "0.0.3", "form-data": "^3.0.0", - "fs-extra": "^8.1.0", "glob": "^7.1.3", "ipfs-block": "~0.8.1", "ipfs-utils": "^0.4.0", @@ -71,17 +68,13 @@ "is-pull-stream": "0.0.0", "is-stream": "^2.0.0", "iso-stream-http": "~0.1.2", - "iso-url": "~0.4.6", "it-glob": "0.0.6", "it-tar": "^1.1.0", "it-to-stream": "^0.1.1", "iterable-ndjson": "^1.1.0", - "just-kebab-case": "^1.1.0", - "just-map-keys": "^1.1.0", "kind-of": "^6.0.2", "ky": "^0.15.0", "ky-universal": "^0.3.0", - "lru-cache": "^5.1.1", "merge-options": "^2.0.0", "multiaddr": "^6.0.6", "multibase": "~0.6.0", @@ -89,26 +82,25 @@ "multihashes": "~0.4.14", "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", "once": "^1.4.0", + "parse-duration": "^0.1.1", "peer-id": "~0.12.3", "peer-info": "~0.15.1", "promise-nodeify": "^3.0.1", "promisify-es6": "^1.0.3", "pull-defer": "~0.2.3", "pull-stream": "^3.6.9", - "pull-stream-to-async-iterator": "^1.0.2", "pull-to-stream": "~0.1.1", "pump": "^3.0.0", "qs": "^6.5.2", "readable-stream": "^3.1.1", - "stream-to-pull-stream": "^1.7.2", - "through2": "^3.0.1" + "stream-to-pull-stream": "^1.7.2" }, "devDependencies": { "aegir": "^20.4.1", "browser-process-platform": "~0.1.1", "cross-env": "^6.0.0", "go-ipfs-dep": "^0.4.22", - "interface-ipfs-core": "^0.119.0", + "interface-ipfs-core": "^0.120.0", "ipfsd-ctl": "^0.47.1", "nock": "^11.4.0", "stream-equal": "^1.1.1" diff --git a/src/files/cp.js b/src/files/cp.js index de4e0954d..812c8b7d7 100644 --- a/src/files/cp.js +++ b/src/files/cp.js @@ -1,20 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') -const findSources = require('../utils/find-sources') +const CID = require('cids') +const configure = require('../lib/configure') +const { findSources } = require('./utils') -module.exports = (send) => { - return promisify(function () { - const { - callback, - sources, - opts - } = findSources(Array.prototype.slice.call(arguments)) +module.exports = configure(({ ky }) => { + return (...args) => { + const { sources, options } = findSources(args) - send({ - path: 'files/cp', - args: sources, - qs: opts - }, (error) => callback(error)) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + sources.forEach(src => searchParams.append('arg', CID.isCID(src) ? `/ipfs/${src}` : src)) + if (options.format) searchParams.set('format', options.format) + if (options.flush != null) searchParams.set('flush', options.flush) + if (options.hashAlg) searchParams.set('hash', options.hashAlg) + if (options.parents != null) searchParams.set('parents', options.parents) + + return ky.post('files/cp', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/files/flush.js b/src/files/flush.js index 6a131989b..ab2062387 100644 --- a/src/files/flush.js +++ b/src/files/flush.js @@ -1,17 +1,24 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, callback) => { - if (typeof args === 'function') { - callback = args - args = '/' +module.exports = configure(({ ky }) => { + return async (path, options) => { + if (typeof path !== 'string') { + options = path + path = '/' } - return send({ - path: 'files/flush', - args: args - }, (error) => callback(error)) - }) -} + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', path) + + await ky.post('files/flush', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/files/index.js b/src/files/index.js index d35e82ea7..25e79fcab 100644 --- a/src/files/index.js +++ b/src/files/index.js @@ -1,23 +1,25 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') +const { collectify, streamify, pullify, concatify } = require('../lib/converters') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = config => { + const ls = require('./ls')(config) + const read = require('./read')(config) return { - cp: require('./cp')(send), - mkdir: require('./mkdir')(send), - flush: require('./flush')(send), - stat: require('./stat')(send), - rm: require('./rm')(send), - ls: require('./ls')(send), - lsReadableStream: require('./ls-readable-stream')(send), - lsPullStream: require('./ls-pull-stream')(send), - read: require('./read')(send), - readReadableStream: require('./read-readable-stream')(send), - readPullStream: require('./read-pull-stream')(send), - write: require('./write')(send), - mv: require('./mv')(send) + cp: callbackify.variadic(require('./cp')(config)), + mkdir: callbackify.variadic(require('./mkdir')(config)), + flush: callbackify.variadic(require('./flush')(config)), + stat: callbackify.variadic(require('./stat')(config)), + rm: callbackify.variadic(require('./rm')(config)), + ls: callbackify.variadic(collectify(ls)), + lsReadableStream: streamify.readable(ls), + lsPullStream: pullify.source(ls), + read: callbackify.variadic(concatify(read)), + readReadableStream: streamify.readable(read), + readPullStream: pullify.source(read), + write: callbackify.variadic(require('./write')(config)), + mv: callbackify.variadic(require('./mv')(config)) } } diff --git a/src/files/ls-pull-stream.js b/src/files/ls-pull-stream.js deleted file mode 100644 index 111eba7ed..000000000 --- a/src/files/ls-pull-stream.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const toPull = require('stream-to-pull-stream') -const lsReadableStream = require('./ls-readable-stream') - -module.exports = (send) => { - return (args, opts) => { - opts = opts || {} - - return toPull.source(lsReadableStream(send)(args, opts)) - } -} diff --git a/src/files/ls-readable-stream.js b/src/files/ls-readable-stream.js deleted file mode 100644 index 404893e70..000000000 --- a/src/files/ls-readable-stream.js +++ /dev/null @@ -1,62 +0,0 @@ -'use strict' - -const { - Transform, - PassThrough -} = require('readable-stream') -const pump = require('pump') -const ndjson = require('ndjson') -const isStream = require('is-stream') - -const toEntry = (entry) => { - return { - name: entry.Name, - type: entry.Type, - size: entry.Size, - hash: entry.Hash - } -} - -module.exports = (send) => { - return (args, opts) => { - opts = opts || {} - - const transform = new Transform({ - objectMode: true, - - transform (entry, encoding, callback) { - callback(null, toEntry(entry)) - } - }) - - const output = new PassThrough({ - objectMode: true - }) - - send({ - path: 'files/ls', - args: args, - qs: Object.assign({}, opts, { stream: true }) - }, (err, res) => { - if (err) { - return output.destroy(err) - } - - if (isStream(res)) { - const parse = ndjson.parse() - - pump(res, parse, transform, output) - } else { - const entries = res.Entries || [] - - entries.forEach((entry) => { - output.write(toEntry(entry)) - }) - - output.end() - } - }) - - return output - } -} diff --git a/src/files/ls.js b/src/files/ls.js index ff22f5396..1baa3f656 100644 --- a/src/files/ls.js +++ b/src/files/ls.js @@ -1,37 +1,42 @@ 'use strict' -const promisify = require('promisify-es6') +const CID = require('cids') +const ndjson = require('iterable-ndjson') +const toIterable = require('../lib/stream-to-iterable') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - const entries = res.Entries || [] - - callback(null, entries.map((entry) => { - return { - name: entry.Name, - type: entry.Type, - size: entry.Size, - hash: entry.Hash +module.exports = configure(({ ky }) => { + return async function * ls (path, options) { + if (typeof path !== 'string') { + options = path + path = '/' } - })) -} -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + options = options || {} - if (typeof (args) === 'function') { - callback = args - opts = {} - args = null - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', CID.isCID(path) ? `/ipfs/${path}` : path) + searchParams.set('stream', true) + if (options.cidBase) searchParams.set('cid-base', options.cidBase) + if (options.long != null) searchParams.set('long', options.long) - return send.andTransform({ - path: 'files/ls', - args: args, - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('files/ls', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const result of ndjson(toIterable(res.body))) { + // go-ipfs does not yet support the "stream" option + if ('Entries' in result) { + for (const entry of result.Entries || []) { + yield toCamel(entry) + } + return + } + yield toCamel(result) + } + } +}) diff --git a/src/files/mkdir.js b/src/files/mkdir.js index b77fbf6dd..0fc3c238d 100644 --- a/src/files/mkdir.js +++ b/src/files/mkdir.js @@ -1,18 +1,24 @@ - 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') + +module.exports = configure(({ ky }) => { + return (path, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.append('arg', path) + if (options.cidVersion != null) searchParams.set('cid-version', options.cidVersion) + if (options.format) searchParams.set('format', options.format) + if (options.flush != null) searchParams.set('flush', options.flush) + if (options.hashAlg) searchParams.set('hash', options.hashAlg) + if (options.parents != null) searchParams.set('parents', options.parents) -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'files/mkdir', - args: args, - qs: opts - }, (error) => callback(error)) - }) -} + return ky.post('files/mkdir', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/files/mv.js b/src/files/mv.js index 234491b28..fadf0c34c 100644 --- a/src/files/mv.js +++ b/src/files/mv.js @@ -1,20 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') -const findSources = require('../utils/find-sources') +const CID = require('cids') +const configure = require('../lib/configure') +const { findSources } = require('./utils') -module.exports = (send) => { - return promisify(function () { - const { - callback, - sources, - opts - } = findSources(Array.prototype.slice.call(arguments)) +module.exports = configure(({ ky }) => { + return (...args) => { + const { sources, options } = findSources(args) - send({ - path: 'files/mv', - args: sources, - qs: opts - }, (error) => callback(error)) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + sources.forEach(src => searchParams.append('arg', CID.isCID(src) ? `/ipfs/${src}` : src)) + if (options.format) searchParams.set('format', options.format) + if (options.flush != null) searchParams.set('flush', options.flush) + if (options.hashAlg) searchParams.set('hash', options.hashAlg) + if (options.parents != null) searchParams.set('parents', options.parents) + + return ky.post('files/mv', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/files/read-pull-stream.js b/src/files/read-pull-stream.js deleted file mode 100644 index 3e9ab8c3d..000000000 --- a/src/files/read-pull-stream.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const toPull = require('stream-to-pull-stream') -const deferred = require('pull-defer') - -module.exports = (send) => { - return (args, opts) => { - opts = opts || {} - - const p = deferred.source() - - send({ - path: 'files/read', - args: args, - qs: opts - }, (err, stream) => { - if (err) { - return p.abort(err) - } - - p.resolve(toPull(stream)) - }) - - return p - } -} diff --git a/src/files/read-readable-stream.js b/src/files/read-readable-stream.js deleted file mode 100644 index df8b92fbf..000000000 --- a/src/files/read-readable-stream.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict' - -const Stream = require('readable-stream') -const pump = require('pump') - -module.exports = (send) => { - return (args, opts) => { - opts = opts || {} - - const pt = new Stream.PassThrough() - - send({ - path: 'files/read', - args: args, - qs: opts - }, (err, stream) => { - if (err) { - return pt.destroy(err) - } - - pump(stream, pt) - }) - - return pt - } -} diff --git a/src/files/read.js b/src/files/read.js index 378d53dfa..5a6a14acb 100644 --- a/src/files/read.js +++ b/src/files/read.js @@ -1,19 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') -const streamToValue = require('../utils/stream-to-value') +const { Buffer } = require('buffer') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return async function * read (path, options) { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.append('arg', `${path}`) + if (options.length != null) searchParams.set('length', options.length) + if (options.offset != null) searchParams.set('offset', options.offset) - send.andTransform({ - path: 'files/read', - args: args, - qs: opts - }, streamToValue, callback) - }) -} + const res = await ky.post('files/read', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const chunk of toIterable(res.body)) { + yield Buffer.from(chunk) + } + } +}) diff --git a/src/files/rm.js b/src/files/rm.js index 404ceed10..c0a5e7eab 100644 --- a/src/files/rm.js +++ b/src/files/rm.js @@ -1,27 +1,21 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((path, opts, callback) => { - if (typeof opts === 'function' && - !callback) { - callback = opts - opts = {} - } +module.exports = configure(({ ky }) => { + return (path, options) => { + options = options || {} - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && - typeof callback === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.append('arg', path) + if (options.recursive != null) searchParams.set('recursive', options.recursive) + if (options.force != null) searchParams.set('force', options.force) - send({ - path: 'files/rm', - args: path, - qs: opts - }, (error) => callback(error)) - }) -} + return ky.post('files/rm', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/files/stat.js b/src/files/stat.js index 7274e32a1..98026283e 100644 --- a/src/files/stat.js +++ b/src/files/stat.js @@ -1,35 +1,32 @@ 'use strict' -const promisify = require('promisify-es6') -const mapKeys = require('just-map-keys') -const kebabCase = require('just-kebab-case') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (data, callback) { - callback(null, { - type: data.Type, - blocks: data.Blocks, - size: data.Size, - hash: data.Hash, - cumulativeSize: data.CumulativeSize, - withLocality: data.WithLocality || false, - local: data.Local || undefined, - sizeLocal: data.SizeLocal || undefined - }) -} - -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} +module.exports = configure(({ ky }) => { + return async (path, options) => { + if (typeof path !== 'string') { + options = path + path = '/' } - opts = mapKeys(opts, (v, k) => kebabCase(k)) + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', path) + if (options.cidBase) searchParams.set('cid-base', options.cidBase) + if (options.hash != null) searchParams.set('hash', options.hash) + if (options.size != null) searchParams.set('size', options.size) + if (options.withLocal != null) searchParams.set('with-local', options.withLocal) + + const res = await ky.post('files/stat', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send.andTransform({ - path: 'files/stat', - args: args, - qs: opts - }, transform, callback) - }) -} + res.WithLocality = res.WithLocality || false + return toCamel(res) + } +}) diff --git a/src/utils/find-sources.js b/src/files/utils.js similarity index 50% rename from src/utils/find-sources.js rename to src/files/utils.js index 2a862514a..6dc2c499d 100644 --- a/src/utils/find-sources.js +++ b/src/files/utils.js @@ -1,25 +1,23 @@ 'use strict' -module.exports = (args) => { - const callback = args.pop() - let opts = {} +exports.findSources = (args) => { + let options = {} let sources = [] if (!Array.isArray(args[args.length - 1]) && typeof args[args.length - 1] === 'object') { - opts = args.pop() + options = args.pop() } if (args.length === 1 && Array.isArray(args[0])) { - // support ipfs.file.cp([src, dest], opts, cb) + // support ipfs.files.cp([src, dest], opts) sources = args[0] } else { - // support ipfs.file.cp(src, dest, opts, cb) and ipfs.file.cp(src1, src2, dest, opts, cb) + // support ipfs.files.cp(src, dest, opts) and ipfs.files.cp(src1, src2, dest, opts) sources = args } return { - callback, sources, - opts + options } } diff --git a/src/files/write.js b/src/files/write.js index 33f1ec973..77a772ea6 100644 --- a/src/files/write.js +++ b/src/files/write.js @@ -1,42 +1,32 @@ 'use strict' -const promisify = require('promisify-es6') -const concatStream = require('concat-stream') -const once = require('once') -const SendFilesStream = require('../utils/send-files-stream') - -module.exports = (send) => { - const sendFilesStream = SendFilesStream(send, 'files/write') - - return promisify((pathDst, _files, opts, _callback) => { - if (typeof opts === 'function' && - !_callback) { - _callback = opts - opts = {} - } - - // opts is the real callback -- - // 'callback' is being injected by promisify - if (typeof opts === 'function' && - typeof _callback === 'function') { - _callback = opts - opts = {} - } - - const files = [].concat(_files) - const callback = once(_callback) - - const options = { - args: pathDst, - qs: opts - } - - const stream = sendFilesStream({ qs: options }) - const concat = concatStream((result) => callback(null, result)) - stream.once('error', callback) - stream.pipe(concat) - - files.forEach((file) => stream.write(file)) - stream.end() - }) -} +const configure = require('../lib/configure') +const toFormData = require('../lib/buffer-to-form-data') + +module.exports = configure(({ ky }) => { + return async (path, input, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', path) + searchParams.set('stream-channels', true) + if (options.cidVersion) searchParams.set('cid-version', options.cidVersion) + if (options.create != null) searchParams.set('create', options.create) + if (options.hashAlg) searchParams.set('hash', options.hashAlg) + if (options.length != null) searchParams.set('length', options.length) + if (options.offset != null) searchParams.set('offset', options.offset) + if (options.parents != null) searchParams.set('parents', options.parents) + if (options.rawLeaves != null) searchParams.set('raw-leaves', options.rawLeaves) + if (options.truncate != null) searchParams.set('truncate', options.truncate) + + const res = await ky.post('files/write', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(input) // TODO: support inputs other than buffer as per spec + }) + + return res.text() + } +}) diff --git a/src/lib/configure.js b/src/lib/configure.js index 8401683f9..b1a1f8948 100644 --- a/src/lib/configure.js +++ b/src/lib/configure.js @@ -6,6 +6,7 @@ const { isBrowser, isWebWorker } = require('ipfs-utils/src/env') const { toUri } = require('./multiaddr') const errorHandler = require('./error-handler') const mergeOptions = require('merge-options').bind({ ignoreUndefined: true }) +const parseDuration = require('parse-duration') // Set default configuration and call create function with them module.exports = create => config => { @@ -27,7 +28,7 @@ module.exports = create => config => { // https://github.com/sindresorhus/ky/pull/153 const defaults = { prefixUrl: config.apiAddr + config.apiPath, - timeout: config.timeout || 60000 * 20, + timeout: parseTimeout(config.timeout) || 60000 * 20, headers: config.headers, hooks: { afterResponse: [errorHandler] @@ -72,6 +73,11 @@ function getDefaultApiAddr ({ protocol, host, port }) { // undefined values in the passed `options` object function wrap (fn, defaults) { return (input, options) => { + if (options.timeout) options.timeout = parseTimeout(options.timeout) return fn(input, mergeOptions(defaults, options)) } } + +function parseTimeout (value) { + return typeof value === 'string' ? parseDuration(value) : value +} diff --git a/src/object/addLink.js b/src/object/addLink.js deleted file mode 100644 index bda202bce..000000000 --- a/src/object/addLink.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const CID = require('cids') - -module.exports = (send) => { - return promisify((cid, dLink, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - if (!opts) { - opts = {} - } - - try { - cid = new CID(cid) - } catch (err) { - return callback(err) - } - - const args = [ - cid.toString(), - dLink.Name || dLink.name || null, - (dLink.Hash || dLink.cid || '').toString() || null - ] - - send({ path: 'object/patch/add-link', args }, (err, result) => { - if (err) { - return callback(err) - } - callback(null, new CID(result.Hash)) - }) - }) -} diff --git a/src/object/appendData.js b/src/object/appendData.js deleted file mode 100644 index 6c6cdb722..000000000 --- a/src/object/appendData.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const once = require('once') -const CID = require('cids') -const SendOneFile = require('../utils/send-one-file') - -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'object/patch/append-data') - - return promisify((cid, data, opts, _callback) => { - if (typeof opts === 'function') { - _callback = opts - opts = {} - } - const callback = once(_callback) - if (!opts) { - opts = {} - } - - try { - cid = new CID(cid) - } catch (err) { - return callback(err) - } - - sendOneFile(data, { args: [cid.toString()] }, (err, result) => { - if (err) { - return callback(err) - } - - callback(null, new CID(result.Hash)) - }) - }) -} diff --git a/src/object/data.js b/src/object/data.js index bbc43ebd6..8f1e42b7a 100644 --- a/src/object/data.js +++ b/src/object/data.js @@ -1,53 +1,26 @@ 'use strict' -const promisify = require('promisify-es6') -const streamToValue = require('../utils/stream-to-value') +const { Buffer } = require('buffer') const CID = require('cids') -const LRU = require('lru-cache') -const lruOptions = { - max: 128 -} +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -const cache = new LRU(lruOptions) +module.exports = configure(({ ky }) => { + return async function * (cid, options) { + options = options || {} -module.exports = (send) => { - return promisify((cid, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - if (!options) { - options = {} - } - - let cidB58Str - - try { - cid = new CID(cid) - cidB58Str = cid.toBaseEncodedString() - } catch (err) { - return callback(err) - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) - const node = cache.get(cidB58Str) + const res = await ky.get('object/data', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) - if (node) { - return callback(null, node.data) + for await (const chunk of toIterable(res.body)) { + yield Buffer.from(chunk) } - - send({ - path: 'object/data', - args: cidB58Str - }, (err, result) => { - if (err) { - return callback(err) - } - - if (typeof result.pipe === 'function') { - streamToValue(result, callback) - } else { - callback(null, result) - } - }) - }) -} + } +}) diff --git a/src/object/get.js b/src/object/get.js index 5052c8af3..5ed7468dc 100644 --- a/src/object/get.js +++ b/src/object/get.js @@ -1,57 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') -const { DAGNode, DAGLink } = require('ipld-dag-pb') +const { Buffer } = require('buffer') const CID = require('cids') -const LRU = require('lru-cache') -const lruOptions = { - max: 128 -} - -const cache = new LRU(lruOptions) - -module.exports = (send) => { - return promisify((cid, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - - if (!options) { - options = {} - } - - let cidB58Str - - try { - cid = new CID(cid) - cidB58Str = cid.toBaseEncodedString() - } catch (err) { - return callback(err) - } - - const node = cache.get(cidB58Str) - - if (node) { - return callback(null, node) - } - - send({ - path: 'object/get', - args: cidB58Str, - qs: { - 'data-encoding': 'base64' - } - }, (err, result) => { - if (err) { - return callback(err) - } - - const links = result.Links.map(l => new DAGLink(l.Name, l.Size, l.Hash)) - const node = new DAGNode(Buffer.from(result.Data, 'base64'), links) - - cache.set(cidB58Str, node) - callback(null, node) - }) - }) -} +const { DAGNode, DAGLink } = require('ipld-dag-pb') +const configure = require('../lib/configure') + +module.exports = configure(({ ky }) => { + return async (cid, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + searchParams.set('data-encoding', 'base64') + + const res = await ky.get('object/get', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return new DAGNode( + Buffer.from(res.Data, 'base64'), + (res.Links || []).map(l => new DAGLink(l.Name, l.Size, l.Hash)) + ) + } +}) diff --git a/src/object/index.js b/src/object/index.js index 2966232c4..dac85598c 100644 --- a/src/object/index.js +++ b/src/object/index.js @@ -1,22 +1,14 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') +const { concatify } = require('../lib/converters') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - get: require('./get')(send), - put: require('./put')(send), - data: require('./data')(send), - links: require('./links')(send), - stat: require('./stat')(send), - new: require('./new')(send), - patch: { - addLink: require('./addLink')(send), - rmLink: require('./rmLink')(send), - setData: require('./setData')(send), - appendData: require('./appendData')(send) - } - } -} +module.exports = config => ({ + data: callbackify.variadic(concatify(require('./data')(config))), + get: callbackify.variadic(require('./get')(config)), + links: callbackify.variadic(require('./links')(config)), + new: callbackify.variadic(require('./new')(config)), + patch: require('./patch')(config), + put: callbackify.variadic(require('./put')(config)), + stat: callbackify.variadic(require('./stat')(config)) +}) diff --git a/src/object/links.js b/src/object/links.js index 0b0366c81..49b088254 100644 --- a/src/object/links.js +++ b/src/object/links.js @@ -1,53 +1,24 @@ 'use strict' -const promisify = require('promisify-es6') -const { DAGLink } = require('ipld-dag-pb') +const { Buffer } = require('buffer') const CID = require('cids') -const LRU = require('lru-cache') -const lruOptions = { - max: 128 -} - -const cache = new LRU(lruOptions) - -module.exports = (send) => { - return promisify((cid, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - if (!options) { - options = {} - } - - try { - cid = new CID(cid) - } catch (err) { - return callback(err) - } - - const node = cache.get(cid.toString()) +const { DAGLink } = require('ipld-dag-pb') +const configure = require('../lib/configure') - if (node) { - return callback(null, node.links) - } +module.exports = configure(({ ky }) => { + return async (cid, options) => { + options = options || {} - send({ - path: 'object/links', - args: cid.toString() - }, (err, result) => { - if (err) { - return callback(err) - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) - let links = [] + const res = await ky.get('object/links', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - if (result.Links) { - links = result.Links.map((l) => { - return new DAGLink(l.Name, l.Size, l.Hash) - }) - } - callback(null, links) - }) - }) -} + return (res.Links || []).map(l => new DAGLink(l.Name, l.Size, l.Hash)) + } +}) diff --git a/src/object/new.js b/src/object/new.js index f9d8ddb35..d372812a5 100644 --- a/src/object/new.js +++ b/src/object/new.js @@ -1,23 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') const CID = require('cids') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((template, callback) => { - if (typeof template === 'function') { - callback = template - template = undefined +module.exports = configure(({ ky }) => { + return async (template, options) => { + if (typeof template !== 'string') { + options = template + template = null } - send({ - path: 'object/new', - args: template - }, (err, result) => { - if (err) { - return callback(err) - } - callback(null, new CID(result.Hash)) - }) - }) -} + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + if (template) searchParams.set('arg', template) + + const { Hash } = await ky.post('object/new', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/patch/add-link.js b/src/object/patch/add-link.js new file mode 100644 index 000000000..55821751d --- /dev/null +++ b/src/object/patch/add-link.js @@ -0,0 +1,25 @@ +'use strict' + +const { Buffer } = require('buffer') +const CID = require('cids') +const configure = require('../../lib/configure') + +module.exports = configure(({ ky }) => { + return async (cid, dLink, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + searchParams.append('arg', dLink.Name || dLink.name || null) + searchParams.append('arg', (dLink.Hash || dLink.cid || '').toString() || null) + + const { Hash } = await ky.post('object/patch/add-link', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/patch/append-data.js b/src/object/patch/append-data.js new file mode 100644 index 000000000..1ab8d1381 --- /dev/null +++ b/src/object/patch/append-data.js @@ -0,0 +1,25 @@ +'use strict' + +const { Buffer } = require('buffer') +const CID = require('cids') +const configure = require('../../lib/configure') +const toFormData = require('../../lib/buffer-to-form-data') + +module.exports = configure(({ ky }) => { + return async (cid, data, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + + const { Hash } = await ky.post('object/patch/append-data', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(data) + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/patch/index.js b/src/object/patch/index.js new file mode 100644 index 000000000..5711200ec --- /dev/null +++ b/src/object/patch/index.js @@ -0,0 +1,10 @@ +'use strict' + +const callbackify = require('callbackify') + +module.exports = config => ({ + addLink: callbackify.variadic(require('./add-link')(config)), + appendData: callbackify.variadic(require('./append-data')(config)), + rmLink: callbackify.variadic(require('./rm-link')(config)), + setData: callbackify.variadic(require('./set-data')(config)) +}) diff --git a/src/object/patch/rm-link.js b/src/object/patch/rm-link.js new file mode 100644 index 000000000..39ea0ea3b --- /dev/null +++ b/src/object/patch/rm-link.js @@ -0,0 +1,24 @@ +'use strict' + +const { Buffer } = require('buffer') +const CID = require('cids') +const configure = require('../../lib/configure') + +module.exports = configure(({ ky }) => { + return async (cid, dLink, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + searchParams.append('arg', dLink.Name || dLink.name || null) + + const { Hash } = await ky.post('object/patch/rm-link', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/patch/set-data.js b/src/object/patch/set-data.js new file mode 100644 index 000000000..7bb131fb7 --- /dev/null +++ b/src/object/patch/set-data.js @@ -0,0 +1,25 @@ +'use strict' + +const { Buffer } = require('buffer') +const CID = require('cids') +const configure = require('../../lib/configure') +const toFormData = require('../../lib/buffer-to-form-data') + +module.exports = configure(({ ky }) => { + return async (cid, data, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + + const { Hash } = await ky.post('object/patch/set-data', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(data) + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/put.js b/src/object/put.js index 40b9ffac4..be8660a00 100644 --- a/src/object/put.js +++ b/src/object/put.js @@ -1,26 +1,14 @@ 'use strict' -const promisify = require('promisify-es6') const CID = require('cids') const { DAGNode } = require('ipld-dag-pb') +const { Buffer } = require('buffer') +const configure = require('../lib/configure') +const toFormData = require('../lib/buffer-to-form-data') -const SendOneFile = require('../utils/send-one-file') -const once = require('once') - -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'object/put') - - return promisify((obj, options, _callback) => { - if (typeof options === 'function') { - _callback = options - options = {} - } - - const callback = once(_callback) - - if (!options) { - options = {} - } +module.exports = configure(({ ky }) => { + return async (obj, options) => { + options = options || {} let tmpObj = { Data: null, @@ -47,7 +35,7 @@ module.exports = (send) => { tmpObj.Data = obj.Data.toString() tmpObj.Links = obj.Links } else { - return callback(new Error('obj not recognized')) + throw new Error('obj not recognized') } let buf @@ -56,18 +44,20 @@ module.exports = (send) => { } else { buf = Buffer.from(JSON.stringify(tmpObj)) } - const enc = options.enc || 'json' - - const sendOptions = { - qs: { inputenc: enc } - } - - sendOneFile(buf, sendOptions, (err, result) => { - if (err) { - return callback(err) // early - } - callback(null, new CID(result.Hash)) - }) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + if (options.enc) searchParams.set('inputenc', options.enc) + if (options.pin != null) searchParams.set('pin', options.pin) + if (options.quiet != null) searchParams.set('quiet', options.quiet) + + const { Hash } = await ky.post('object/put', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams, + body: toFormData(buf) + }).json() + + return new CID(Hash) + } +}) diff --git a/src/object/rmLink.js b/src/object/rmLink.js deleted file mode 100644 index db699feeb..000000000 --- a/src/object/rmLink.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const CID = require('cids') - -module.exports = (send) => { - return promisify((cid, dLink, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - if (!opts) { - opts = {} - } - - try { - cid = new CID(cid) - } catch (err) { - return callback(err) - } - - send({ - path: 'object/patch/rm-link', - args: [ - cid.toString(), - dLink.Name || dLink.name || null - ] - }, (err, result) => { - if (err) { - return callback(err) - } - callback(null, new CID(result.Hash)) - }) - }) -} diff --git a/src/object/setData.js b/src/object/setData.js deleted file mode 100644 index 5eb014474..000000000 --- a/src/object/setData.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const once = require('once') -const CID = require('cids') -const SendOneFile = require('../utils/send-one-file') - -module.exports = (send) => { - const sendOneFile = SendOneFile(send, 'object/patch/set-data') - - return promisify((cid, data, opts, _callback) => { - if (typeof opts === 'function') { - _callback = opts - opts = {} - } - const callback = once(_callback) - if (!opts) { - opts = {} - } - - try { - cid = new CID(cid) - } catch (err) { - return callback(err) - } - - sendOneFile(data, { args: [cid.toString()] }, (err, result) => { - if (err) { - return callback(err) - } - callback(null, new CID(result.Hash)) - }) - }) -} diff --git a/src/object/stat.js b/src/object/stat.js index 6488a297e..c3d2d8edc 100644 --- a/src/object/stat.js +++ b/src/object/stat.js @@ -1,28 +1,31 @@ 'use strict' -const promisify = require('promisify-es6') +const { Buffer } = require('buffer') const CID = require('cids') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((cid, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - if (!opts) { - opts = {} - } +module.exports = configure(({ ky }) => { + return async (cid, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) + let res try { - cid = new CID(cid) + res = await ky.post('object/stat', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() } catch (err) { - return callback(err) + if (err.name === 'TimeoutError') { + err.message = `failed to get block for ${Buffer.isBuffer(cid) ? new CID(cid) : cid}: context deadline exceeded` + } + throw err } - send({ - path: 'object/stat', - args: cid.toString(), - qs: opts - }, callback) - }) -} + return res + } +}) diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js index 933241a0b..a4a6dcd07 100644 --- a/src/utils/load-commands.js +++ b/src/utils/load-commands.js @@ -102,6 +102,7 @@ function requireCommands (send, config) { lsReadableStream: streamify.readable(ls), lsPullStream: pullify.source(ls), _lsAsyncIterator: ls, + object: require('../object')(config), refs: callbackify.variadic((path, options) => collectify(refs)(path, options)), refsReadableStream: streamify.readable(refs), refsPullStream: pullify.source(refs), @@ -114,6 +115,7 @@ function requireCommands (send, config) { dag: require('../dag')(config), dht: require('../dht')(config), diag: require('../diag')(config), + files: require('../files')(config), pin: require('../pin')(config) } @@ -125,12 +127,6 @@ function requireCommands (send, config) { }) const subCmds = { - // Files MFS (Mutable Filesystem) - files: require('../files'), - - // Graph - object: require('../object'), - // Network name: require('../name'), ping: require('../ping'), diff --git a/test/files-mfs.spec.js b/test/files-mfs.spec.js index 203fd6eb5..6ae508d1d 100644 --- a/test/files-mfs.spec.js +++ b/test/files-mfs.spec.js @@ -376,9 +376,7 @@ describe('.files (the MFS API part)', function () { cumulativeSize: 70, blocks: 1, type: 'file', - withLocality: false, - local: undefined, - sizeLocal: undefined + withLocality: false }) }) From 3e5967af8e456517485c8a7536792107c0ed6e63 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 22 Nov 2019 11:45:30 +0000 Subject: [PATCH 22/24] refactor: async await roundup (#1173) This is a round up of the remaining async/await PRs along with some cleanup and docs fixes. resolves #1103 resolves https://github.com/ipfs/js-ipfs-http-client/issues/1122 resolves https://github.com/ipfs/js-ipfs-http-client/issues/1158 (hopefully!) closes https://github.com/ipfs/js-ipfs-http-client/pull/1164 closes https://github.com/ipfs/js-ipfs-http-client/pull/1165 closes https://github.com/ipfs/js-ipfs-http-client/pull/1166 closes https://github.com/ipfs/js-ipfs-http-client/pull/1169 closes https://github.com/ipfs/js-ipfs-http-client/pull/1170 closes https://github.com/ipfs/js-ipfs-http-client/pull/1172 BREAKING CHANGE: The `log.tail` method now returns an async iterator that yields log messages. Use it like: ```js for await (const message of ipfs.log.tail()) { console.log(message) } ``` BREAKING CHANGE: The response to a call to `log.level` now returns an object that has camel cased keys. i.e. `Message` and `Error` properties have changed to `message` and `error`. BREAKING CHANGE: Dropped support for go-ipfs <= 0.4.4 in `swarm.peers` response. BREAKING CHANGE: The signature for `ipfs.mount` has changed from `ipfs.mount([ipfsPath], [ipnsPath])` to `ipfs.mount([options])`. Where `options` is an optional object that may contain two boolean properties `ipfsPath` and `ipnsPath`. The response object has also changed to be camel case. See https://docs.ipfs.io/reference/api/http/#api-v0-mount. BREAKING CHANGE: Default ping `count` of 1 in client has been removed. The default ping count is now whatever the IPFS node defaults it to (currently 10). If you specifically need 1 ping message then please pass `count: 1` in options for `ipfs.ping()`. BREAKING CHANGE: Multi parameter constructor options are no longer supported. To create a new IPFS HTTP client, pass a single parameter to the constructor. The parameter can be one of: * String, formatted as one of: * Multiaddr e.g. /ip4/127.0.0.1/tcp/5001 * URL e.g. http://127.0.0.1:5001 * [Multiaddr](https://www.npmjs.com/package/multiaddr) instance * Object, in format of either: * Address and path e.g. `{ apiAddr: '/ip4/127.0.0.1/tcp/5001': apiPath: '/api/v0' }` (Note: `apiAddr` can also be a string in URL form or a Multiaddr instance) * Node.js style address e.g. `{ host: '127.0.0.1', port: 5001, protocol: 'http' }` --- README.md | 231 +++++++++-------- package.json | 32 +-- src/add-from-url.js | 4 +- src/add/index.js | 4 +- src/bitswap/stat.js | 2 +- src/bitswap/unwant.js | 2 +- src/bitswap/wantlist.js | 2 +- src/block/get.js | 2 +- src/block/rm-async-iterator.js | 2 +- src/block/stat.js | 2 +- src/bootstrap/list.js | 2 +- src/cat.js | 6 +- src/commands.js | 29 ++- src/config/get.js | 2 +- src/config/profiles/list.js | 2 +- src/dag/resolve.js | 2 +- src/dht/find-peer.js | 6 +- src/dht/find-provs.js | 6 +- src/dht/get.js | 6 +- src/dht/provide.js | 6 +- src/dht/put.js | 6 +- src/dht/query.js | 6 +- src/diag/cmds.js | 2 +- src/diag/net.js | 2 +- src/diag/sys.js | 2 +- src/dns.js | 35 ++- src/get-endpoint-config.js | 15 +- src/get.js | 16 +- src/id.js | 41 +-- src/index.js | 191 ++++++++++---- src/key/export.js | 35 ++- src/key/gen.js | 39 ++- src/key/import.js | 44 ++-- src/key/index.js | 22 +- src/key/list.js | 35 +-- src/key/rename.js | 37 +-- src/key/rm.js | 33 +-- src/lib/configure.js | 31 ++- src/lib/multiaddr.js | 18 -- src/log/index.js | 16 +- src/log/level.js | 40 ++- src/log/ls.js | 27 +- src/log/tail.js | 32 +-- src/ls.js | 16 +- src/mount.js | 43 ++-- src/name/index.js | 16 +- src/name/publish.js | 43 ++-- src/name/pubsub/cancel.js | 36 ++- src/name/pubsub/index.js | 10 +- src/name/pubsub/state.js | 32 +-- src/name/pubsub/subs.js | 29 +-- src/name/resolve.js | 37 +-- src/object/data.js | 4 +- src/object/get.js | 2 +- src/object/links.js | 2 +- src/pin/ls.js | 2 +- src/ping-pull-stream.js | 34 --- src/ping-readable-stream.js | 30 --- src/ping.js | 81 ++---- src/pubsub/ls.js | 2 +- src/pubsub/peers.js | 2 +- src/refs/index.js | 18 +- src/refs/local.js | 2 +- src/repo/gc.js | 48 ++-- src/repo/index.js | 17 +- src/repo/stat.js | 44 ++-- src/repo/version.js | 32 +-- src/resolve.js | 75 ++---- src/stats/bitswap.js | 32 --- src/stats/bw-pull-stream.js | 31 --- src/stats/bw-readable-stream.js | 31 --- src/stats/bw-util.js | 12 - src/stats/bw.js | 51 ++-- src/stats/index.js | 22 +- src/stats/repo.js | 28 -- src/stop.js | 20 +- src/swarm/addrs.js | 40 ++- src/swarm/connect.js | 33 ++- src/swarm/disconnect.js | 33 ++- src/swarm/index.js | 20 +- src/swarm/localAddrs.js | 38 ++- src/swarm/peers.js | 104 +++----- src/update.js | 47 +--- src/utils/clean-cid.js | 17 -- src/utils/clean-multihash.js | 21 -- src/utils/default-config.js | 13 - src/utils/load-commands.js | 161 ------------ src/utils/module-config.js | 22 -- src/utils/multipart.js | 121 --------- src/utils/ping-message-converter.js | 23 -- src/utils/ping-message-stream.js | 27 -- src/utils/prepare-file.js | 153 ----------- src/utils/progress-stream.js | 49 ---- src/utils/send-files-stream.js | 161 ------------ src/utils/send-one-file-multiple-results.js | 18 -- src/utils/send-one-file.js | 15 -- src/utils/send-request.js | 239 ------------------ src/utils/stream-to-json-value.js | 34 --- src/utils/stream-to-value-with-transformer.js | 18 -- src/utils/stream-to-value.js | 18 -- src/version.js | 39 +-- test/constructor.spec.js | 21 +- test/custom-headers.spec.js | 21 +- test/endpoint-config.spec.js | 35 +-- test/lib.configure.spec.js | 13 +- test/log.spec.js | 23 +- test/node/swarm.js | 18 -- test/ping.spec.js | 54 +--- test/sub-modules.spec.js | 52 ++-- 109 files changed, 1079 insertions(+), 2581 deletions(-) delete mode 100644 src/lib/multiaddr.js delete mode 100644 src/ping-pull-stream.js delete mode 100644 src/ping-readable-stream.js delete mode 100644 src/stats/bitswap.js delete mode 100644 src/stats/bw-pull-stream.js delete mode 100644 src/stats/bw-readable-stream.js delete mode 100644 src/stats/bw-util.js delete mode 100644 src/stats/repo.js delete mode 100644 src/utils/clean-cid.js delete mode 100644 src/utils/clean-multihash.js delete mode 100644 src/utils/default-config.js delete mode 100644 src/utils/load-commands.js delete mode 100644 src/utils/module-config.js delete mode 100644 src/utils/multipart.js delete mode 100644 src/utils/ping-message-converter.js delete mode 100644 src/utils/ping-message-stream.js delete mode 100644 src/utils/prepare-file.js delete mode 100644 src/utils/progress-stream.js delete mode 100644 src/utils/send-files-stream.js delete mode 100644 src/utils/send-one-file-multiple-results.js delete mode 100644 src/utils/send-one-file.js delete mode 100644 src/utils/send-request.js delete mode 100644 src/utils/stream-to-json-value.js delete mode 100644 src/utils/stream-to-value-with-transformer.js delete mode 100644 src/utils/stream-to-value.js diff --git a/README.md b/README.md index 4e27f3db3..5c6a00070 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,16 @@ - [In a web browser](#in-a-web-browser) - [CORS](#cors) - [Custom Headers](#custom-headers) + - [Global Timeouts](#global-timeouts) - [Usage](#usage) - [API](#api) - [Files](#files) - [Graph](#graph) - [Network](#network) - [Node Management](#node-management) - - [Instance utils](#instance-utils) - - [Static types and utils](#static-types-and-utils) + - [Additional Options](#additional-options) + - [Instance Utils](#instance-utils) + - [Static Types and Utils](#static-types-and-utils) - [Development](#development) - [Testing](#testing) - [Contribute](#contribute) @@ -86,19 +88,19 @@ To interact with the API, you need to have a local daemon running. It needs to b ### Importing the module and usage ```javascript -var ipfsClient = require('ipfs-http-client') +const ipfsClient = require('ipfs-http-client') // connect to ipfs daemon API server -var ipfs = ipfsClient('localhost', '5001', { protocol: 'http' }) // leaving out the arguments will default to these values +const ipfs = ipfsClient('http://localhost:5001') // (the default in Node.js) // or connect with multiaddr -var ipfs = ipfsClient('/ip4/127.0.0.1/tcp/5001') +const ipfs = ipfsClient('/ip4/127.0.0.1/tcp/5001') // or using options -var ipfs = ipfsClient({ host: 'localhost', port: '5001', protocol: 'http' }) +const ipfs = ipfsClient({ host: 'localhost', port: '5001', protocol: 'http' }) // or specifying a specific API path -var ipfs = ipfsClient({ host: '1.1.1.1', port: '80', 'api-path': '/ipfs/api/v0' }) +const ipfs = ipfsClient({ host: '1.1.1.1', port: '80', apiPath: '/ipfs/api/v0' }) ``` ### Importing a sub-module and usage @@ -106,9 +108,8 @@ var ipfs = ipfsClient({ host: '1.1.1.1', port: '80', 'api-path': '/ipfs/api/v0' ```javascript const bitswap = require('ipfs-http-client/src/bitswap')('/ip4/127.0.0.1/tcp/5001') -bitswap.wantlist(key, (err) => { - // ... -}) +const list = await bitswap.wantlist(key) +// ... ``` ### In a web browser @@ -130,12 +131,11 @@ Instead of a local installation (and browserification) you may request a remote To always request the latest version, use the following: ```html - - - ``` +Note: remove the `.min` from the URL to get the human-readable (not minified) version. + For maximum security you may also decide to: * reference a specific version of IPFS API (to prevent unexpected breaking changes when a newer latest version is published) @@ -153,7 +153,7 @@ crossorigin="anonymous"> CDN-based IPFS API provides the `IpfsHttpClient` constructor as a method of the global `window` object. Example: ```js -const ipfs = window.IpfsHttpClient('localhost', '5001') +const ipfs = window.IpfsHttpClient({ host: 'localhost', port: 5001 }) ``` If you omit the host and port, the client will parse `window.host`, and use this information. This also works, and can be useful if you want to write apps that can be run from multiple different gateways: @@ -186,6 +186,18 @@ const ipfs = ipfsClient({ }) ``` +### Global Timeouts + +To set a global timeout for _all_ requests pass a value for the `timeout` option: + +```js +// Timeout after 10 seconds +const ipfs = ipfsClient({ timeout: 10000 }) +// Timeout after 2 minutes +const ipfs = ipfsClient({ timeout: '2m' }) +// see https://www.npmjs.com/package/parse-duration for valid string values +``` + ## Usage ### API @@ -197,74 +209,74 @@ const ipfs = ipfsClient({ #### Files - [Regular Files API](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md) - - [`ipfs.add(data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#add) + - [`ipfs.add(data, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#add) - [`ipfs.addPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addpullstream) - [`ipfs.addReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addreadablestream) - - [`ipfs.addFromStream(stream, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromstream) - - [`ipfs.addFromFs(path, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromfs) - - [`ipfs.addFromURL(url, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromurl) - - [`ipfs.cat(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#cat) + - [`ipfs.addFromStream(stream)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromstream) + - [`ipfs.addFromFs(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromfs) + - [`ipfs.addFromURL(url, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#addfromurl) + - [`ipfs.cat(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#cat) - [`ipfs.catPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#catpullstream) - [`ipfs.catReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#catreadablestream) - - [`ipfs.get(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#get) + - [`ipfs.get(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#get) - [`ipfs.getPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#getpullstream) - [`ipfs.getReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#getreadablestream) - - [`ipfs.ls(ipfsPath, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#ls) + - [`ipfs.ls(ipfsPath)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#ls) - [`ipfs.lsPullStream(ipfsPath)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#lspullstream) - [`ipfs.lsReadableStream(ipfsPath)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#lsreadablestream) - [MFS (mutable file system) specific](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#mutable-file-system) _Explore the Mutable File System through interactive coding challenges in our [ProtoSchool tutorial](https://proto.school/#/mutable-file-system/)._ - - [`ipfs.files.cp([from, to], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filescp) - - [`ipfs.files.flush([path], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesflush) - - [`ipfs.files.ls([path], [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesls) - - [`ipfs.files.mkdir(path, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesmkdir) - - [`ipfs.files.mv([from, to], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesmv) - - [`ipfs.files.read(path, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesread) + - [`ipfs.files.cp([from, to])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filescp) + - [`ipfs.files.flush([path])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesflush) + - [`ipfs.files.ls([path], [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesls) + - [`ipfs.files.mkdir(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesmkdir) + - [`ipfs.files.mv([from, to])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesmv) + - [`ipfs.files.read(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesread) - [`ipfs.files.readPullStream(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesreadpullstream) - [`ipfs.files.readReadableStream(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesreadreadablestream) - - [`ipfs.files.rm(path, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesrm) - - [`ipfs.files.stat(path, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesstat) - - [`ipfs.files.write(path, content, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#fileswrite) + - [`ipfs.files.rm(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesrm) + - [`ipfs.files.stat(path, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#filesstat) + - [`ipfs.files.write(path, content, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#fileswrite) - [block](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md) - - [`ipfs.block.get(cid, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockget) - - [`ipfs.block.put(block, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockput) - - [`ipfs.block.stat(cid, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockstat) + - [`ipfs.block.get(cid, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockget) + - [`ipfs.block.put(block, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockput) + - [`ipfs.block.stat(cid)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BLOCK.md#blockstat) - [refs](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md) - - [`ipfs.refs(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refs) - - [`ipfs.refsReadableStream(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refsreadablestream) - - [`ipfs.refsPullStream(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refspullstream) - - [`ipfs.refs.local([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocal) - - [`ipfs.refs.localReadableStream([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocalreadablestream) - - [`ipfs.refs.localPullStream([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocalpullstream) + - [`ipfs.refs(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refs) + - [`ipfs.refsReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refsreadablestream) + - [`ipfs.refsPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refspullstream) + - [`ipfs.refs.local()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocal) + - [`ipfs.refs.localReadableStream()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocalreadablestream) + - [`ipfs.refs.localPullStream()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REFS.md#refslocalpullstream) #### Graph - [dag](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md) _Explore the DAG API through interactive coding challenges in our [ProtoSchool tutorial](https://proto.school/#/basics)._ - - [`ipfs.dag.get(cid, [path], [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagget) - - [`ipfs.dag.put(dagNode, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagput) - - [`ipfs.dag.tree(cid, [path], [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagtree) + - [`ipfs.dag.get(cid, [path], [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagget) + - [`ipfs.dag.put(dagNode, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagput) + - [`ipfs.dag.tree(cid, [path], [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DAG.md#dagtree) - [object](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md) - - [`ipfs.object.data(multihash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectdata) - - [`ipfs.object.get(multihash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectget) - - [`ipfs.object.links(multihash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectlinks) - - [`ipfs.object.new([template], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectnew) - - [`ipfs.object.patch.addLink(multihash, DAGLink, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchaddlink) - - [`ipfs.object.patch.appendData(multihash, data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchappenddata) - - [`ipfs.object.patch.rmLink(multihash, DAGLink, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchrmlink) - - [`ipfs.object.patch.setData(multihash, data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchsetdata) - - [`ipfs.object.put(obj, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectput) - - [`ipfs.object.stat(multihash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectstat) + - [`ipfs.object.data(multihash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectdata) + - [`ipfs.object.get(multihash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectget) + - [`ipfs.object.links(multihash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectlinks) + - [`ipfs.object.new([template])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectnew) + - [`ipfs.object.patch.addLink(multihash, DAGLink, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchaddlink) + - [`ipfs.object.patch.appendData(multihash, data, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchappenddata) + - [`ipfs.object.patch.rmLink(multihash, DAGLink, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchrmlink) + - [`ipfs.object.patch.setData(multihash, data, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectpatchsetdata) + - [`ipfs.object.put(obj, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectput) + - [`ipfs.object.stat(multihash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/OBJECT.md#objectstat) - [pin](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md) - - [`ipfs.pin.add(hash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinadd) - - [`ipfs.pin.ls([hash], [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinls) - - [`ipfs.pin.rm(hash, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinrm) + - [`ipfs.pin.add(hash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinadd) + - [`ipfs.pin.ls([hash], [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinls) + - [`ipfs.pin.rm(hash, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PIN.md#pinrm) - refs - `ipfs.refs.local()` @@ -272,92 +284,101 @@ const ipfs = ipfsClient({ #### Network - [bootstrap](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md) - - [`ipfs.bootstrap.add(addr, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstrapadd) - - [`ipfs.bootstrap.list([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstraplist) - - [`ipfs.bootstrap.rm(addr, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstraprm) + - [`ipfs.bootstrap.add(addr, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstrapadd) + - [`ipfs.bootstrap.list()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstraplist) + - [`ipfs.bootstrap.rm(addr, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BOOTSTRAP.md#bootstraprm) - [bitswap](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BITSWAP.md) - - [`ipfs.bitswap.stat([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BITSWAP.md#bitswapstat) + - [`ipfs.bitswap.stat()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BITSWAP.md#bitswapstat) - [`ipfs.bitswap.wantlist([peerId])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BITSWAP.md#bitswapwantlist) - [`ipfs.bitswap.unwant(cid)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/BITSWAP.md#bitswapunwant) - [dht](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md) - - [`ipfs.dht.findPeer(peerId, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtfindpeer) - - [`ipfs.dht.findProvs(hash, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtfindprovs) - - [`ipfs.dht.get(key, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtget) - - [`ipfs.dht.provide(cid, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtprovide) - - [`ipfs.dht.put(key, value, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtput) + - [`ipfs.dht.findPeer(peerId)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtfindpeer) + - [`ipfs.dht.findProvs(hash)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtfindprovs) + - [`ipfs.dht.get(key)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtget) + - [`ipfs.dht.provide(cid)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtprovide) + - [`ipfs.dht.put(key, value)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/DHT.md#dhtput) - [pubsub](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md) - - [`ipfs.pubsub.ls(topic, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubls) - - [`ipfs.pubsub.peers(topic, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubpeers) - - [`ipfs.pubsub.publish(topic, data, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubpublish) - - [`ipfs.pubsub.subscribe(topic, handler, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubsubscribe) - - [`ipfs.pubsub.unsubscribe(topic, handler, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubunsubscribe) + - [`ipfs.pubsub.ls(topic)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubls) + - [`ipfs.pubsub.peers(topic)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubpeers) + - [`ipfs.pubsub.publish(topic, data)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubpublish) + - [`ipfs.pubsub.subscribe(topic, handler, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubsubscribe) + - [`ipfs.pubsub.unsubscribe(topic, handler)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md#pubsubunsubscribe) - [swarm](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md) - - [`ipfs.swarm.addrs([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmaddrs) - - [`ipfs.swarm.connect(addr, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmconnect) - - [`ipfs.swarm.disconnect(addr, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmdisconnect) - - [`ipfs.swarm.peers([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmpeers) + - [`ipfs.swarm.addrs()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmaddrs) + - [`ipfs.swarm.connect(addr)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmconnect) + - [`ipfs.swarm.disconnect(addr)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmdisconnect) + - [`ipfs.swarm.peers([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/SWARM.md#swarmpeers) - [name](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md) - - [`ipfs.name.publish(addr, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepublish) - - [`ipfs.name.pubsub.cancel(arg, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubcancel) - - [`ipfs.name.pubsub.state([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubstate) - - [`ipfs.name.pubsub.subs([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubsubs) - - [`ipfs.name.resolve(addr, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#nameresolve) + - [`ipfs.name.publish(addr, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepublish) + - [`ipfs.name.pubsub.cancel(arg)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubcancel) + - [`ipfs.name.pubsub.state()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubstate) + - [`ipfs.name.pubsub.subs()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#namepubsubsubs) + - [`ipfs.name.resolve(addr, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/NAME.md#nameresolve) #### Node Management - [miscellaneous operations](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md) - - [`ipfs.dns(domain, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#dns) - - [`ipfs.id([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#id) - - [`ipfs.ping(id, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#ping) + - [`ipfs.dns(domain)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#dns) + - [`ipfs.id()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#id) + - [`ipfs.ping(id, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#ping) - [`ipfs.pingPullStream(id, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#pingpullstream) - [`ipfs.pingReadableStream(id, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#pingreadablestream) - - [`ipfs.stop([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#stop). Alias to `ipfs.shutdown`. - - [`ipfs.version([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#version) + - [`ipfs.stop()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#stop). Alias to `ipfs.shutdown`. + - [`ipfs.version()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/MISCELLANEOUS.md#version) - [config](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md) - - [`ipfs.config.get([key], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configget) - - [`ipfs.config.replace(config, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configreplace) - - [`ipfs.config.set(key, value, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configset) - - [`ipfs.config.profiles.list([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configprofileslist) - - [`ipfs.config.profiles.apply(name, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configprofilesapply) + - [`ipfs.config.get([key])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configget) + - [`ipfs.config.replace(config)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configreplace) + - [`ipfs.config.set(key, value)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configset) + - [`ipfs.config.profiles.list()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configprofileslist) + - [`ipfs.config.profiles.apply(name, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/CONFIG.md#configprofilesapply) - [stats](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md) - - [`ipfs.stats.bitswap([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbitswap) - - [`ipfs.stats.bw([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbw) + - [`ipfs.stats.bitswap()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbitswap) + - [`ipfs.stats.bw([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbw) - [`ipfs.stats.bwPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbwpullstream) - [`ipfs.stats.bwReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsbwreadablestream) - - [`ipfs.stats.repo([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsrepo) + - [`ipfs.stats.repo([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/STATS.md#statsrepo) - log - - `ipfs.log.level(subsystem, level, [options], [callback])` - - `ipfs.log.ls([callback])` - - `ipfs.log.tail([callback])` + - `ipfs.log.level(subsystem, level, [options])` + - `ipfs.log.ls()` + - `ipfs.log.tail()` - [repo](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md) - - [`ipfs.repo.gc([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repogc) - - [`ipfs.repo.stat([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repostat) - - [`ipfs.repo.version([callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repoversion) + - [`ipfs.repo.gc([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repogc) + - [`ipfs.repo.stat([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repostat) + - [`ipfs.repo.version()`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md#repoversion) - [key](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md) - - [`ipfs.key.export(name, password, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyexport) - - [`ipfs.key.gen(name, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keygen) - - [`ipfs.key.import(name, pem, password, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyimport) - - [`ipfs.key.list([options, callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keylist) - - [`ipfs.key.rename(oldName, newName, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyrename) - - [`ipfs.key.rm(name, [callback])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyrm) + - [`ipfs.key.export(name, password)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyexport) + - [`ipfs.key.gen(name, [options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keygen) + - [`ipfs.key.import(name, pem, password)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyimport) + - [`ipfs.key.list([options])`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keylist) + - [`ipfs.key.rename(oldName, newName)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyrename) + - [`ipfs.key.rm(name)`](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/KEY.md#keyrm) + +#### Additional Options + +All core API methods take _additional_ `options` specific to the HTTP API: + +* `headers` - An object or [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) instance that can be used to set custom HTTP headers. Note that this option can also be [configured globally](#custom-headers) via the constructor options. +* `signal` - An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that can be used to abort the request on demand. +* `timeout` - A number or string specifying a timeout for the request. If the timeout is reached before data is received a [`TimeoutError`](https://github.com/sindresorhus/ky/blob/2f37c3f999efb36db9108893b8b3d4b3a7f5ec45/index.js#L127-L132) is thrown. If a number is specified it is interpreted as milliseconds, if a string is passed, it is intepreted according to [`parse-duration`](https://www.npmjs.com/package/parse-duration). Note that this option can also be [configured globally](#global-timeouts) via the constructor options. +* `searchParams` - An object or [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) instance that can be used to add additional query parameters to the query string sent with each request. -#### Instance utils +#### Instance Utils - `ipfs.getEndpointConfig()` Call this on your client instance to return an object containing the `host`, `port`, `protocol` and `api-path`. -#### Static types and utils +#### Static Types and Utils Aside from the default export, `ipfs-http-client` exports various types and utilities that are included in the bundle: diff --git a/package.json b/package.json index 4b305550a..8fc450b79 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,6 @@ }, "dependencies": { "abort-controller": "^3.0.0", - "async": "^2.6.1", "async-iterator-all": "^1.0.0", "async-iterator-to-pull-stream": "^1.3.0", "bignumber.js": "^9.0.0", @@ -51,58 +50,47 @@ "buffer": "^5.4.2", "callbackify": "^1.1.0", "cids": "~0.7.1", - "concat-stream": "github:hugomrdias/concat-stream#feat/smaller", "debug": "^4.1.0", - "detect-node": "^2.0.4", "err-code": "^2.0.0", "explain-error": "^1.0.4", - "flatmap": "0.0.3", "form-data": "^3.0.0", - "glob": "^7.1.3", "ipfs-block": "~0.8.1", "ipfs-utils": "^0.4.0", "ipld-dag-cbor": "~0.15.0", "ipld-dag-pb": "^0.18.1", "ipld-raw": "^4.0.0", "is-ipfs": "~0.6.1", - "is-pull-stream": "0.0.0", - "is-stream": "^2.0.0", - "iso-stream-http": "~0.1.2", "it-glob": "0.0.6", - "it-tar": "^1.1.0", + "it-tar": "^1.1.1", "it-to-stream": "^0.1.1", "iterable-ndjson": "^1.1.0", - "kind-of": "^6.0.2", "ky": "^0.15.0", "ky-universal": "^0.3.0", "merge-options": "^2.0.0", "multiaddr": "^6.0.6", + "multiaddr-to-uri": "^5.0.0", "multibase": "~0.6.0", "multicodec": "~0.5.1", "multihashes": "~0.4.14", - "ndjson": "github:hugomrdias/ndjson#feat/readable-stream3", - "once": "^1.4.0", "parse-duration": "^0.1.1", "peer-id": "~0.12.3", "peer-info": "~0.15.1", - "promise-nodeify": "^3.0.1", - "promisify-es6": "^1.0.3", - "pull-defer": "~0.2.3", - "pull-stream": "^3.6.9", - "pull-to-stream": "~0.1.1", - "pump": "^3.0.0", - "qs": "^6.5.2", - "readable-stream": "^3.1.1", - "stream-to-pull-stream": "^1.7.2" + "promise-nodeify": "^3.0.1" }, "devDependencies": { "aegir": "^20.4.1", + "async": "^3.1.0", "browser-process-platform": "~0.1.1", "cross-env": "^6.0.0", + "detect-node": "^2.0.4", "go-ipfs-dep": "^0.4.22", - "interface-ipfs-core": "^0.120.0", + "interface-ipfs-core": "^0.121.0", "ipfsd-ctl": "^0.47.1", + "ndjson": "^1.5.0", "nock": "^11.4.0", + "promisify-es6": "^1.0.3", + "pull-stream": "^3.6.14", + "pump": "^3.0.0", "stream-equal": "^1.1.1" }, "engines": { diff --git a/src/add-from-url.js b/src/add-from-url.js index 388072984..deb3f4bad 100644 --- a/src/add-from-url.js +++ b/src/add-from-url.js @@ -6,7 +6,7 @@ const toIterable = require('./lib/stream-to-iterable') module.exports = (config) => { const add = require('./add')(config) - return (url, options) => (async function * () { + return async function * addFromURL (url, options) { options = options || {} const { body } = await kyDefault.get(url) @@ -17,5 +17,5 @@ module.exports = (config) => { } yield * add(input, options) - })() + } } diff --git a/src/add/index.js b/src/add/index.js index 8b8ba7690..b1a8bb2a1 100644 --- a/src/add/index.js +++ b/src/add/index.js @@ -7,7 +7,7 @@ const { toFormData } = require('./form-data') const toCamel = require('../lib/object-to-camel') module.exports = configure(({ ky }) => { - return (input, options) => (async function * () { + return async function * add (input, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) @@ -47,7 +47,7 @@ module.exports = configure(({ ky }) => { yield toCoreInterface(file) } } - })() + } }) function toCoreInterface ({ name, hash, size }) { diff --git a/src/bitswap/stat.js b/src/bitswap/stat.js index 3795327bb..fee13c355 100644 --- a/src/bitswap/stat.js +++ b/src/bitswap/stat.js @@ -7,7 +7,7 @@ module.exports = configure(({ ky }) => { return async (options) => { options = options || {} - const res = await ky.get('bitswap/stat', { + const res = await ky.post('bitswap/stat', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/bitswap/unwant.js b/src/bitswap/unwant.js index 9b2044d00..a66653d69 100644 --- a/src/bitswap/unwant.js +++ b/src/bitswap/unwant.js @@ -15,7 +15,7 @@ module.exports = configure(({ ky }) => { searchParams.set('arg', new CID(cid).toString()) } - const res = await ky.get('bitswap/unwant', { + const res = await ky.post('bitswap/unwant', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/bitswap/wantlist.js b/src/bitswap/wantlist.js index 3235de8a9..6b087db1b 100644 --- a/src/bitswap/wantlist.js +++ b/src/bitswap/wantlist.js @@ -17,7 +17,7 @@ module.exports = configure(({ ky }) => { } } - const res = await ky.get('bitswap/wantlist', { + const res = await ky.post('bitswap/wantlist', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/block/get.js b/src/block/get.js index 6e28643f3..b53b38f64 100644 --- a/src/block/get.js +++ b/src/block/get.js @@ -13,7 +13,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${cid}`) - const data = await ky.get('block/get', { + const data = await ky.post('block/get', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/block/rm-async-iterator.js b/src/block/rm-async-iterator.js index b934df32b..e44aedcd2 100644 --- a/src/block/rm-async-iterator.js +++ b/src/block/rm-async-iterator.js @@ -7,7 +7,7 @@ const toIterable = require('../lib/stream-to-iterable') const toCamel = require('../lib/object-to-camel') module.exports = configure(({ ky }) => { - return async function * removeBlock (cid, options) { + return async function * rm (cid, options) { options = options || {} if (!Array.isArray(cid)) { diff --git a/src/block/stat.js b/src/block/stat.js index 4d0b82787..9063d137c 100644 --- a/src/block/stat.js +++ b/src/block/stat.js @@ -16,7 +16,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${cid}`) - const res = await ky.get('block/stat', { + const res = await ky.post('block/stat', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/bootstrap/list.js b/src/bootstrap/list.js index 2a20f5d05..2a6bbef4b 100644 --- a/src/bootstrap/list.js +++ b/src/bootstrap/list.js @@ -6,7 +6,7 @@ module.exports = configure(({ ky }) => { return async (options) => { options = options || {} - const res = await ky.get('bootstrap/list', { + const res = await ky.post('bootstrap/list', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/cat.js b/src/cat.js index 496257e84..32bccf59e 100644 --- a/src/cat.js +++ b/src/cat.js @@ -6,7 +6,7 @@ const configure = require('./lib/configure') const toIterable = require('./lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return (path, options) => (async function * () { + return async function * cat (path, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) @@ -20,7 +20,7 @@ module.exports = configure(({ ky }) => { if (options.offset) searchParams.set('offset', options.offset) if (options.length) searchParams.set('length', options.length) - const res = await ky.get('cat', { + const res = await ky.post('cat', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -30,5 +30,5 @@ module.exports = configure(({ ky }) => { for await (const chunk of toIterable(res.body)) { yield Buffer.from(chunk) } - })() + } }) diff --git a/src/commands.js b/src/commands.js index 8327e103a..4f8463fe9 100644 --- a/src/commands.js +++ b/src/commands.js @@ -1,14 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') - -module.exports = (arg) => { - const send = moduleConfig(arg) - - return promisify((callback) => { - send({ - path: 'commands' - }, callback) - }) -} +const configure = require('./lib/configure') + +module.exports = configure(({ ky }) => { + return options => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + if (options.flags != null) searchParams.set('flags', options.flags) + + return ky.post('commands', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + } +}) diff --git a/src/config/get.js b/src/config/get.js index b8a42a2e3..e4a7b5c2d 100644 --- a/src/config/get.js +++ b/src/config/get.js @@ -15,7 +15,7 @@ module.exports = configure(({ ky }) => { if (key) searchParams.set('arg', key) const url = key ? 'config' : 'config/show' - const data = await ky.get(url, { + const data = await ky.post(url, { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/config/profiles/list.js b/src/config/profiles/list.js index 1e3f44308..0261070bf 100644 --- a/src/config/profiles/list.js +++ b/src/config/profiles/list.js @@ -7,7 +7,7 @@ module.exports = configure(({ ky }) => { return async (options) => { options = options || {} - const res = await ky.get('config/profile/list', { + const res = await ky.post('config/profile/list', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/dag/resolve.js b/src/dag/resolve.js index f0a83d69d..cb7014a41 100644 --- a/src/dag/resolve.js +++ b/src/dag/resolve.js @@ -19,7 +19,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', cidPath) - const res = await ky.get('dag/resolve', { + const res = await ky.post('dag/resolve', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/dht/find-peer.js b/src/dht/find-peer.js index 953e9fc78..71779952c 100644 --- a/src/dht/find-peer.js +++ b/src/dht/find-peer.js @@ -8,14 +8,14 @@ const configure = require('../lib/configure') const toIterable = require('../lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return (peerId, options) => (async function * () { + return async function * findPeer (peerId, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${peerId}`) if (options.verbose != null) searchParams.set('verbose', options.verbose) - const res = await ky.get('dht/findpeer', { + const res = await ky.post('dht/findpeer', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -33,5 +33,5 @@ module.exports = configure(({ ky }) => { } } } - })() + } }) diff --git a/src/dht/find-provs.js b/src/dht/find-provs.js index b04d001d8..a0fc35722 100644 --- a/src/dht/find-provs.js +++ b/src/dht/find-provs.js @@ -8,7 +8,7 @@ const configure = require('../lib/configure') const toIterable = require('../lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return (cid, options) => (async function * () { + return async function * findProvs (cid, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) @@ -16,7 +16,7 @@ module.exports = configure(({ ky }) => { if (options.numProviders) searchParams.set('num-providers', options.numProviders) if (options.verbose != null) searchParams.set('verbose', options.verbose) - const res = await ky.get('dht/findprovs', { + const res = await ky.post('dht/findprovs', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -34,5 +34,5 @@ module.exports = configure(({ ky }) => { } } } - })() + } }) diff --git a/src/dht/get.js b/src/dht/get.js index 8a7b8c6a3..d2cd0db22 100644 --- a/src/dht/get.js +++ b/src/dht/get.js @@ -5,14 +5,14 @@ const configure = require('../lib/configure') const toIterable = require('../lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return (key, options) => (async function * () { + return async function * get (key, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${key}`) if (options.verbose != null) searchParams.set('verbose', options.verbose) - const res = await ky.get('dht/get', { + const res = await ky.post('dht/get', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -26,5 +26,5 @@ module.exports = configure(({ ky }) => { yield message.Extra } } - })() + } }) diff --git a/src/dht/provide.js b/src/dht/provide.js index 1f05710ec..cb72f9c6d 100644 --- a/src/dht/provide.js +++ b/src/dht/provide.js @@ -9,7 +9,7 @@ const toIterable = require('../lib/stream-to-iterable') const toCamel = require('../lib/object-to-camel') module.exports = configure(({ ky }) => { - return (cids, options) => (async function * () { + return async function * provide (cids, options) { cids = Array.isArray(cids) ? cids : [cids] options = options || {} @@ -18,7 +18,7 @@ module.exports = configure(({ ky }) => { if (options.recursive != null) searchParams.set('recursive', options.recursive) if (options.verbose != null) searchParams.set('verbose', options.verbose) - const res = await ky.get('dht/provide', { + const res = await ky.post('dht/provide', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -36,5 +36,5 @@ module.exports = configure(({ ky }) => { } yield message } - })() + } }) diff --git a/src/dht/put.js b/src/dht/put.js index 50137e528..49a6947aa 100644 --- a/src/dht/put.js +++ b/src/dht/put.js @@ -10,7 +10,7 @@ const encodeBufferURIComponent = require('../lib/encode-buffer-uri-component') const toCamel = require('../lib/object-to-camel') module.exports = configure(({ ky }) => { - return (key, value, options) => (async function * () { + return async function * put (key, value, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) @@ -20,7 +20,7 @@ module.exports = configure(({ ky }) => { value = Buffer.isBuffer(value) ? encodeBufferURIComponent(value) : encodeURIComponent(value) const url = `dht/put?arg=${key}&arg=${value}&${searchParams}` - const res = await ky.get(url, { + const res = await ky.post(url, { timeout: options.timeout, signal: options.signal, headers: options.headers @@ -37,5 +37,5 @@ module.exports = configure(({ ky }) => { } yield message } - })() + } }) diff --git a/src/dht/query.js b/src/dht/query.js index 8ebca71f7..5aefaf90d 100644 --- a/src/dht/query.js +++ b/src/dht/query.js @@ -7,14 +7,14 @@ const configure = require('../lib/configure') const toIterable = require('../lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return (peerId, options) => (async function * () { + return async function * query (peerId, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${peerId}`) if (options.verbose != null) searchParams.set('verbose', options.verbose) - const res = await ky.get('dht/query', { + const res = await ky.post('dht/query', { timeout: options.timeout, signal: options.signal, headers: options.headers, @@ -24,5 +24,5 @@ module.exports = configure(({ ky }) => { for await (const message of ndjson(toIterable(res.body))) { yield new PeerInfo(PeerId.createFromB58String(message.ID)) } - })() + } }) diff --git a/src/diag/cmds.js b/src/diag/cmds.js index 68f20ca04..88bb728ef 100644 --- a/src/diag/cmds.js +++ b/src/diag/cmds.js @@ -9,7 +9,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) if (options.verbose != null) searchParams.set('verbose', options.verbose) - return ky.get('diag/cmds', { + return ky.post('diag/cmds', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/diag/net.js b/src/diag/net.js index a7404b802..71b971ba7 100644 --- a/src/diag/net.js +++ b/src/diag/net.js @@ -6,7 +6,7 @@ module.exports = configure(({ ky }) => { return options => { options = options || {} - return ky.get('diag/net', { + return ky.post('diag/net', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/diag/sys.js b/src/diag/sys.js index a8cd91b6f..768d13d4d 100644 --- a/src/diag/sys.js +++ b/src/diag/sys.js @@ -6,7 +6,7 @@ module.exports = configure(({ ky }) => { return options => { options = options || {} - return ky.get('diag/sys', { + return ky.post('diag/sys', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/dns.js b/src/dns.js index 3f734bfc2..5032e3fb5 100644 --- a/src/dns.js +++ b/src/dns.js @@ -1,25 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') -const transform = function (res, callback) { - callback(null, res.Path) -} +module.exports = configure(({ ky }) => { + return async (domain, options) => { + options = options || {} -module.exports = (arg) => { - const send = moduleConfig(arg) + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', domain) + if (options.recursive != null) searchParams.set('recursive', options.recursive) - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('dns', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send.andTransform({ - path: 'dns', - args: args, - qs: opts - }, transform, callback) - }) -} + return res.Path + } +}) diff --git a/src/get-endpoint-config.js b/src/get-endpoint-config.js index a4f0c80e1..cf7125e70 100644 --- a/src/get-endpoint-config.js +++ b/src/get-endpoint-config.js @@ -1,10 +1,13 @@ 'use strict' -module.exports = (config) => { +const configure = require('./lib/configure') + +module.exports = configure(({ apiAddr, apiPath }) => { + const url = new URL(apiAddr) return () => ({ - host: config.host, - port: config.port, - protocol: config.protocol, - 'api-path': config['api-path'] + host: url.hostname, + port: url.port, + protocol: url.protocol.split(':')[0], // remove ":" + 'api-path': apiPath }) -} +}) diff --git a/src/get.js b/src/get.js index c06fc6d36..1a5ebfd93 100644 --- a/src/get.js +++ b/src/get.js @@ -2,24 +2,16 @@ const configure = require('./lib/configure') const Tar = require('it-tar') -const IsIpfs = require('is-ipfs') +const { Buffer } = require('buffer') +const CID = require('cids') const toIterable = require('./lib/stream-to-iterable') -const cleanCID = require('./utils/clean-cid') module.exports = configure(({ ky }) => { return async function * get (path, options) { options = options || {} - try { - path = cleanCID(path) - } catch (err) { - if (!IsIpfs.ipfsPath(path)) { - throw err - } - } - const searchParams = new URLSearchParams() - searchParams.set('arg', path.toString()) + searchParams.set('arg', `${Buffer.isBuffer(path) ? new CID(path) : path}`) if (options.compress !== undefined) { searchParams.set('compress', options.compress) @@ -37,7 +29,7 @@ module.exports = configure(({ ky }) => { searchParams.set('length', options.length) } - const res = await ky.get('get', { + const res = await ky.post('get', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/id.js b/src/id.js index b98be8443..d6080ea67 100644 --- a/src/id.js +++ b/src/id.js @@ -1,32 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') +const toCamel = require('./lib/object-to-camel') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} - return promisify((opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = undefined - } + const res = await ky.post('id', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - send({ - path: 'id', - args: opts - }, (err, result) => { - if (err) { - return callback(err) - } - const identity = { - id: result.ID, - publicKey: result.PublicKey, - addresses: result.Addresses, - agentVersion: result.AgentVersion, - protocolVersion: result.ProtocolVersion - } - callback(null, identity) - }) - }) -} + return toCamel(res) + } +}) diff --git a/src/index.js b/src/index.js index bd58a66f1..d9dc89630 100644 --- a/src/index.js +++ b/src/index.js @@ -1,5 +1,4 @@ 'use strict' -/* global self */ const isIPFS = require('is-ipfs') const { Buffer } = require('buffer') @@ -10,67 +9,151 @@ const multicodec = require('multicodec') const multihash = require('multihashes') const PeerId = require('peer-id') const PeerInfo = require('peer-info') -const loadCommands = require('./utils/load-commands') -const getConfig = require('./utils/default-config') -const sendRequest = require('./utils/send-request') +const nodeify = require('promise-nodeify') +const callbackify = require('callbackify') +const all = require('async-iterator-all') +const toPullStream = require('async-iterator-to-pull-stream') +const toStream = require('it-to-stream') +const BufferList = require('bl/BufferList') +const { concatify, collectify, pullify, streamify } = require('./lib/converters') -function ipfsClient (hostOrMultiaddr, port, userOptions) { - // convert all three params to objects that we can merge. - let options = {} +function ipfsClient (config) { + const add = require('./add')(config) + const addFromFs = require('./add-from-fs')(config) + const addFromURL = require('./add-from-url')(config) + const cat = require('./cat')(config) + const get = require('./get')(config) + const ls = require('./ls')(config) + const ping = require('./ping')(config) + const refs = require('./refs')(config) - if (!hostOrMultiaddr) { - // autoconfigure host and port in browser - if (typeof self !== 'undefined') { - options = urlToOptions(self.location) - } - } else if (multiaddr.isMultiaddr(hostOrMultiaddr)) { - options = maToOptions(hostOrMultiaddr) - } else if (typeof hostOrMultiaddr === 'object') { - options = hostOrMultiaddr - } else if (typeof hostOrMultiaddr === 'string') { - if (hostOrMultiaddr[0] === '/') { - // throws if multiaddr is malformed or can't be converted to a nodeAddress - options = maToOptions(multiaddr(hostOrMultiaddr)) - } else { - // hostOrMultiaddr is domain or ip address as a string - options.host = hostOrMultiaddr - } - } + const api = { + add: (input, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(add)(input, options), callback) + }, + addReadableStream: streamify.transform(add), + addPullStream: pullify.transform(add), + addFromFs: (path, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(addFromFs)(path, options), callback) + }, + addFromURL: (url, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(addFromURL)(url, options), callback) + }, + addFromStream: (input, options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + return nodeify(collectify(add)(input, options), callback) + }, + _addAsyncIterator: add, + bitswap: require('./bitswap')(config), + block: require('./block')(config), + bootstrap: require('./bootstrap')(config), + cat: callbackify.variadic((path, options) => concatify(cat)(path, options)), + catReadableStream: streamify.readable(cat), + catPullStream: pullify.source(cat), + _catAsyncIterator: cat, + commands: callbackify.variadic(require('./commands')(config)), + config: require('./config')(config), + dag: require('./dag')(config), + dht: require('./dht')(config), + diag: require('./diag')(config), + dns: callbackify.variadic(require('./dns')(config)), + files: require('./files')(config), + get: callbackify.variadic(async (path, options) => { + const output = [] - if (port && typeof port !== 'object') { - port = { port: port } - } + for await (const entry of get(path, options)) { + if (entry.content) { + entry.content = new BufferList(await all(entry.content)).slice() + } - const config = Object.assign(getConfig(), options, port, userOptions) - const requestAPI = sendRequest(config) - const cmds = loadCommands(requestAPI, config) - cmds.send = requestAPI + output.push(entry) + } - return cmds -} + return output + }), + getEndpointConfig: require('./get-endpoint-config')(config), + getReadableStream: streamify.readable(async function * (path, options) { + for await (const file of get(path, options)) { + if (file.content) { + const { content } = file + file.content = toStream((async function * () { + for await (const chunk of content) { + yield chunk.slice() // Convert bl to Buffer + } + })()) + } -function maToOptions (multiaddr) { - // ma.nodeAddress() throws if multiaddr can't be converted to a nodeAddress - const nodeAddr = multiaddr.nodeAddress() - const protos = multiaddr.protos() - // only http and https are allowed as protocol, - // anything else will be replaced with http - const exitProtocol = protos[protos.length - 1].name - return { - host: nodeAddr.address, - port: nodeAddr.port, - protocol: exitProtocol.startsWith('http') ? exitProtocol : 'http' - } -} + yield file + } + }), + getPullStream: pullify.source(async function * (path, options) { + for await (const file of get(path, options)) { + if (file.content) { + const { content } = file + file.content = toPullStream((async function * () { + for await (const chunk of content) { + yield chunk.slice() // Convert bl to Buffer + } + })()) + } -function urlToOptions (url) { - return { - host: url.hostname, - port: url.port || (url.protocol.startsWith('https') ? 443 : 80), - protocol: url.protocol.startsWith('http') ? url.protocol.split(':')[0] : 'http' + yield file + } + }), + _getAsyncIterator: get, + id: callbackify.variadic(require('./id')(config)), + key: require('./key')(config), + log: require('./log')(config), + ls: callbackify.variadic((path, options) => collectify(ls)(path, options)), + lsReadableStream: streamify.readable(ls), + lsPullStream: pullify.source(ls), + _lsAsyncIterator: ls, + mount: callbackify.variadic(require('./mount')(config)), + name: require('./name')(config), + object: require('./object')(config), + pin: require('./pin')(config), + ping: callbackify.variadic(collectify(ping)), + pingReadableStream: streamify.readable(ping), + pingPullStream: pullify.source(ping), + pubsub: require('./pubsub')(config), + refs: callbackify.variadic((path, options) => collectify(refs)(path, options)), + refsReadableStream: streamify.readable(refs), + refsPullStream: pullify.source(refs), + _refsAsyncIterator: refs, + repo: require('./repo')(config), + resolve: callbackify.variadic(require('./resolve')(config)), + stats: require('./stats')(config), + stop: callbackify.variadic(require('./stop')(config)), + shutdown: callbackify.variadic(require('./stop')(config)), + swarm: require('./swarm')(config), + version: callbackify.variadic(require('./version')(config)) } + + Object.assign(api.refs, { + local: callbackify.variadic(options => collectify(refs.local)(options)), + localReadableStream: streamify.readable(refs.local), + localPullStream: pullify.source(refs.local), + _localAsyncIterator: refs.local + }) + + return api } -module.exports = ipfsClient +Object.assign(ipfsClient, { isIPFS, Buffer, CID, multiaddr, multibase, multicodec, multihash, PeerId, PeerInfo }) -Object.assign(module.exports, { isIPFS, Buffer, CID, multiaddr, multibase, multicodec, multihash, PeerId, PeerInfo }) +module.exports = ipfsClient diff --git a/src/key/export.js b/src/key/export.js index f19db4022..b5f315580 100644 --- a/src/key/export.js +++ b/src/key/export.js @@ -1,16 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((name, password, callback) => { - send({ - path: 'key/export', - args: name, - qs: { password: password } - }, (err, pem) => { - if (err) return callback(err) - callback(null, pem.toString()) - }) - }) -} +module.exports = configure(({ ky }) => { + return (name, password, options) => { + if (typeof password !== 'string') { + options = password + password = null + } + + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', name) + if (password) searchParams.set('password', password) + + return ky.post('key/export', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).text() + } +}) diff --git a/src/key/gen.js b/src/key/gen.js index 38612d9af..5fd6acb86 100644 --- a/src/key/gen.js +++ b/src/key/gen.js @@ -1,25 +1,24 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - id: res.Id, - name: res.Name - }) -} +module.exports = configure(({ ky }) => { + return async (name, options) => { + options = options || {} -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', name) + if (options.type) searchParams.set('type', options.type) + if (options.size != null) searchParams.set('size', options.size) - send.andTransform({ - path: 'key/gen', - args: args, - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('key/gen', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/key/import.js b/src/key/import.js index 9cea80e27..7cc8f5ddc 100644 --- a/src/key/import.js +++ b/src/key/import.js @@ -1,23 +1,29 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - id: res.Id, - name: res.Name - }) -} +module.exports = configure(({ ky }) => { + return async (name, pem, password, options) => { + if (typeof password !== 'string') { + options = password + password = null + } -module.exports = (send) => { - return promisify((name, pem, password, callback) => { - send.andTransform({ - path: 'key/import', - args: name, - qs: { - pem: pem, - password: password - } - }, transform, callback) - }) -} + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', name) + searchParams.set('pem', pem) + if (password) searchParams.set('password', password) + + const res = await ky.post('key/import', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/key/index.js b/src/key/index.js index 717d719c3..7293236f1 100644 --- a/src/key/index.js +++ b/src/key/index.js @@ -1,16 +1,12 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - gen: require('./gen')(send), - list: require('./list')(send), - rename: require('./rename')(send), - rm: require('./rm')(send), - export: require('./export')(send), - import: require('./import')(send) - } -} +module.exports = config => ({ + gen: callbackify.variadic(require('./gen')(config)), + list: callbackify.variadic(require('./list')(config)), + rename: callbackify.variadic(require('./rename')(config)), + rm: callbackify.variadic(require('./rm')(config)), + export: callbackify.variadic(require('./export')(config)), + import: callbackify.variadic(require('./import')(config)) +}) diff --git a/src/key/list.js b/src/key/list.js index bcd9bc8e2..80e5069aa 100644 --- a/src/key/list.js +++ b/src/key/list.js @@ -1,26 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, res.Keys.map(key => { - return { - id: key.Id, - name: key.Name - } - })) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('key/list', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - send.andTransform({ - path: 'key/list', - qs: opts - }, transform, callback) - }) -} + return (res.Keys || []).map(k => toCamel(k)) + } +}) diff --git a/src/key/rename.js b/src/key/rename.js index 68b45f010..18e069768 100644 --- a/src/key/rename.js +++ b/src/key/rename.js @@ -1,21 +1,24 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - id: res.Id, - was: res.Was, - now: res.Now, - overwrite: res.Overwrite - }) -} +module.exports = configure(({ ky }) => { + return async (oldName, newName, options) => { + options = options || {} -module.exports = (send) => { - return promisify((oldName, newName, callback) => { - send.andTransform({ - path: 'key/rename', - args: [oldName, newName] - }, transform, callback) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', oldName) + searchParams.append('arg', newName) + if (options.force != null) searchParams.set('force', options.force) + + const res = await ky.post('key/rename', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/key/rm.js b/src/key/rm.js index 7e4e98500..edab61060 100644 --- a/src/key/rm.js +++ b/src/key/rm.js @@ -1,19 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - id: res.Keys[0].Id, - name: res.Keys[0].Name - }) -} +module.exports = configure(({ ky }) => { + return async (name, options) => { + options = options || {} -module.exports = (send) => { - return promisify((args, callback) => { - send.andTransform({ - path: 'key/rm', - args: args - }, transform, callback) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', name) + + const res = await ky.post('key/rm', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res.Keys[0]) + } +}) diff --git a/src/lib/configure.js b/src/lib/configure.js index b1a1f8948..9e6c9465f 100644 --- a/src/lib/configure.js +++ b/src/lib/configure.js @@ -3,7 +3,7 @@ const ky = require('ky-universal').default const { isBrowser, isWebWorker } = require('ipfs-utils/src/env') -const { toUri } = require('./multiaddr') +const toUri = require('multiaddr-to-uri') const errorHandler = require('./error-handler') const mergeOptions = require('merge-options').bind({ ignoreUndefined: true }) const parseDuration = require('parse-duration') @@ -22,10 +22,17 @@ module.exports = create => config => { config.apiAddr = (config.apiAddr || getDefaultApiAddr(config)).toString() config.apiAddr = config.apiAddr.startsWith('/') ? toUri(config.apiAddr) : config.apiAddr - config.apiPath = config.apiPath || config['api-path'] || '/api/v0' + config.apiAddr = trimEnd(config.apiAddr, '/') + + const apiAddrPath = getNonRootPath(config.apiAddr) + + // Use configured apiPath, or path on the end of apiAddr (if there is one) or default to /api/v0 + config.apiPath = config.apiPath || config['api-path'] || apiAddrPath || '/api/v0' + config.apiPath = trimEnd(config.apiPath, '/') + + // If user passed apiAddr with a path, trim it from the end (it is now apiPath) + config.apiAddr = apiAddrPath ? trimEnd(config.apiAddr, apiAddrPath) : config.apiAddr - // TODO configure ky to use config.fetch when this is released: - // https://github.com/sindresorhus/ky/pull/153 const defaults = { prefixUrl: config.apiAddr + config.apiPath, timeout: parseTimeout(config.timeout) || 60000 * 20, @@ -50,13 +57,9 @@ module.exports = create => config => { function getDefaultApiAddr ({ protocol, host, port }) { if (isBrowser || isWebWorker) { - if (!protocol && !host && !port) { // Use current origin - return '' - } - if (!protocol) { protocol = location.protocol.startsWith('http') - ? location.protocol.split(':')[0] + ? trimEnd(location.protocol, ':') : 'http' } @@ -81,3 +84,13 @@ function wrap (fn, defaults) { function parseTimeout (value) { return typeof value === 'string' ? parseDuration(value) : value } + +const trimEnd = (str, end) => str.endsWith(end) ? str.slice(0, -end.length) : str + +// Get the path from a URL is it is not / +function getNonRootPath (url) { + if (url) { + const { pathname } = new URL(url) + return pathname === '/' ? null : pathname + } +} diff --git a/src/lib/multiaddr.js b/src/lib/multiaddr.js deleted file mode 100644 index 09462ab34..000000000 --- a/src/lib/multiaddr.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' - -// Convert a multiaddr to a URI -// Assumes multiaddr is in a format that can be converted to a HTTP(s) URI -exports.toUri = ma => { - const parts = `${ma}`.split('/') - const port = getPort(parts) - return `${getProtocol(parts)}://${parts[2]}${port == null ? '' : ':' + port}` -} - -function getProtocol (maParts) { - return maParts.indexOf('https') === -1 ? 'http' : 'https' -} - -function getPort (maParts) { - const tcpIndex = maParts.indexOf('tcp') - return tcpIndex === -1 ? null : maParts[tcpIndex + 1] -} diff --git a/src/log/index.js b/src/log/index.js index 94597bdc6..f7d94f910 100644 --- a/src/log/index.js +++ b/src/log/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - tail: require('./tail')(send), - ls: require('./ls')(send), - level: require('./level')(send) - } -} +module.exports = config => ({ + tail: require('./tail')(config), + ls: callbackify.variadic(require('./ls')(config)), + level: callbackify.variadic(require('./level')(config)) +}) diff --git a/src/log/level.js b/src/log/level.js index 4304ff90f..dcc20c7bd 100644 --- a/src/log/level.js +++ b/src/log/level.js @@ -1,27 +1,23 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -module.exports = (send) => { - return promisify((subsystem, level, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - if (typeof subsystem !== 'string') { - return callback(new Error('Invalid subsystem type')) - } +module.exports = configure(({ ky }) => { + return async (subsystem, level, options) => { + options = options || {} - if (typeof level !== 'string') { - return callback(new Error('Invalid level type')) - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', subsystem) + searchParams.append('arg', level) - send({ - path: 'log/level', - args: [subsystem, level], - qs: opts, - files: undefined, - buffer: true - }, callback) - }) -} + const res = await ky.post('log/level', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/log/ls.js b/src/log/ls.js index ab243605b..0a8d69c6c 100644 --- a/src/log/ls.js +++ b/src/log/ls.js @@ -1,17 +1,18 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((callback) => { - send({ - path: 'log/ls' - }, (err, result) => { - if (err) { - return callback(err) - } +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} - callback(null, result.Strings) - }) - }) -} + const res = await ky.post('log/ls', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() + + return res.Strings + } +}) diff --git a/src/log/tail.js b/src/log/tail.js index bad4e4d34..00708e9b9 100644 --- a/src/log/tail.js +++ b/src/log/tail.js @@ -1,20 +1,20 @@ 'use strict' -const promisify = require('promisify-es6') -const pump = require('pump') -const ndjson = require('ndjson') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -module.exports = (send) => { - return promisify((callback) => { - return send({ - path: 'log/tail' - }, (err, response) => { - if (err) { - return callback(err) - } - const outputStream = ndjson.parse() - pump(response, outputStream) - callback(null, outputStream) +module.exports = configure(({ ky }) => { + return async function * tail (options) { + options = options || {} + + const res = await ky.post('log/tail', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams }) - }) -} + + yield * ndjson(toIterable(res.body)) + } +}) diff --git a/src/ls.js b/src/ls.js index fc9921963..a9cd476f9 100644 --- a/src/ls.js +++ b/src/ls.js @@ -1,23 +1,15 @@ 'use strict' -const IsIpfs = require('is-ipfs') -const cleanCID = require('./utils/clean-cid') +const { Buffer } = require('buffer') +const CID = require('cids') const configure = require('./lib/configure') module.exports = configure(({ ky }) => { return async function * ls (path, options) { options = options || {} - try { - path = cleanCID(path) - } catch (err) { - if (!IsIpfs.ipfsPath(path)) { - throw err - } - } - const searchParams = new URLSearchParams() - searchParams.set('arg', path.toString()) + searchParams.set('arg', `${Buffer.isBuffer(path) ? new CID(path) : path}`) if (options.long !== undefined) { searchParams.set('long', options.long) @@ -31,7 +23,7 @@ module.exports = configure(({ ky }) => { searchParams.set('recursive', options.recursive) } - const res = await ky.get('ls', { + const res = await ky.post('ls', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/mount.js b/src/mount.js index 7c2e92cab..a5d2faef1 100644 --- a/src/mount.js +++ b/src/mount.js @@ -1,30 +1,23 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') +const toCamel = require('./lib/object-to-camel') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} - return promisify((ipfs, ipns, callback) => { - if (typeof ipfs === 'function') { - callback = ipfs - ipfs = null - } else if (typeof ipns === 'function') { - callback = ipns - ipns = null - } - const opts = {} - if (ipfs) { - opts.f = ipfs - } - if (ipns) { - opts.n = ipns - } + const searchParams = new URLSearchParams(options.searchParams) + if (options.ipfsPath != null) searchParams.set('ipfs-path', options.ipfsPath) + if (options.ipnsPath != null) searchParams.set('ipns-path', options.ipnsPath) - send({ - path: 'mount', - qs: opts - }, callback) - }) -} + const res = await ky.post('dns', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/name/index.js b/src/name/index.js index 8f823311a..7a6837b82 100644 --- a/src/name/index.js +++ b/src/name/index.js @@ -1,13 +1,9 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - publish: require('./publish')(send), - resolve: require('./resolve')(send), - pubsub: require('./pubsub')(send) - } -} +module.exports = config => ({ + publish: callbackify.variadic(require('./publish')(config)), + resolve: callbackify.variadic(require('./resolve')(config)), + pubsub: require('./pubsub')(config) +}) diff --git a/src/name/publish.js b/src/name/publish.js index cfc7482e3..e470606f9 100644 --- a/src/name/publish.js +++ b/src/name/publish.js @@ -1,25 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') +const toCamel = require('../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - name: res.Name, - value: res.Value - }) -} +module.exports = configure(({ ky }) => { + return async (path, options) => { + options = options || {} -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', path) + if (options.allowOffline != null) searchParams.set('allow-offline', options.allowOffline) + if (options.key) searchParams.set('key', options.key) + if (options.lifetime) searchParams.set('lifetime', options.lifetime) + if (options.quieter != null) searchParams.set('quieter', options.quieter) + if (options.resolve != null) searchParams.set('resolve', options.resolve) + if (options.ttl) searchParams.set('ttl', options.ttl) - send.andTransform({ - path: 'name/publish', - args: args, - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('name/publish', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/name/pubsub/cancel.js b/src/name/pubsub/cancel.js index 32dbbb3af..ea5391e64 100644 --- a/src/name/pubsub/cancel.js +++ b/src/name/pubsub/cancel.js @@ -1,24 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../../lib/configure') +const toCamel = require('../../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - canceled: res.Canceled === undefined || res.Canceled === true - }) -} +module.exports = configure(({ ky }) => { + return async (name, options) => { + options = options || {} -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', name) - send.andTransform({ - path: 'name/pubsub/cancel', - args: args, - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('name/pubsub/cancel', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return toCamel(res) + } +}) diff --git a/src/name/pubsub/index.js b/src/name/pubsub/index.js index aefc0f880..70db19874 100644 --- a/src/name/pubsub/index.js +++ b/src/name/pubsub/index.js @@ -1,7 +1,9 @@ 'use strict' -module.exports = (send) => ({ - cancel: require('./cancel')(send), - state: require('./state')(send), - subs: require('./subs')(send) +const callbackify = require('callbackify') + +module.exports = config => ({ + cancel: callbackify.variadic(require('./cancel')(config)), + state: callbackify.variadic(require('./state')(config)), + subs: callbackify.variadic(require('./subs')(config)) }) diff --git a/src/name/pubsub/state.js b/src/name/pubsub/state.js index cc9b0b369..03e18aa7f 100644 --- a/src/name/pubsub/state.js +++ b/src/name/pubsub/state.js @@ -1,23 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../../lib/configure') +const toCamel = require('../../lib/object-to-camel') -const transform = function (res, callback) { - callback(null, { - enabled: res.Enabled - }) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('name/pubsub/state', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - send.andTransform({ - path: 'name/pubsub/state', - qs: opts - }, transform, callback) - }) -} + return toCamel(res) + } +}) diff --git a/src/name/pubsub/subs.js b/src/name/pubsub/subs.js index 3a3a54c2a..9bc6c2208 100644 --- a/src/name/pubsub/subs.js +++ b/src/name/pubsub/subs.js @@ -1,21 +1,18 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../../lib/configure') -const transform = function (res, callback) { - callback(null, res.Strings || []) -} +module.exports = configure(({ ky }) => { + return async (name, options) => { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('name/pubsub/subs', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - send.andTransform({ - path: 'name/pubsub/subs', - qs: opts - }, transform, callback) - }) -} + return res.Strings || [] + } +}) diff --git a/src/name/resolve.js b/src/name/resolve.js index addb567d6..b6e8db47e 100644 --- a/src/name/resolve.js +++ b/src/name/resolve.js @@ -1,22 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -const transform = function (res, callback) { - callback(null, res.Path) -} +module.exports = configure(({ ky }) => { + return async (path, options) => { + options = options || {} -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', path) + if (options.dhtRecordCount != null) searchParams.set('dht-record-count', options.dhtRecordCount) + if (options.dhtTimeout != null) searchParams.set('dht-timeout', options.dhtTimeout) + if (options.noCache != null) searchParams.set('nocache', options.noCache) + if (options.recursive != null) searchParams.set('recursive', options.recursive) - send.andTransform({ - path: 'name/resolve', - args: args, - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('name/resolve', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res.Path + } +}) diff --git a/src/object/data.js b/src/object/data.js index 8f1e42b7a..48291f722 100644 --- a/src/object/data.js +++ b/src/object/data.js @@ -6,13 +6,13 @@ const configure = require('../lib/configure') const toIterable = require('../lib/stream-to-iterable') module.exports = configure(({ ky }) => { - return async function * (cid, options) { + return async function * data (cid, options) { options = options || {} const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) - const res = await ky.get('object/data', { + const res = await ky.post('object/data', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/object/get.js b/src/object/get.js index 5ed7468dc..8dd2b638d 100644 --- a/src/object/get.js +++ b/src/object/get.js @@ -13,7 +13,7 @@ module.exports = configure(({ ky }) => { searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) searchParams.set('data-encoding', 'base64') - const res = await ky.get('object/get', { + const res = await ky.post('object/get', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/object/links.js b/src/object/links.js index 49b088254..f05ddb630 100644 --- a/src/object/links.js +++ b/src/object/links.js @@ -12,7 +12,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', `${Buffer.isBuffer(cid) ? new CID(cid) : cid}`) - const res = await ky.get('object/links', { + const res = await ky.post('object/links', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/pin/ls.js b/src/pin/ls.js index bf1746d63..cd1cc07f1 100644 --- a/src/pin/ls.js +++ b/src/pin/ls.js @@ -15,7 +15,7 @@ module.exports = configure(({ ky }) => { if (path) searchParams.set('arg', `${path}`) if (options.type) searchParams.set('type', options.type) - const { Keys } = await ky.get('pin/ls', { + const { Keys } = await ky.post('pin/ls', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/ping-pull-stream.js b/src/ping-pull-stream.js deleted file mode 100644 index a7871faa3..000000000 --- a/src/ping-pull-stream.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const toPull = require('stream-to-pull-stream') -const deferred = require('pull-defer') -const pump = require('pump') -const moduleConfig = require('./utils/module-config') -const PingMessageStream = require('./utils/ping-message-stream') - -module.exports = (arg) => { - const send = moduleConfig(arg) - - return (id, opts = {}) => { - // Default number of packtes to 1 - if (!opts.n && !opts.count) { - opts.n = 1 - } - const request = { - path: 'ping', - args: id, - qs: opts - } - const p = deferred.source() - const response = new PingMessageStream() - - send(request, (err, stream) => { - if (err) { return p.abort(err) } - - pump(stream, response) - p.resolve(toPull.source(response)) - }) - - return p - } -} diff --git a/src/ping-readable-stream.js b/src/ping-readable-stream.js deleted file mode 100644 index df4f70401..000000000 --- a/src/ping-readable-stream.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict' - -const pump = require('pump') -const moduleConfig = require('./utils/module-config') -const PingMessageStream = require('./utils/ping-message-stream') - -module.exports = (arg) => { - const send = moduleConfig(arg) - - return (id, opts = {}) => { - // Default number of packtes to 1 - if (!opts.n && !opts.count) { - opts.n = 1 - } - const request = { - path: 'ping', - args: id, - qs: opts - } - - const response = new PingMessageStream() - - send(request, (err, stream) => { - if (err) { return response.emit('error', err) } - pump(stream, response) - }) - - return response - } -} diff --git a/src/ping.js b/src/ping.js index f3ff63ec8..33b275617 100644 --- a/src/ping.js +++ b/src/ping.js @@ -1,60 +1,27 @@ 'use strict' -const promisify = require('promisify-es6') -const pump = require('pump') -const Writable = require('readable-stream').Writable -const moduleConfig = require('./utils/module-config') -const PingMessageStream = require('./utils/ping-message-stream') - -module.exports = (arg) => { - const send = moduleConfig(arg) - - return promisify((id, opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } - - if (opts.n && opts.count) { - return callback(new Error('Use either n or count, not both')) - } - - // Default number of packtes to 1 - if (!opts.n && !opts.count) { - opts.n = 1 +const ndjson = require('iterable-ndjson') +const configure = require('./lib/configure') +const toIterable = require('./lib/stream-to-iterable') +const toCamel = require('./lib/object-to-camel') + +module.exports = configure(({ ky }) => { + return async function * ping (peerId, options) { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${peerId}`) + if (options.count != null) searchParams.set('count', options.count) + + const res = await ky.post('ping', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) + + for await (const chunk of ndjson(toIterable(res.body))) { + yield toCamel(chunk) } - - const request = { - path: 'ping', - args: id, - qs: opts - } - - // Transform the response stream to a value: - // [{ success: , time: , text: }] - const transform = (stream, callback) => { - const messageConverter = new PingMessageStream() - const responses = [] - - pump( - stream, - messageConverter, - new Writable({ - objectMode: true, - write (chunk, enc, cb) { - responses.push(chunk) - cb() - } - }), - (err) => { - if (err) { - return callback(err) - } - callback(null, responses) - } - ) - } - - send.andTransform(request, transform, callback) - }) -} + } +}) diff --git a/src/pubsub/ls.js b/src/pubsub/ls.js index 177dcd491..d2bc8f68d 100644 --- a/src/pubsub/ls.js +++ b/src/pubsub/ls.js @@ -6,7 +6,7 @@ module.exports = configure(({ ky }) => { return async (options) => { options = options || {} - const { Strings } = await ky.get('pubsub/ls', { + const { Strings } = await ky.post('pubsub/ls', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/pubsub/peers.js b/src/pubsub/peers.js index bdeca60e4..5fa5b2436 100644 --- a/src/pubsub/peers.js +++ b/src/pubsub/peers.js @@ -14,7 +14,7 @@ module.exports = configure(({ ky }) => { const searchParams = new URLSearchParams(options.searchParams) searchParams.set('arg', topic) - const { Strings } = await ky.get('pubsub/peers', { + const { Strings } = await ky.post('pubsub/peers', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/refs/index.js b/src/refs/index.js index d86944eb2..b15f2cd0c 100644 --- a/src/refs/index.js +++ b/src/refs/index.js @@ -1,8 +1,8 @@ 'use strict' const configure = require('../lib/configure') -const cleanCID = require('../utils/clean-cid') -const IsIpfs = require('is-ipfs') +const { Buffer } = require('buffer') +const CID = require('cids') const ndjson = require('iterable-ndjson') const toIterable = require('../lib/stream-to-iterable') const toCamel = require('../lib/object-to-camel') @@ -38,19 +38,11 @@ module.exports = config => { args = [args] } - for (let arg of args) { - try { - arg = cleanCID(arg) - } catch (err) { - if (!IsIpfs.ipfsPath(arg)) { - throw err - } - } - - searchParams.append('arg', arg.toString()) + for (const arg of args) { + searchParams.append('arg', `${Buffer.isBuffer(arg) ? new CID(arg) : arg}`) } - const res = await ky.get('refs', { + const res = await ky.post('refs', { timeout: options.timeout, signal: options.signal, headers: options.headers, diff --git a/src/refs/local.js b/src/refs/local.js index efb8d32d2..afa1630ea 100644 --- a/src/refs/local.js +++ b/src/refs/local.js @@ -9,7 +9,7 @@ module.exports = configure(({ ky }) => { return async function * refsLocal (options) { options = options || {} - const res = await ky.get('refs/local', { + const res = await ky.post('refs/local', { timeout: options.timeout, signal: options.signal, headers: options.headers diff --git a/src/repo/gc.js b/src/repo/gc.js index 35d4288b0..3d92dee4c 100644 --- a/src/repo/gc.js +++ b/src/repo/gc.js @@ -1,33 +1,29 @@ 'use strict' -const promisify = require('promisify-es6') -const streamToValueWithTransformer = require('../utils/stream-to-value-with-transformer') const CID = require('cids') +const ndjson = require('iterable-ndjson') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -const transform = function (res, callback) { - callback(null, res.map(r => ({ - err: r.Err ? new Error(r.Err) : null, - cid: (r.Key || {})['/'] ? new CID(r.Key['/']) : null - }))) -} +module.exports = configure(({ ky }) => { + return async function * gc (peerId, options) { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - - const request = { - path: 'repo/gc', - qs: opts - } - send(request, (err, result) => { - if (err) { - return callback(err) - } + const searchParams = new URLSearchParams(options.searchParams) + if (options.streamErrors) searchParams.set('stream-errors', options.streamErrors) - streamToValueWithTransformer(result, transform, callback) + const res = await ky.post('repo/gc', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams }) - }) -} + + for await (const gcResult of ndjson(toIterable(res.body))) { + yield { + err: gcResult.Error ? new Error(gcResult.Error) : null, + cid: (gcResult.Key || {})['/'] ? new CID(gcResult.Key['/']) : null + } + } + } +}) diff --git a/src/repo/index.js b/src/repo/index.js index d3ac72785..fe58504ad 100644 --- a/src/repo/index.js +++ b/src/repo/index.js @@ -1,13 +1,10 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') +const { collectify } = require('../lib/converters') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - gc: require('./gc')(send), - stat: require('./stat')(send), - version: require('./version')(send) - } -} +module.exports = config => ({ + gc: callbackify.variadic(collectify(require('./gc')(config))), + stat: callbackify.variadic(require('./stat')(config)), + version: callbackify.variadic(require('./version')(config)) +}) diff --git a/src/repo/stat.js b/src/repo/stat.js index 2b922de03..17895e353 100644 --- a/src/repo/stat.js +++ b/src/repo/stat.js @@ -1,28 +1,28 @@ 'use strict' -const promisify = require('promisify-es6') const Big = require('bignumber.js') +const configure = require('../lib/configure') -const transform = function (res, callback) { - callback(null, { - numObjects: new Big(res.NumObjects), - repoSize: new Big(res.RepoSize), - repoPath: res.RepoPath, - version: res.Version, - storageMax: new Big(res.StorageMax) - }) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + if (options.sizeOnly) searchParams.set('size-only', options.sizeOnly) + + const res = await ky.post('repo/stat', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() - send.andTransform({ - path: 'repo/stat', - qs: opts - }, transform, callback) - }) -} + return { + numObjects: new Big(res.NumObjects), + repoSize: new Big(res.RepoSize), + repoPath: res.RepoPath, + version: res.Version, + storageMax: new Big(res.StorageMax) + } + } +}) diff --git a/src/repo/version.js b/src/repo/version.js index 84e2a0008..1bfc708e0 100644 --- a/src/repo/version.js +++ b/src/repo/version.js @@ -1,21 +1,21 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -const transform = function (res, callback) { - callback(null, res.Version) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const searchParams = new URLSearchParams(options.searchParams) + if (options.sizeOnly) searchParams.set('size-only', options.sizeOnly) - send.andTransform({ - path: 'repo/version', - qs: opts - }, transform, callback) - }) -} + const res = await ky.post('repo/version', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res.Version + } +}) diff --git a/src/resolve.js b/src/resolve.js index f48a3b02b..33c44b6e6 100644 --- a/src/resolve.js +++ b/src/resolve.js @@ -1,54 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') -const multibase = require('multibase') -const CID = require('cids') - -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - - opts = opts || {} - - if (opts.cidBase) { - opts['cid-base'] = opts.cidBase - delete opts.cidBase - } - - const transform = (res, callback) => { - if (!opts['cid-base']) { - return callback(null, res.Path) - } - - // FIXME: remove when go-ipfs supports ?cid-base for /api/v0/resolve - // https://github.com/ipfs/go-ipfs/pull/5777#issuecomment-439838555 - const parts = res.Path.split('/') // ['', 'ipfs', 'QmHash', ...] - - if (multibase.isEncoded(parts[2]) !== opts['cid-base']) { - try { - let cid = new CID(parts[2]) - - if (cid.version === 0 && opts['cid-base'] !== 'base58btc') { - cid = cid.toV1() - } - - parts[2] = cid.toBaseEncodedString(opts['cid-base']) - res.Path = parts.join('/') - } catch (err) { - return callback(err) - } - } - - callback(null, res.Path) - } - - send.andTransform({ - path: 'resolve', - args: args, - qs: opts - }, transform, callback) - }) -} +const configure = require('./lib/configure') + +module.exports = configure(({ ky }) => { + return async (path, options) => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + searchParams.set('arg', `${path}`) + if (options.cidBase) searchParams.set('cid-base', options.cidBase) + if (options.dhtRecordCount) searchParams.set('dht-record-count', options.dhtRecordCount) + if (options.dhtTimeout) searchParams.set('dht-timeout', options.dhtTimeout) + if (options.recursive != null) searchParams.set('recursive', options.recursive) + + const res = await ky.post('resolve', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res.Path + } +}) diff --git a/src/stats/bitswap.js b/src/stats/bitswap.js deleted file mode 100644 index 3f641f680..000000000 --- a/src/stats/bitswap.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const Big = require('bignumber.js') - -const transform = function (res, callback) { - callback(null, { - provideBufLen: res.ProvideBufLen, - wantlist: res.Wantlist || [], - peers: res.Peers || [], - blocksReceived: new Big(res.BlocksReceived), - dataReceived: new Big(res.DataReceived), - blocksSent: new Big(res.BlocksSent), - dataSent: new Big(res.DataSent), - dupBlksReceived: new Big(res.DupBlksReceived), - dupDataReceived: new Big(res.DupDataReceived) - }) -} - -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - - send.andTransform({ - path: 'stats/bitswap', - qs: opts - }, transform, callback) - }) -} diff --git a/src/stats/bw-pull-stream.js b/src/stats/bw-pull-stream.js deleted file mode 100644 index 26a4eb311..000000000 --- a/src/stats/bw-pull-stream.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict' - -const toPull = require('stream-to-pull-stream') -const map = require('pull-stream/throughs/map') -const pull = require('pull-stream/pull') -const transformChunk = require('./bw-util') -const deferred = require('pull-defer') - -module.exports = (send) => { - return (opts) => { - opts = opts || {} - - const p = deferred.source() - - send({ - path: 'stats/bw', - qs: opts - }, (err, stream) => { - if (err) { - return p.end(err) - } - - p.resolve(pull( - toPull.source(stream), - map(transformChunk) - )) - }) - - return p - } -} diff --git a/src/stats/bw-readable-stream.js b/src/stats/bw-readable-stream.js deleted file mode 100644 index c36fea518..000000000 --- a/src/stats/bw-readable-stream.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict' - -const Stream = require('readable-stream') -const pump = require('pump') -const transformChunk = require('./bw-util') - -module.exports = (send) => { - return (opts) => { - opts = opts || {} - - const pt = new Stream.Transform({ - objectMode: true, - transform (chunk, encoding, cb) { - cb(null, transformChunk(chunk)) - } - }) - - send({ - path: 'stats/bw', - qs: opts - }, (err, stream) => { - if (err) { - return pt.destroy(err) - } - - pump(stream, pt) - }) - - return pt - } -} diff --git a/src/stats/bw-util.js b/src/stats/bw-util.js deleted file mode 100644 index 928ee0c3c..000000000 --- a/src/stats/bw-util.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const Big = require('bignumber.js') - -module.exports = (chunk) => { - return { - totalIn: new Big(chunk.TotalIn), - totalOut: new Big(chunk.TotalOut), - rateIn: new Big(chunk.RateIn), - rateOut: new Big(chunk.RateOut) - } -} diff --git a/src/stats/bw.js b/src/stats/bw.js index 1db636a25..f68ad23ba 100644 --- a/src/stats/bw.js +++ b/src/stats/bw.js @@ -1,29 +1,34 @@ 'use strict' -const promisify = require('promisify-es6') -const streamToValue = require('../utils/stream-to-value') -const transformChunk = require('./bw-util') +const ndjson = require('iterable-ndjson') +const Big = require('bignumber.js') +const configure = require('../lib/configure') +const toIterable = require('../lib/stream-to-iterable') -const transform = (res, callback) => { - return streamToValue(res, (err, data) => { - if (err) { - return callback(err) - } +module.exports = configure(({ ky }) => { + return async function * bw (options) { + options = options || {} - callback(null, transformChunk(data[0])) - }) -} + const searchParams = new URLSearchParams(options.searchParams) + if (options.interval) searchParams.set('interval', options.interval) + if (options.peer) searchParams.set('peer', options.peer) + if (options.poll != null) searchParams.set('poll', options.poll) + if (options.proto) searchParams.set('proto', options.proto) -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('stats/bw', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }) - send.andTransform({ - path: 'stats/bw', - qs: opts - }, transform, callback) - }) -} + for await (const stats of ndjson(toIterable(res.body))) { + yield { + totalIn: new Big(stats.TotalIn), + totalOut: new Big(stats.TotalOut), + rateIn: new Big(stats.RateIn), + rateOut: new Big(stats.RateOut) + } + } + } +}) diff --git a/src/stats/index.js b/src/stats/index.js index 445a39835..4351d79e2 100644 --- a/src/stats/index.js +++ b/src/stats/index.js @@ -1,15 +1,19 @@ 'use strict' -const moduleConfig = require('../utils/module-config') - -module.exports = (arg) => { - const send = moduleConfig(arg) +const callbackify = require('callbackify') +const { streamify, pullify } = require('../lib/converters') +module.exports = config => { + const bw = require('./bw')(config) return { - bitswap: require('./bitswap')(send), - bw: require('./bw')(send), - bwReadableStream: require('./bw-readable-stream')(send), - bwPullStream: require('./bw-pull-stream')(send), - repo: require('./repo')(send) + bitswap: callbackify.variadic(require('../bitswap/stat')(config)), + bw: callbackify.variadic(async options => { + for await (const stats of bw(options)) { + return stats + } + }), + bwReadableStream: streamify.readable(bw), + bwPullStream: pullify.source(bw), + repo: callbackify.variadic(require('../repo/stat')(config)) } } diff --git a/src/stats/repo.js b/src/stats/repo.js deleted file mode 100644 index 81f808951..000000000 --- a/src/stats/repo.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' - -const promisify = require('promisify-es6') -const Big = require('bignumber.js') - -const transform = function (res, callback) { - callback(null, { - numObjects: new Big(res.NumObjects), - repoSize: new Big(res.RepoSize), - repoPath: res.RepoPath, - version: res.Version, - storageMax: new Big(res.StorageMax) - }) -} - -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - - send.andTransform({ - path: 'stats/repo', - qs: opts - }, transform, callback) - }) -} diff --git a/src/stop.js b/src/stop.js index 0da69eaa1..7cae46880 100644 --- a/src/stop.js +++ b/src/stop.js @@ -1,12 +1,16 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = configure(({ ky }) => { + return options => { + options = options || {} - return promisify((callback) => { - send({ path: 'shutdown' }, callback) - }) -} + return ky.post('shutdown', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).text() + } +}) diff --git a/src/swarm/addrs.js b/src/swarm/addrs.js index 103df148b..a786d32cb 100644 --- a/src/swarm/addrs.js +++ b/src/swarm/addrs.js @@ -1,33 +1,25 @@ 'use strict' -const promisify = require('promisify-es6') const PeerInfo = require('peer-info') const PeerId = require('peer-id') const multiaddr = require('multiaddr') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'swarm/addrs', - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} - const peers = Object.keys(result.Addrs).map((id) => { - const peerInfo = new PeerInfo(PeerId.createFromB58String(id)) - result.Addrs[id].forEach((addr) => { - peerInfo.multiaddrs.add(multiaddr(addr)) - }) - return peerInfo - }) + const res = await ky.post('swarm/addrs', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - callback(null, peers) + return Object.keys(res.Addrs).map(id => { + const peerInfo = new PeerInfo(PeerId.createFromB58String(id)) + res.Addrs[id].forEach(addr => peerInfo.multiaddrs.add(multiaddr(addr))) + return peerInfo }) - }) -} + } +}) diff --git a/src/swarm/connect.js b/src/swarm/connect.js index 9875af411..f47ae6974 100644 --- a/src/swarm/connect.js +++ b/src/swarm/connect.js @@ -1,17 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'swarm/connect', - args: args, - qs: opts - }, callback) - }) -} +module.exports = configure(({ ky }) => { + return async (addrs, options) => { + addrs = Array.isArray(addrs) ? addrs : [addrs] + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + addrs.forEach(addr => searchParams.append('arg', addr)) + + const res = await ky.post('swarm/connect', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res.Strings || [] + } +}) diff --git a/src/swarm/disconnect.js b/src/swarm/disconnect.js index 84b800f7e..a3d60d172 100644 --- a/src/swarm/disconnect.js +++ b/src/swarm/disconnect.js @@ -1,17 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((args, opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'swarm/disconnect', - args: args, - qs: opts - }, callback) - }) -} +module.exports = configure(({ ky }) => { + return async (addrs, options) => { + addrs = Array.isArray(addrs) ? addrs : [addrs] + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + addrs.forEach(addr => searchParams.append('arg', addr)) + + const res = await ky.post('swarm/disconnect', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return res.Strings || [] + } +}) diff --git a/src/swarm/index.js b/src/swarm/index.js index fe8c88b35..e86a7c22c 100644 --- a/src/swarm/index.js +++ b/src/swarm/index.js @@ -1,15 +1,11 @@ 'use strict' -const moduleConfig = require('../utils/module-config') +const callbackify = require('callbackify') -module.exports = (arg) => { - const send = moduleConfig(arg) - - return { - peers: require('./peers')(send), - connect: require('./connect')(send), - disconnect: require('./disconnect')(send), - addrs: require('./addrs')(send), - localAddrs: require('./localAddrs')(send) - } -} +module.exports = config => ({ + addrs: callbackify.variadic(require('./addrs')(config)), + connect: callbackify.variadic(require('./connect')(config)), + disconnect: callbackify.variadic(require('./disconnect')(config)), + localAddrs: callbackify.variadic(require('./localAddrs')(config)), + peers: callbackify.variadic(require('./peers')(config)) +}) diff --git a/src/swarm/localAddrs.js b/src/swarm/localAddrs.js index 4798aad52..41c32db2d 100644 --- a/src/swarm/localAddrs.js +++ b/src/swarm/localAddrs.js @@ -1,24 +1,22 @@ 'use strict' -const promisify = require('promisify-es6') const multiaddr = require('multiaddr') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'swarm/addrs/local', - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } - callback(null, result.Strings.map((addr) => { - return multiaddr(addr) - })) - }) - }) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} + + const searchParams = new URLSearchParams(options.searchParams) + if (options.id != null) searchParams.append('id', options.id) + + const res = await ky.post('swarm/addrs/local', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() + + return (res.Strings || []).map(a => multiaddr(a)) + } +}) diff --git a/src/swarm/peers.js b/src/swarm/peers.js index 37d11cd7e..3b897348c 100644 --- a/src/swarm/peers.js +++ b/src/swarm/peers.js @@ -1,74 +1,48 @@ 'use strict' -const promisify = require('promisify-es6') const multiaddr = require('multiaddr') const PeerId = require('peer-id') +const configure = require('../lib/configure') -module.exports = (send) => { - return promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - const verbose = opts.v || opts.verbose - send({ - path: 'swarm/peers', - qs: opts - }, (err, response) => { - if (err) { - return callback(err) - } - const peerInfo = parsePeersResponse(verbose, response) - callback(null, peerInfo) - }) - }) -} +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} -function parsePeersResponse (verbose, response) { - // go-ipfs <= 0.4.4 - if (Array.isArray(response.Strings)) { - return response.Strings.map(parseLegacyPeer.bind(null, verbose)) - } - // go-ipfs >= 0.4.5 - if (Array.isArray(response.Peers)) { - return response.Peers.map(parsePeer.bind(null, verbose)) - } - return [] -} + const searchParams = new URLSearchParams(options.searchParams) + if (options.direction != null) searchParams.append('direction', options.direction) + if (options.latency != null) searchParams.append('latency', options.latency) + if (options.streams != null) searchParams.append('streams', options.streams) + if (options.verbose != null) searchParams.append('verbose', options.verbose) -function parseLegacyPeer (verbose, peer) { - const res = {} - try { - if (verbose) { - const parts = peer.split(' ') - res.addr = multiaddr(parts[0]) - res.latency = parts[1] - } else { - res.addr = multiaddr(peer) - } - res.peer = PeerId.createFromB58String(res.addr.getPeerId()) - } catch (error) { - res.error = error - res.rawPeerInfo = peer - } - return res -} + const res = await ky.post('swarm/peers', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams + }).json() -function parsePeer (verbose, peer) { - const res = {} - try { - res.addr = multiaddr(peer.Addr) - res.peer = PeerId.createFromB58String(peer.Peer) - res.muxer = peer.Muxer - } catch (error) { - res.error = error - res.rawPeerInfo = peer - } - if (peer.Latency) { - res.latency = peer.Latency - } - if (peer.Streams) { - res.streams = peer.Streams + return (res.Peers || []).map(peer => { + const info = {} + try { + info.addr = multiaddr(peer.Addr) + info.peer = PeerId.createFromB58String(peer.Peer) + } catch (error) { + info.error = error + info.rawPeerInfo = peer + } + if (peer.Muxer) { + info.muxer = peer.Muxer + } + if (peer.Latency) { + info.latency = peer.Latency + } + if (peer.Streams) { + info.streams = peer.Streams + } + if (peer.Direction != null) { + info.direction = peer.Direction + } + return info + }) } - return res -} +}) diff --git a/src/update.js b/src/update.js index aee1a64a6..91bea6f7f 100644 --- a/src/update.js +++ b/src/update.js @@ -1,41 +1,16 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = configure(({ ky }) => { + return options => { + options = options || {} - return { - apply: promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'update', - qs: opts - }, callback) - }), - check: promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'update/check', - qs: opts - }, callback) - }), - log: promisify((opts, callback) => { - if (typeof (opts) === 'function') { - callback = opts - opts = {} - } - send({ - path: 'update/log', - qs: opts - }, callback) - }) + return ky.post('update', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).text() } -} +}) diff --git a/src/utils/clean-cid.js b/src/utils/clean-cid.js deleted file mode 100644 index 1767c9ac2..000000000 --- a/src/utils/clean-cid.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict' - -const CID = require('cids') - -module.exports = function (cid) { - if (Buffer.isBuffer(cid)) { - return new CID(cid).toString() - } - if (CID.isCID(cid)) { - return cid.toString() - } - if (typeof cid !== 'string') { - throw new Error('unexpected cid type: ' + typeof cid) - } - new CID(cid.split('/')[0]) // eslint-disable-line no-new - return cid -} diff --git a/src/utils/clean-multihash.js b/src/utils/clean-multihash.js deleted file mode 100644 index 230135ad7..000000000 --- a/src/utils/clean-multihash.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict' - -const bs58 = require('bs58') -const CID = require('cids') -const isIPFS = require('is-ipfs') - -module.exports = function (multihash) { - if (Buffer.isBuffer(multihash)) { - multihash = bs58.encode(multihash) - } - if (CID.isCID(multihash)) { - multihash = multihash.toBaseEncodedString() - } - if (typeof multihash !== 'string') { - throw new Error('unexpected multihash type: ' + typeof multihash) - } - if (!isIPFS.multihash(multihash.split('/')[0])) { - throw new Error('not valid multihash') - } - return multihash -} diff --git a/src/utils/default-config.js b/src/utils/default-config.js deleted file mode 100644 index 5ae6ae82e..000000000 --- a/src/utils/default-config.js +++ /dev/null @@ -1,13 +0,0 @@ -'use strict' - -const pkg = require('../../package.json') - -exports = module.exports = () => { - return { - 'api-path': '/api/v0/', - 'user-agent': `/node-${pkg.name}/${pkg.version}/`, - host: 'localhost', - port: '5001', - protocol: 'http' - } -} diff --git a/src/utils/load-commands.js b/src/utils/load-commands.js deleted file mode 100644 index a4a6dcd07..000000000 --- a/src/utils/load-commands.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict' - -const nodeify = require('promise-nodeify') -const callbackify = require('callbackify') -const all = require('async-iterator-all') -const { concatify, collectify, pullify, streamify } = require('../lib/converters') -const toPullStream = require('async-iterator-to-pull-stream') -const pull = require('pull-stream/pull') -const map = require('pull-stream/throughs/map') -const toStream = require('it-to-stream') -const BufferList = require('bl/BufferList') - -function requireCommands (send, config) { - const add = require('../add')(config) - const addFromFs = require('../add-from-fs')(config) - const addFromURL = require('../add-from-url')(config) - const cat = require('../cat')(config) - const get = require('../get')(config) - const ls = require('../ls')(config) - const refs = require('../refs')(config) - - const cmds = { - add: (input, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(add)(input, options), callback) - }, - addReadableStream: streamify.transform(add), - addPullStream: pullify.transform(add), - addFromFs: (path, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(addFromFs)(path, options), callback) - }, - addFromURL: (url, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(addFromURL)(url, options), callback) - }, - addFromStream: (input, options, callback) => { - if (typeof options === 'function') { - callback = options - options = {} - } - return nodeify(collectify(add)(input, options), callback) - }, - _addAsyncIterator: add, - cat: callbackify.variadic((path, options) => concatify(cat)(path, options)), - catReadableStream: streamify.readable(cat), - catPullStream: pullify.source(cat), - _catAsyncIterator: cat, - get: callbackify.variadic(async (path, options) => { - const output = [] - - for await (const entry of get(path, options)) { - if (entry.content) { - entry.content = new BufferList(await all(entry.content)).slice() - } - - output.push(entry) - } - - return output - }), - getReadableStream: streamify.readable((path, options) => (async function * () { - for await (const file of get(path, options)) { - if (file.content) { - const { content } = file - file.content = toStream((async function * () { - for await (const chunk of content) { - yield chunk.slice() // Convert bl to Buffer - } - })()) - } - - yield file - } - })()), - getPullStream: (path, options) => { - return pull( - toPullStream(get(path, options)), - map(file => { - if (file.content) { - file.content = pull( - toPullStream(file.content), - map(chunk => chunk.slice()) // Convert bl to Buffer - ) - } - - return file - }) - ) - }, - _getAsyncIterator: get, - ls: callbackify.variadic((path, options) => collectify(ls)(path, options)), - lsReadableStream: streamify.readable(ls), - lsPullStream: pullify.source(ls), - _lsAsyncIterator: ls, - object: require('../object')(config), - refs: callbackify.variadic((path, options) => collectify(refs)(path, options)), - refsReadableStream: streamify.readable(refs), - refsPullStream: pullify.source(refs), - _refsAsyncIterator: refs, - getEndpointConfig: require('../get-endpoint-config')(config), - bitswap: require('../bitswap')(config), - block: require('../block')(config), - bootstrap: require('../bootstrap')(config), - config: require('../config')(config), - dag: require('../dag')(config), - dht: require('../dht')(config), - diag: require('../diag')(config), - files: require('../files')(config), - pin: require('../pin')(config) - } - - Object.assign(cmds.refs, { - local: callbackify.variadic(options => collectify(refs.local)(options)), - localReadableStream: streamify.readable(refs.local), - localPullStream: pullify.source(refs.local), - _localAsyncIterator: refs.local - }) - - const subCmds = { - // Network - name: require('../name'), - ping: require('../ping'), - pingReadableStream: require('../ping-readable-stream'), - pingPullStream: require('../ping-pull-stream'), - swarm: require('../swarm'), - pubsub: require('../pubsub'), - dns: require('../dns'), - - // Miscellaneous - commands: require('../commands'), - id: require('../id'), - key: require('../key'), - log: require('../log'), - mount: require('../mount'), - repo: require('../repo'), - stop: require('../stop'), - shutdown: require('../stop'), - stats: require('../stats'), - update: require('../update'), - version: require('../version'), - resolve: require('../resolve') - } - - Object.keys(subCmds).forEach((file) => { - cmds[file] = subCmds[file](send, config) - }) - - return cmds -} - -module.exports = requireCommands diff --git a/src/utils/module-config.js b/src/utils/module-config.js deleted file mode 100644 index 4e1b0e6a1..000000000 --- a/src/utils/module-config.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict' - -const getConfig = require('./default-config') -const sendRequest = require('./send-request') -const multiaddr = require('multiaddr') - -module.exports = (arg) => { - const config = getConfig() - - if (typeof arg === 'function') { - return arg - } else if (typeof arg === 'object') { - return sendRequest(arg) - } else if (typeof arg === 'string') { - const maddr = multiaddr(arg).nodeAddress() - config.host = maddr.address - config.port = maddr.port - return sendRequest(config) - } else { - throw new Error('Argument must be a send function or a config object.') - } -} diff --git a/src/utils/multipart.js b/src/utils/multipart.js deleted file mode 100644 index 78bead247..000000000 --- a/src/utils/multipart.js +++ /dev/null @@ -1,121 +0,0 @@ -'use strict' - -const Transform = require('readable-stream').Transform -const isNode = require('detect-node') - -const PADDING = '--' -const NEW_LINE = '\r\n' -const NEW_LINE_BUFFER = Buffer.from(NEW_LINE) - -class Multipart extends Transform { - constructor (options) { - super(Object.assign({}, options, { objectMode: true, highWaterMark: 1 })) - - this._boundary = this._generateBoundary() - this._files = [] - this._draining = false - } - - _flush () { - this.push(Buffer.from(PADDING + this._boundary + PADDING + NEW_LINE)) - this.push(null) - } - - _generateBoundary () { - var boundary = '--------------------------' - for (var i = 0; i < 24; i++) { - boundary += Math.floor(Math.random() * 10).toString(16) - } - - return boundary - } - - _transform (file, encoding, callback) { - if (Buffer.isBuffer(file)) { - this.push(file) - return callback() // early - } - // not a buffer, must be a file - this._files.push(file) - this._maybeDrain(callback) - } - - _maybeDrain (callback) { - if (!this._draining) { - if (this._files.length) { - this._draining = true - const file = this._files.shift() - this._pushFile(file, (err) => { - this._draining = false - if (err) { - this.emit('error', err) - } else { - this._maybeDrain(callback) - } - }) - } else { - this.emit('drained all files') - callback() - } - } else { - this.once('drained all files', callback) - } - } - - _pushFile (file, callback) { - const leading = this._leading(file.headers || {}) - - this.push(leading) - - const content = file.content || Buffer.alloc(0) - - if (Buffer.isBuffer(content)) { - this.push(content) - this.push(NEW_LINE_BUFFER) - return callback() // early - } - - // From now on we assume content is a stream - content.once('error', this.emit.bind(this, 'error')) - - content.once('end', () => { - this.push(NEW_LINE_BUFFER) - callback() - - // TODO: backpressure!!! wait once self is drained so we can proceed - // This does not work - // this.once('drain', () => { - // callback() - // }) - }) - - content.on('data', (data) => { - const drained = this.push(data) - // Only do the drain dance on Node.js. - // In browserland, the underlying stream - // does NOT drain because the request is only sent - // once this stream ends. - if (!drained && isNode) { - content.pause() - this.once('drain', () => content.resume()) - } - }) - } - - _leading (headers) { - var leading = [PADDING + this._boundary] - - Object.keys(headers).forEach((header) => { - leading.push(header + ': ' + headers[header]) - }) - - leading.push('') - leading.push('') - - const leadingStr = leading.join(NEW_LINE) - - return Buffer.from(leadingStr) - } -} - -module.exports = Multipart diff --git a/src/utils/ping-message-converter.js b/src/utils/ping-message-converter.js deleted file mode 100644 index 79d9fc3be..000000000 --- a/src/utils/ping-message-converter.js +++ /dev/null @@ -1,23 +0,0 @@ -'use strict' - -// Converts IPFS API ping messages to lowercase -// -// { -// Success: true, -// Text: 'foobar', -// Time: 0 -// } -// - -module.exports = function pingMessageConverter (obj) { - if (!isPingMessage(obj)) throw new Error('Invalid ping message received') - return { - success: obj.Success, - time: obj.Time, - text: obj.Text - } -} - -function isPingMessage (obj) { - return obj && typeof obj.Success === 'boolean' -} diff --git a/src/utils/ping-message-stream.js b/src/utils/ping-message-stream.js deleted file mode 100644 index 944e2d9cf..000000000 --- a/src/utils/ping-message-stream.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict' - -const TransformStream = require('readable-stream').Transform -const pingMessageConverter = require('./ping-message-converter') - -class PingMessageStream extends TransformStream { - constructor (options) { - const opts = Object.assign(options || {}, { objectMode: true }) - super(opts) - } - - _transform (obj, enc, callback) { - try { - const msg = pingMessageConverter(obj) - this.push(msg) - - if (!msg.success) { - throw new Error(msg.text) - } - } catch (err) { - return callback(err) - } - callback() - } -} - -module.exports = PingMessageStream diff --git a/src/utils/prepare-file.js b/src/utils/prepare-file.js deleted file mode 100644 index 9a02f8338..000000000 --- a/src/utils/prepare-file.js +++ /dev/null @@ -1,153 +0,0 @@ -'use strict' - -const isNode = require('detect-node') -const flatmap = require('flatmap') -const { Readable } = require('readable-stream') -const kindOf = require('kind-of') -const { isSource } = require('is-pull-stream') -const isStream = require('is-stream') -const pullToStream = require('pull-to-stream') -const { supportsFileReader } = require('ipfs-utils/src/supports') -const streamFromFileReader = require('ipfs-utils/src/streams/stream-from-filereader') - -function loadPaths (opts, file) { - const path = require('path') - const fs = require('fs') - const glob = require('glob') - - const followSymlinks = opts.followSymlinks != null ? opts.followSymlinks : true - - file = path.resolve(file) - const stats = fs.statSync(file) - - if (stats.isDirectory() && !opts.recursive) { - throw new Error('Can only add directories using --recursive') - } - - if (stats.isDirectory() && opts.recursive) { - // glob requires a POSIX filename - file = file.split(path.sep).join('/') - const fullDir = file + (file.endsWith('/') ? '' : '/') - let dirName = fullDir.split('/') - dirName = dirName[dirName.length - 2] + '/' - const mg = new glob.sync.GlobSync('**/*', { - cwd: file, - follow: followSymlinks, - dot: opts.hidden, - ignore: opts.ignore - }) - - return mg.found - .map((name) => { - const fqn = fullDir + name - // symlinks - if (mg.symlinks[fqn] === true) { - return { - path: dirName + name, - symlink: true, - dir: false, - content: fs.readlinkSync(fqn) - } - } - - // files - if (mg.cache[fqn] === 'FILE') { - return { - path: dirName + name, - symlink: false, - dir: false, - content: fs.createReadStream(fqn) - } - } - - // directories - if (mg.cache[fqn] === 'DIR' || mg.cache[fqn] instanceof Array) { - return { - path: dirName + name, - symlink: false, - dir: true - } - } - // files inside symlinks and others - }) - // filter out null files - .filter(Boolean) - } - - return { - path: path.basename(file), - content: fs.createReadStream(file) - } -} - -function contentToStream (content) { - if (supportsFileReader && kindOf(content) === 'file') { - return streamFromFileReader(content) - } - - if (kindOf(content) === 'buffer') { - return new Readable({ - read () { - this.push(content) - this.push(null) - } - }) - } - - if (isSource(content)) { - return pullToStream.readable(content) - } - - if (isStream.readable(content)) { - return content - } - - throw new Error(`Input not supported. Expected Buffer|ReadableStream|PullStream|File got ${kindOf(content)}. Check the documentation for more info https://github.com/ipfs/interface-js-ipfs-core/blob/master/SPEC/FILES.md#add`) -} - -function prepareFile (file, opts) { - const files = [].concat(file) - - return flatmap(files, (file) => { - // add from fs with file path - if (typeof file === 'string') { - if (!isNode) { - throw new Error('Can only add file paths in node') - } - - return loadPaths(opts, file) - } - - // add with object syntax { path : , content: {}) - } - - static fromStream (track, stream) { - const prog = new ProgressStream({ track }) - return stream.pipe(prog) - } - - _transform (chunk, encoding, callback) { - if (chunk && - typeof chunk.Bytes !== 'undefined' && - typeof chunk.Hash === 'undefined') { - this._track(chunk.Bytes) - return callback() - } - - callback(null, chunk) - } -} - -module.exports = ProgressStream diff --git a/src/utils/send-files-stream.js b/src/utils/send-files-stream.js deleted file mode 100644 index 09c55d376..000000000 --- a/src/utils/send-files-stream.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict' - -const { Duplex } = require('readable-stream') -const eachSeries = require('async/eachSeries') -const isStream = require('is-stream') -const once = require('once') -const prepareFile = require('./prepare-file') -const Multipart = require('./multipart') - -function headers (file, i) { - const filename = file.path - ? encodeURIComponent(file.path) - : '' - - const header = { 'Content-Disposition': `form-data; name="data${i}"; filename="${filename}"` } - - if (!file.content) { - header['Content-Type'] = 'application/x-directory' - } else if (file.symlink) { - header['Content-Type'] = 'application/symlink' - } else { - header['Content-Type'] = 'application/octet-stream' - } - - return header -} - -module.exports = (send, path) => { - return (options) => { - let ended = false - let writing = false - - options = options ? Object.assign({}, options, options.qs) : {} - - const multipart = new Multipart() - - const retStream = new Duplex({ objectMode: true }) - - retStream._read = (n) => {} - - retStream._write = (file, enc, _next) => { - const next = once(_next) - try { - const files = prepareFile(file, options) - .map((file, i) => Object.assign({ headers: headers(file, i) }, file)) - - writing = true - eachSeries( - files, - (file, cb) => multipart.write(file, enc, cb), - (err) => { - writing = false - if (err) { - return next(err) - } - if (ended) { - multipart.end() - } - next() - }) - } catch (err) { - next(err) - } - } - - retStream.once('finish', () => { - if (!ended) { - ended = true - if (!writing) { - multipart.end() - } - } - }) - - const qs = options.qs || {} - - qs['cid-version'] = propOrProp(options, 'cid-version', 'cidVersion') - qs['raw-leaves'] = propOrProp(options, 'raw-leaves', 'rawLeaves') - qs['only-hash'] = propOrProp(options, 'only-hash', 'onlyHash') - qs['wrap-with-directory'] = propOrProp(options, 'wrap-with-directory', 'wrapWithDirectory') - qs.pin = propOrProp(options, 'pin') - qs.preload = propOrProp(options, 'preload') - qs.hash = propOrProp(options, 'hash', 'hashAlg') - - if (options.strategy === 'trickle' || options.trickle) { - qs.trickle = 'true' - } - - const args = { - path: path, - qs: qs, - args: options.args, - multipart: true, - multipartBoundary: multipart._boundary, - stream: true, - recursive: true, - progress: options.progress - } - - multipart.on('error', (err) => { - retStream.emit('error', err) - }) - - const request = send(args, (err, response) => { - if (err) { - return retStream.emit('error', err) - } - - if (!response) { - // no response, which means everything is ok, so we end the retStream - return retStream.push(null) // early - } - - if (!isStream(response)) { - retStream.push(response) - retStream.push(null) - return - } - - response.on('error', (err) => retStream.emit('error', err)) - - if (options.converter) { - response.on('data', (d) => { - if (d.Bytes && options.progress) { - options.progress(d.Bytes) - } - }) - - const Converter = options.converter - const convertedResponse = new Converter() - convertedResponse.once('end', () => retStream.push(null)) - convertedResponse.on('data', (d) => retStream.push(d)) - response.pipe(convertedResponse) - } else { - response.on('data', (d) => { - if (d.Bytes && options.progress) { - options.progress(d.Bytes) - } - retStream.push(d) - }) - response.once('end', () => retStream.push(null)) - } - }) - - // signal the multipart that the underlying stream has drained and that - // it can continue producing data.. - request.on('drain', () => multipart.emit('drain')) - - multipart.pipe(request) - - return retStream - } -} - -function propOrProp (source, prop1, prop2) { - if (prop1 in source) { - return source[prop1] - } else if (prop2 in source) { - return source[prop2] - } -} diff --git a/src/utils/send-one-file-multiple-results.js b/src/utils/send-one-file-multiple-results.js deleted file mode 100644 index 180a9ad34..000000000 --- a/src/utils/send-one-file-multiple-results.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' - -const once = require('once') -const ConcatStream = require('concat-stream') -const SendFilesStream = require('./send-files-stream') - -module.exports = (send, path) => { - const sendFilesStream = SendFilesStream(send, path) - return (file, options, _callback) => { - const callback = once(_callback) - const stream = sendFilesStream(options) - const concat = ConcatStream((results) => callback(null, results)) - stream.once('error', callback) - stream.pipe(concat) - stream.write(file) - stream.end() - } -} diff --git a/src/utils/send-one-file.js b/src/utils/send-one-file.js deleted file mode 100644 index 7b510f19d..000000000 --- a/src/utils/send-one-file.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict' - -const SendOneFileMultipleResults = require('./send-one-file-multiple-results') - -module.exports = (send, path) => { - const sendFile = SendOneFileMultipleResults(send, path) - return (file, options, callback) => { - sendFile(file, options, (err, results) => { - if (err) { - return callback(err) - } - callback(null, results[0]) - }) - } -} diff --git a/src/utils/send-request.js b/src/utils/send-request.js deleted file mode 100644 index 1645969f2..000000000 --- a/src/utils/send-request.js +++ /dev/null @@ -1,239 +0,0 @@ -'use strict' - -const Qs = require('qs') -const qsDefaultEncoder = require('qs/lib/utils').encode -const isNode = require('detect-node') -const ndjson = require('ndjson') -const pump = require('pump') -const once = require('once') -const { getRequest } = require('iso-stream-http') -const streamToValue = require('./stream-to-value') -const streamToJsonValue = require('./stream-to-json-value') -const log = require('debug')('ipfs-http-client:request') - -// -- Internal - -function hasJSONHeaders (res) { - return res.headers['content-type'] && - res.headers['content-type'].indexOf('application/json') === 0 -} - -function parseError (res, cb) { - const error = new Error(`Server responded with ${res.statusCode}`) - error.statusCode = res.statusCode - - if (!hasJSONHeaders(res)) { - return streamToValue(res, (err, data) => { // eslint-disable-line handle-callback-err - // the `err` here refers to errors in stream processing, which - // we ignore here, since we already have a valid `error` response - // from the server above that we have to report to the caller. - if (data && data.length) { - error.message = data.toString() - } - cb(error) - }) - } - - streamToJsonValue(res, (err, payload) => { - if (err) { - return cb(err) - } - - if (payload) { - error.code = payload.Code - error.message = payload.Message || payload.toString() - error.type = payload.Type - } - cb(error) - }) -} - -function onRes (buffer, cb) { - return (res) => { - const stream = Boolean(res.headers['x-stream-output']) - const chunkedObjects = Boolean(res.headers['x-chunked-output']) - const isJson = hasJSONHeaders(res) - - if (res.req) { - log(res.req.method, `${res.req.getHeaders().host}${res.req.path}`, res.statusCode, res.statusMessage) - } else { - log(res.url, res.statusCode, res.statusMessage) - } - - if (res.statusCode >= 400 || !res.statusCode) { - return parseError(res, cb) - } - - // Return the response stream directly - if (stream && !buffer) { - return cb(null, res) - } - - // Return a stream of JSON objects - if (chunkedObjects && isJson) { - const outputStream = ndjson.parse() - pump(res, outputStream) - res.on('end', () => { - let err = res.trailers['x-stream-error'] - if (err) { - // Not all errors are JSON - try { - err = JSON.parse(err) - } catch (e) { - err = { Message: err } - } - outputStream.emit('error', new Error(err.Message)) - } - }) - return cb(null, outputStream) - } - - // Return a JSON object - if (isJson) { - return streamToJsonValue(res, cb) - } - - // Return a value - return streamToValue(res, cb) - } -} - -function requestAPI (config, options, callback) { - callback = once(callback) - options.qs = options.qs || {} - - if (Array.isArray(options.path)) { - options.path = options.path.join('/') - } - if (options.args && !Array.isArray(options.args)) { - options.args = [options.args] - } - if (options.args) { - options.qs.arg = options.args - } - if (options.progress) { - options.qs.progress = true - } - - if (options.qs.r) { - options.qs.recursive = options.qs.r - // From IPFS 0.4.0, it throws an error when both r and recursive are passed - delete options.qs.r - } - - options.qs['stream-channels'] = true - - if (options.stream) { - options.buffer = false - } - - // this option is only used internally, not passed to daemon - delete options.qs.followSymlinks - - const method = 'POST' - const headers = Object.assign({}, config.headers) - - if (isNode) { - // Browsers do not allow you to modify the user agent - headers['User-Agent'] = config['user-agent'] - } - - if (options.multipart) { - if (!options.multipartBoundary) { - return callback(new Error('No multipartBoundary')) - } - - headers['Content-Type'] = `multipart/form-data; boundary=${options.multipartBoundary}` - } - - const qs = Qs.stringify(options.qs, { - arrayFormat: 'repeat', - encoder: data => { - // TODO: future releases of qs will provide the default - // encoder as a 2nd argument to this function; it will - // no longer be necessary to import qsDefaultEncoder - if (Buffer.isBuffer(data)) { - let uriEncoded = '' - for (const byte of data) { - // https://tools.ietf.org/html/rfc3986#page-14 - // ALPHA (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), underscore (%5F), or tilde (%7E) - if ( - (byte >= 0x41 && byte <= 0x5A) || - (byte >= 0x61 && byte <= 0x7A) || - (byte >= 0x30 && byte <= 0x39) || - (byte === 0x2D) || - (byte === 0x2E) || - (byte === 0x5F) || - (byte === 0x7E) - ) { - uriEncoded += String.fromCharCode(byte) - } else { - const hex = byte.toString(16) - // String.prototype.padStart() not widely supported yet - const padded = hex.length === 1 ? `0${hex}` : hex - uriEncoded += `%${padded}` - } - } - return uriEncoded - } - return qsDefaultEncoder(data) - } - }) - const reqOptions = { - hostname: config.host, - path: `${config['api-path']}${options.path}?${qs}`, - port: config.port, - method: method, - headers: headers, - protocol: `${config.protocol}:` - } - - const req = getRequest(reqOptions, onRes(options.buffer, callback)) - - req.on('error', (err) => { - callback(err) - }) - - if (!options.stream) { - req.end() - } - - return req -} - -// -// -- Module Interface - -exports = module.exports = (config) => { - /* - * options: { - * path: // API path (like /add or /config) - type: string - * args: // Arguments to the command - type: object - * qs: // Opts as query string opts to the command --something - type: object - * files: // files to be sent - type: string, buffer or array of strings or buffers - * buffer: // buffer the request before sending it - type: bool - * } - */ - const send = (options, callback) => { - if (typeof options !== 'object') { - return callback(new Error('no options were passed')) - } - - return requestAPI(config, options, callback) - } - - // Send a HTTP request and pass via a transform function - // to convert the response data to wanted format before - // returning it to the callback. - // Eg. send.andTransform({}, (e) => JSON.parse(e), (err, res) => ...) - send.andTransform = (options, transform, callback) => { - return send(options, (err, res) => { - if (err) { - return callback(err) - } - transform(res, callback) - }) - } - - return send -} diff --git a/src/utils/stream-to-json-value.js b/src/utils/stream-to-json-value.js deleted file mode 100644 index 2ae83e50d..000000000 --- a/src/utils/stream-to-json-value.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const streamToValue = require('./stream-to-value') - -/* - Converts a stream to a single JSON value -*/ -function streamToJsonValue (res, cb) { - streamToValue(res, (err, data) => { - if (err) { - return cb(err) - } - - if (!data || data.length === 0) { - return cb() - } - - // TODO: check if needed, afaik JSON.parse can parse Buffers - if (Buffer.isBuffer(data)) { - data = data.toString() - } - - let res - try { - res = JSON.parse(data) - } catch (err) { - return cb(new Error(`Invalid JSON: ${data}`)) - } - - cb(null, res) - }) -} - -module.exports = streamToJsonValue diff --git a/src/utils/stream-to-value-with-transformer.js b/src/utils/stream-to-value-with-transformer.js deleted file mode 100644 index 402148667..000000000 --- a/src/utils/stream-to-value-with-transformer.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' - -const streamToValue = require('./stream-to-value') - -function streamToValueWithTransformer (response, transformer, callback) { - if (typeof response.pipe === 'function') { - streamToValue(response, (err, res) => { - if (err) { - return callback(err) - } - transformer(res, callback) - }) - } else { - transformer(response, callback) - } -} - -module.exports = streamToValueWithTransformer diff --git a/src/utils/stream-to-value.js b/src/utils/stream-to-value.js deleted file mode 100644 index d28fd6130..000000000 --- a/src/utils/stream-to-value.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict' - -const pump = require('pump') -const concat = require('concat-stream') - -/* - Concatenate a stream to a single value. -*/ -function streamToValue (response, callback) { - let data - pump( - response, - concat((d) => { data = d }), - (err) => callback(err, data) - ) -} - -module.exports = streamToValue diff --git a/src/version.js b/src/version.js index 438cdd000..8faee147a 100644 --- a/src/version.js +++ b/src/version.js @@ -1,30 +1,19 @@ 'use strict' -const promisify = require('promisify-es6') -const moduleConfig = require('./utils/module-config') +const configure = require('./lib/configure') +const toCamel = require('./lib/object-to-camel') -module.exports = (arg) => { - const send = moduleConfig(arg) +module.exports = configure(({ ky }) => { + return async options => { + options = options || {} - return promisify((opts, callback) => { - if (typeof opts === 'function') { - callback = opts - opts = {} - } + const res = await ky.post('version', { + timeout: options.timeout, + signal: options.signal, + headers: options.headers, + searchParams: options.searchParams + }).json() - send({ - path: 'version', - qs: opts - }, (err, result) => { - if (err) { - return callback(err) - } - const version = { - version: result.Version, - commit: result.Commit, - repo: result.Repo - } - callback(null, version) - }) - }) -} + return toCamel(res) + } +}) diff --git a/test/constructor.spec.js b/test/constructor.spec.js index e4a7eb1aa..60bfc9f33 100644 --- a/test/constructor.spec.js +++ b/test/constructor.spec.js @@ -44,15 +44,6 @@ describe('ipfs-http-client constructor tests', () => { expectConfig(ipfs, { host, port, protocol }) }) - it('multiaddr dns4 string, explicit https in opts', () => { - const host = 'foo.com' - const port = '1001' - const protocol = 'https' - const addr = `/dns4/${host}/tcp/${port}` - const ipfs = ipfsClient(addr, { protocol }) - expectConfig(ipfs, { host, port, protocol }) - }) - it('multiaddr ipv4 string (implicit http)', () => { const host = '101.101.101.101' const port = '1001' @@ -82,7 +73,7 @@ describe('ipfs-http-client constructor tests', () => { it('host and port strings', () => { const host = '1.1.1.1' const port = '9999' - const ipfs = ipfsClient(host, port) + const ipfs = ipfsClient({ host, port }) expectConfig(ipfs, { host, port }) }) @@ -90,14 +81,14 @@ describe('ipfs-http-client constructor tests', () => { const host = '10.100.100.255' const port = '9999' const apiPath = '/future/api/v1/' - const ipfs = ipfsClient(host, port, { 'api-path': apiPath }) - expectConfig(ipfs, { host, port, apiPath }) + const ipfs = ipfsClient({ host, port, apiPath }) + expectConfig(ipfs, { host, port, apiPath: apiPath.slice(0, -1) }) }) it('throws on invalid multiaddr', () => { expect(() => ipfsClient('/dns4')).to.throw('invalid address') expect(() => ipfsClient('/hello')).to.throw('no protocol with name') - expect(() => ipfsClient('/dns4/ipfs.io')).to.throw('multiaddr must have a valid format') + expect(() => ipfsClient('/dns4/ipfs.io')).to.throw() }) }) @@ -134,7 +125,7 @@ async function clientWorks (client) { function expectConfig (ipfs, { host, port, protocol, apiPath }) { const conf = ipfs.getEndpointConfig() expect(conf.host).to.be.oneOf([host, 'localhost', '']) - expect(conf.port).to.be.oneOf([port, '5001', 80]) + expect(conf.port).to.be.oneOf([port, '5001', '80']) expect(conf.protocol).to.equal(protocol || 'http') - expect(conf['api-path']).to.equal(apiPath || '/api/v0/') + expect(conf['api-path']).to.equal(apiPath || '/api/v0') } diff --git a/test/custom-headers.spec.js b/test/custom-headers.spec.js index 0780c23b9..ce14a01e5 100644 --- a/test/custom-headers.spec.js +++ b/test/custom-headers.spec.js @@ -4,23 +4,13 @@ const isNode = require('detect-node') const { expect } = require('interface-ipfs-core/src/utils/mocha') const ipfsClient = require('../src') -const f = require('./utils/factory') describe('custom headers', function () { // do not test in browser if (!isNode) { return } - this.timeout(50 * 1000) // slow CI let ipfs - let ipfsd // initialize ipfs with custom headers - before(async () => { - ipfsd = await f.spawn({ - initOptions: { - bits: 1024, - profile: 'test' - } - }) - + before(() => { ipfs = ipfsClient({ host: 'localhost', port: 6001, @@ -37,6 +27,7 @@ describe('custom headers', function () { req.on('data', () => {}) req.on('end', () => { res.writeHead(200) + res.write(JSON.stringify({})) res.end() // ensure custom headers are present expect(req.headers.authorization).to.equal('Bearer ' + 'YOLO') @@ -48,16 +39,10 @@ describe('custom headers', function () { server.listen(6001, () => { ipfs.id((err, res) => { if (err) { - throw new Error('Unexpected error.') + throw err } // this call is used to test that headers are being sent. }) }) }) - - after(async () => { - if (ipfsd) { - await ipfsd.stop() - } - }) }) diff --git a/test/endpoint-config.spec.js b/test/endpoint-config.spec.js index c867717b9..a44de3e1c 100644 --- a/test/endpoint-config.spec.js +++ b/test/endpoint-config.spec.js @@ -3,43 +3,16 @@ 'use strict' const { expect } = require('interface-ipfs-core/src/utils/mocha') -const isNode = require('detect-node') const ipfsClient = require('../src') -const f = require('./utils/factory') describe('.getEndpointConfig', () => { - if (!isNode) { return } - - let ipfsd - let ipfs - - before(async function () { - this.timeout(20 * 1000) // slow CI - - ipfsd = await f.spawn({ - initOptions: { - bits: 1024, - profile: 'test' - } - }) - ipfs = ipfsClient(ipfsd.apiAddr) - }) - - after(async function () { - this.timeout(10 * 1000) - - if (ipfsd) { - await ipfsd.stop() - } - }) - it('should return the endpoint configuration', function () { + const ipfs = ipfsClient('https://127.0.0.1:5501/ipfs/api/') const endpoint = ipfs.getEndpointConfig() expect(endpoint.host).to.equal('127.0.0.1') - expect(endpoint.protocol).to.equal('http') - expect(endpoint['api-path']).to.equal('/api/v0/') - // changes per test run so we just assert it exists. - expect(endpoint).to.have.property('port') + expect(endpoint.protocol).to.equal('https') + expect(endpoint['api-path']).to.equal('/ipfs/api') + expect(endpoint.port).to.equal('5501') }) }) diff --git a/test/lib.configure.spec.js b/test/lib.configure.spec.js index 8cb56be5f..550165035 100644 --- a/test/lib.configure.spec.js +++ b/test/lib.configure.spec.js @@ -10,7 +10,7 @@ describe('lib/configure', () => { it('should accept no config', () => { configure(config => { if (isBrowser || isWebWorker) { - expect(config.apiAddr).to.eql('') + expect(config.apiAddr).to.eql(location.origin) } else { expect(config.apiAddr).to.eql('http://localhost:5001') } @@ -24,10 +24,17 @@ describe('lib/configure', () => { })(input) }) + it('should accept string url', () => { + const input = 'http://127.0.0.1:5001' + configure(config => { + expect(config.apiAddr).to.eql('http://127.0.0.1:5001') + })(input) + }) + it('should accept multiaddr instance', () => { - const input = Multiaddr('/ip4/127.0.0.1') + const input = Multiaddr('/ip4/127.0.0.1/tcp/5001') configure(config => { - expect(config.apiAddr).to.eql('http://127.0.0.1') + expect(config.apiAddr).to.eql('http://127.0.0.1:5001') })(input) }) diff --git a/test/log.spec.js b/test/log.spec.js index a9dbc0274..7f8e2c608 100644 --- a/test/log.spec.js +++ b/test/log.spec.js @@ -37,20 +37,11 @@ describe('.log', function () { } }, 1000) - const res = await ipfs.log.tail() - - return new Promise((resolve, reject) => { - res.on('error', (err) => { - reject(err) - }) - - res.once('data', (obj) => { - clearInterval(i) - expect(obj).to.be.an('object') - res.end() - resolve() - }) - }) + for await (const message of ipfs.log.tail()) { + clearInterval(i) + expect(message).to.be.an('object') + break + } }) it('.log.ls', async () => { @@ -65,7 +56,7 @@ describe('.log', function () { expect(res).to.exist() expect(res).to.be.an('object') - expect(res).to.not.have.property('Error') - expect(res).to.have.property('Message') + expect(res).to.not.have.property('error') + expect(res).to.have.property('message') }) }) diff --git a/test/node/swarm.js b/test/node/swarm.js index 27d377904..9e0252a2c 100644 --- a/test/node/swarm.js +++ b/test/node/swarm.js @@ -29,24 +29,6 @@ describe('.swarm.peers', function () { expect(scope.isDone()).to.equal(true) }) - it('handles a go-ipfs <= 0.4.4 peer response', async () => { - const response = { Strings: ['/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm'] } - - const scope = nock(apiUrl) - .post('/api/v0/swarm/peers') - .query(true) - .reply(200, response) - - const res = await ipfs.swarm.peers() - - expect(res).to.be.a('array') - expect(res.length).to.equal(1) - expect(res[0].error).to.not.exist() - expect(res[0].addr.toString()).to.equal('/ip4/73.109.217.59/tcp/49311/ipfs/QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') - expect(res[0].peer.toB58String()).to.equal('QmWjxEGC7BthJrCf7QTModrcsRweHbupdPTY4oGMVoDZXm') - expect(scope.isDone()).to.equal(true) - }) - it('handles an ip6 quic peer', async () => { const response = { Peers: [{ Addr: '/ip6/2001:8a0:7ac5:4201:3ac9:86ff:fe31:7095/udp/4001/quic', Peer: 'QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC', Latency: '', Muxer: '', Streams: null }] } diff --git a/test/ping.spec.js b/test/ping.spec.js index 46c58c890..10c131b75 100644 --- a/test/ping.spec.js +++ b/test/ping.spec.js @@ -6,7 +6,6 @@ const pull = require('pull-stream/pull') const collect = require('pull-stream/sinks/collect') const ipfsClient = require('../src') -const PingMessageStream = require('../src/utils/ping-message-stream') const f = require('./utils/factory') // Determine if a ping response object is a pong, or something else, like a status message @@ -58,23 +57,20 @@ describe('.ping', function () { } }) - it('.ping with default n', async () => { + it('.ping with default count', async () => { const res = await ipfs.ping(otherId) - expect(res).to.be.an('array') - expect(res.filter(isPong)).to.have.lengthOf(1) + expect(res.filter(isPong)).to.have.lengthOf(10) res.forEach(packet => { expect(packet).to.have.keys('success', 'time', 'text') expect(packet.time).to.be.a('number') }) - const resultMsg = res.find(packet => packet.text.includes('Average latency')) expect(resultMsg).to.exist() }) it('.ping with count = 2', async () => { const res = await ipfs.ping(otherId, { count: 2 }) - expect(res).to.be.an('array') expect(res.filter(isPong)).to.have.lengthOf(2) res.forEach(packet => { @@ -85,44 +81,13 @@ describe('.ping', function () { expect(resultMsg).to.exist() }) - it('.ping with n = 2', async () => { - const res = await ipfs.ping(otherId, { n: 2 }) - - expect(res).to.be.an('array') - expect(res.filter(isPong)).to.have.lengthOf(2) - res.forEach(packet => { - expect(packet).to.have.keys('success', 'time', 'text') - expect(packet.time).to.be.a('number') - }) - const resultMsg = res.find(packet => packet.text.includes('Average latency')) - expect(resultMsg).to.exist() - }) - - it('.ping fails with count & n', async function () { - this.timeout(20 * 1000) - - await expect(ipfs.ping(otherId, { count: 2, n: 2 })).to.be.rejected() - }) - - it('.ping with Promises', async () => { - const res = await ipfs.ping(otherId) - expect(res).to.be.an('array') - expect(res.filter(isPong)).to.have.lengthOf(1) - res.forEach(packet => { - expect(packet).to.have.keys('success', 'time', 'text') - expect(packet.time).to.be.a('number') - }) - const resultMsg = res.find(packet => packet.text.includes('Average latency')) - expect(resultMsg).to.exist() - }) - it('.pingPullStream', (done) => { pull( - ipfs.pingPullStream(otherId), + ipfs.pingPullStream(otherId, { count: 2 }), collect((err, data) => { expect(err).to.not.exist() expect(data).to.be.an('array') - expect(data.filter(isPong)).to.have.lengthOf(1) + expect(data.filter(isPong)).to.have.lengthOf(2) data.forEach(packet => { expect(packet).to.have.keys('success', 'time', 'text') expect(packet.time).to.be.a('number') @@ -136,7 +101,7 @@ describe('.ping', function () { it('.pingReadableStream', (done) => { let packetNum = 0 - ipfs.pingReadableStream(otherId) + ipfs.pingReadableStream(otherId, { count: 2 }) .on('data', data => { expect(data).to.be.an('object') expect(data).to.have.keys('success', 'time', 'text') @@ -146,15 +111,8 @@ describe('.ping', function () { expect(err).not.to.exist() }) .on('end', () => { - expect(packetNum).to.equal(1) + expect(packetNum).to.equal(2) done() }) }) - - it('message conversion fails if invalid message is received', () => { - const messageConverter = new PingMessageStream() - expect(() => { - messageConverter.write({ some: 'InvalidMessage' }) - }).to.throw('Invalid ping message received') - }) }) diff --git a/test/sub-modules.spec.js b/test/sub-modules.spec.js index 62d05ce8e..ee8f6d93b 100644 --- a/test/sub-modules.spec.js +++ b/test/sub-modules.spec.js @@ -2,14 +2,10 @@ 'use strict' const { expect } = require('interface-ipfs-core/src/utils/mocha') -const defaultConfig = require('../src/utils/default-config.js') -const config = defaultConfig() -config.host = 'test' -config.port = '1111' describe('submodules', () => { it('bitswap', () => { - const bitswap = require('../src/bitswap')(config) + const bitswap = require('../src/bitswap')() expect(bitswap.wantlist).to.be.a('function') expect(bitswap.stat).to.be.a('function') @@ -17,7 +13,7 @@ describe('submodules', () => { }) it('block', () => { - const block = require('../src/block')(config) + const block = require('../src/block')() expect(block.get).to.be.a('function') expect(block.stat).to.be.a('function') @@ -25,7 +21,7 @@ describe('submodules', () => { }) it('bootstrap', () => { - const bootstrap = require('../src/bootstrap')(config) + const bootstrap = require('../src/bootstrap')() expect(bootstrap.add).to.be.a('function') expect(bootstrap.rm).to.be.a('function') @@ -33,7 +29,7 @@ describe('submodules', () => { }) it('config', () => { - const cfg = require('../src/config')(config) + const cfg = require('../src/config')() expect(cfg.get).to.be.a('function') expect(cfg.set).to.be.a('function') @@ -44,7 +40,7 @@ describe('submodules', () => { }) it('dht', () => { - const dht = require('../src/dht')(config) + const dht = require('../src/dht')() expect(dht.get).to.be.a('function') expect(dht.put).to.be.a('function') @@ -55,21 +51,21 @@ describe('submodules', () => { }) it('id', () => { - const id = require('../src/id')(config) + const id = require('../src/id')() expect(id).to.be.a('function') }) it('version', () => { - const version = require('../src/version')(config) + const version = require('../src/version')() expect(version).to.be.a('function') }) it('ping', () => { - const ping = require('../src/ping')(config) - const pingPullStream = require('../src/ping-pull-stream')(config) - const pingReadableStream = require('../src/ping-readable-stream')(config) + const ping = require('../src')().ping + const pingPullStream = require('../src')().pingPullStream + const pingReadableStream = require('../src')().pingReadableStream expect(ping).to.be.a('function') expect(pingPullStream).to.be.a('function') @@ -77,7 +73,7 @@ describe('submodules', () => { }) it('log', () => { - const log = require('../src/log')(config) + const log = require('../src/log')() expect(log.ls).to.be.a('function') expect(log.tail).to.be.a('function') @@ -85,21 +81,21 @@ describe('submodules', () => { }) it('key', () => { - const key = require('../src/key')(config) + const key = require('../src/key')() expect(key.gen).to.be.a('function') expect(key.list).to.be.a('function') }) it('name', () => { - const name = require('../src/name')(config) + const name = require('../src/name')() expect(name.publish).to.be.a('function') expect(name.resolve).to.be.a('function') }) it('pin', () => { - const pin = require('../src/pin')(config) + const pin = require('../src/pin')() expect(pin.add).to.be.a('function') expect(pin.rm).to.be.a('function') @@ -107,14 +103,14 @@ describe('submodules', () => { }) it('repo', () => { - const repo = require('../src/repo')(config) + const repo = require('../src/repo')() expect(repo.gc).to.be.a('function') expect(repo.stat).to.be.a('function') }) it('stats', () => { - const stats = require('../src/stats')(config) + const stats = require('../src/stats')() expect(stats.bitswap).to.be.a('function') expect(stats.bw).to.be.a('function') @@ -122,7 +118,7 @@ describe('submodules', () => { }) it('swarm', () => { - const swarm = require('../src/swarm')(config) + const swarm = require('../src/swarm')() expect(swarm.peers).to.be.a('function') expect(swarm.connect).to.be.a('function') @@ -132,7 +128,7 @@ describe('submodules', () => { }) it('diag', () => { - const diag = require('../src/diag')(config) + const diag = require('../src/diag')() expect(diag.net).to.be.a('function') expect(diag.sys).to.be.a('function') @@ -140,7 +136,7 @@ describe('submodules', () => { }) it('object', () => { - const object = require('../src/object')(config) + const object = require('../src/object')() expect(object.get).to.be.a('function') expect(object.put).to.be.a('function') @@ -155,7 +151,7 @@ describe('submodules', () => { }) it('pubsub', () => { - const pubsub = require('../src/pubsub')(config) + const pubsub = require('../src/pubsub')() expect(pubsub.subscribe).to.be.a('function') expect(pubsub.unsubscribe).to.be.a('function') @@ -165,7 +161,7 @@ describe('submodules', () => { }) it('files regular API', () => { - const filesRegular = require('../src')(config) + const filesRegular = require('../src')() expect(filesRegular.add).to.be.a('function') expect(filesRegular.addReadableStream).to.be.a('function') @@ -191,7 +187,7 @@ describe('submodules', () => { }) it('files MFS API', () => { - const files = require('../src/files')(config) + const files = require('../src/files')() expect(files.cp).to.be.a('function') expect(files.ls).to.be.a('function') @@ -204,13 +200,13 @@ describe('submodules', () => { }) it('commands', () => { - const commands = require('../src/commands')(config) + const commands = require('../src/commands')() expect(commands).to.be.a('function') }) it('mount', () => { - const mount = require('../src/mount')(config) + const mount = require('../src/mount')() expect(mount).to.be.a('function') }) From 496811b2ead8377227ec872dd256cc6c09c38356 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 22 Nov 2019 14:37:48 +0000 Subject: [PATCH 23/24] chore: update contributors --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8fc450b79..423109411 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipfs-http-client", - "version": "39.0.2", + "version": "40.0.0", "description": "A client library for the IPFS HTTP API", "keywords": [ "ipfs" @@ -101,7 +101,6 @@ "Alan Shaw ", "Alan Shaw ", "Alex Mingoia ", - "Alex Potsides ", "Antonio Tenorio-Fornés ", "Bruno Barbieri ", "Clemo ", @@ -174,6 +173,7 @@ "Victor Bjelkholm ", "Volker Mische ", "Zhiyuan Lin ", + "achingbrain ", "dirkmc ", "dmitriy ryajov ", "elsehow ", From 79ff53241e0b72730eb94a2b5a1793a33c97c687 Mon Sep 17 00:00:00 2001 From: Alan Shaw Date: Fri, 22 Nov 2019 14:37:49 +0000 Subject: [PATCH 24/24] chore: release version v40.0.0 --- CHANGELOG.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 049e2b123..0f0de1f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,57 @@ + +# [40.0.0](https://github.com/ipfs/js-ipfs-http-client/compare/v39.0.2...v40.0.0) (2019-11-22) + + +### Code Refactoring + +* async await roundup ([#1173](https://github.com/ipfs/js-ipfs-http-client/issues/1173)) ([3e5967a](https://github.com/ipfs/js-ipfs-http-client/commit/3e5967a)), closes [#1103](https://github.com/ipfs/js-ipfs-http-client/issues/1103) +* convert config API to async await ([#1155](https://github.com/ipfs/js-ipfs-http-client/issues/1155)) ([621973c](https://github.com/ipfs/js-ipfs-http-client/commit/621973c)) +* move files to root level ([#1150](https://github.com/ipfs/js-ipfs-http-client/issues/1150)) ([559a97d](https://github.com/ipfs/js-ipfs-http-client/commit/559a97d)) + + +### Features + +* support name.resolve of peerid as cid ([#1145](https://github.com/ipfs/js-ipfs-http-client/issues/1145)) ([2d9afc8](https://github.com/ipfs/js-ipfs-http-client/commit/2d9afc8)) + + +### Reverts + +* chore: update multiaddr to version 7.2.0 ([#1136](https://github.com/ipfs/js-ipfs-http-client/issues/1136)) ([#1143](https://github.com/ipfs/js-ipfs-http-client/issues/1143)) ([4131d09](https://github.com/ipfs/js-ipfs-http-client/commit/4131d09)) + + +### BREAKING CHANGES + +* The `log.tail` method now returns an async iterator that yields log messages. Use it like: + +```js +for await (const message of ipfs.log.tail()) { + console.log(message) +} +``` +* The response to a call to `log.level` now returns an object that has camel cased keys. i.e. `Message` and `Error` properties have changed to `message` and `error`. +* Dropped support for go-ipfs <= 0.4.4 in `swarm.peers` response. +* The signature for `ipfs.mount` has changed from `ipfs.mount([ipfsPath], [ipnsPath])` to `ipfs.mount([options])`. Where `options` is an optional object that may contain two boolean properties `ipfsPath` and `ipnsPath`. The response object has also changed to be camel case. See https://docs.ipfs.io/reference/api/http/#api-v0-mount. +* Default ping `count` of 1 in client has been removed. The default ping count is now whatever the IPFS node defaults it to (currently 10). If you specifically need 1 ping message then please pass `count: 1` in options for `ipfs.ping()`. +* Multi parameter constructor options are no longer supported. To create a new IPFS HTTP client, pass a single parameter to the constructor. The parameter can be one of: + +* String, formatted as one of: + * Multiaddr e.g. /ip4/127.0.0.1/tcp/5001 + * URL e.g. http://127.0.0.1:5001 +* [Multiaddr](https://www.npmjs.com/package/multiaddr) instance +* Object, in format of either: + * Address and path e.g. `{ apiAddr: '/ip4/127.0.0.1/tcp/5001': apiPath: '/api/v0' }` (Note: `apiAddr` can also be a string in URL form or a Multiaddr instance) + * Node.js style address e.g. `{ host: '127.0.0.1', port: 5001, protocol: 'http' }` +* Errors returned from request failures are now all [`HTTPError`](https://github.com/sindresorhus/ky/blob/c0d9d2bb07e4c122a08f019b39e9c55a4c9324f3/index.js#L117-L123)s which carry a `response` property. This is a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) that can be used to inspect _all_ information relating to the HTTP response. This means that the `err.status` or `err.statusCode` property should now be accessed via `err.response.status`. + +License: MIT +Signed-off-by: Alan Shaw +* files in `src/files-regular` have moved to `src`. The `src/files-mfs` directory has been renamed to `src/files`. If you were previously requiring files from these directories e.g. `require('ipfs-http-client/src/files-regular/add')` then please be aware that they have moved. + +License: MIT +Signed-off-by: Alan Shaw + + + ## [39.0.2](https://github.com/ipfs/js-ipfs-http-client/compare/v39.0.1...v39.0.2) (2019-10-23)