From 53956bf169ea25e256c9dd1a41e8b2e5a524e3d2 Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 28 Dec 2017 08:15:18 +0000 Subject: [PATCH 01/32] docs: add FAQ about Electron (#1160) * docs: add FAQ about Electron ref: https://github.com/ipfs/js-ipfs/issues/843#issuecomment-332088905 * Update README.md * Update README.md --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index fb803d72e3..01a89fda97 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ You can check the development status at the [Waffle Board](https://waffle.io/ipf - [Network](#network) - [Node Management](#node-management) - [Domain data types](#domain-data-types) +- [FAQ](#faq) - [Packages](#packages) - [Development](#development) - [Clone and install dependencies](#clone-and-install-dependencies) @@ -441,6 +442,29 @@ Yes, unfortunately, due to [Chrome aggressive resource throttling policy](https: A way to mitigate this in Chrome, is to run your IPFS node inside a Service Worker, so that the IPFS instance runs in a background process. You can learn how to install an IPFS node as a service worker in here the repo [ipfs-service-worker](https://github.com/ipfs/ipfs-service-worker) +#### Can I use IPFS in my Electron App? + +Yes you can and in many ways. Read https://github.com/ipfs/notes/issues/256 for the multiple options. + +If your [electron-rebuild step is failing](https://github.com/ipfs/js-ipfs/issues/843), all you need to do is: + +```bash +# Electron's version. +export npm_config_target=1.7.6 +# The architecture of Electron, can be ia32 or x64. +export npm_config_arch=x64 +export npm_config_target_arch=x64 +# Download headers for Electron. +export npm_config_disturl=https://atom.io/download/electron +# Tell node-pre-gyp that we are building for Electron. +export npm_config_runtime=electron +# Tell node-pre-gyp to build module from source code. +export npm_config_build_from_source=true +# Install all dependencies, and store cache to ~/.electron-gyp. +HOME=~/.electron-gyp npm install +``` + +If you find any other issue, please check the [`Electron Support` issue](https://github.com/ipfs/js-ipfs/issues/843). ## Packages From 2af463c73ea95d4f29a99986f899c150fccbdd55 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sat, 6 Jan 2018 09:38:12 +0000 Subject: [PATCH 02/32] chore: update README.md (#1169) --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 01a89fda97..0c42314fec 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,8 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [files](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md) - [`ipfs.files.add(data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#add) - - [`ipfs.files.createAddStream([options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#createaddstream) + - [`ipfs.files.addReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addreadablestream) + - [`ipfs.files.addPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addpullstream) - [`ipfs.files.cat(multihash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) - [`ipfs.files.get(hash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) @@ -256,6 +257,7 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.dag.put(dagNode, options, callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/DAG.md#dagput) - [`ipfs.dag.get(cid [, path, options], callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/DAG.md#dagget) - [`ipfs.dag.tree(cid [, path, options], callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/DAG.md#dagtree) + - [object](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md). - [`ipfs.object.new([template][, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md#objectnew) - [`ipfs.object.put(obj, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md#objectput) @@ -275,21 +277,26 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.bootstrap.list` - `ipfs.bootstrap.add` - `ipfs.bootstrap.rm` + - [bitswap](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) - `ipfs.bitswap.wantlist()` - `ipfs.bitswap.stat()` - `ipfs.bitswap.unwant()` + - [dht (not implemented, yet!)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) + - [pubsub](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md) - [`ipfs.pubsub.subscribe(topic, options, handler, callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md#pubsubsubscribe) - [`ipfs.pubsub.unsubscribe(topic, handler)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md#pubsubunsubscribe) - [`ipfs.pubsub.publish(topic, data, callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md#pubsubpublish) - [`ipfs.pubsub.ls(topic, callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md#pubsubls) - [`ipfs.pubsub.peers(topic, callback)`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/PUBSUB.md#pubsubpeers) + - [libp2p](https://github.com/libp2p/interface-libp2p). Every IPFS instance also exposes the libp2p SPEC at `ipfs.libp2p`. The formal interface for this SPEC hasn't been defined by you can find documentation at its implementations: - [Node.js bundle](./src/core/runtime/libp2p-nodejs.js) - [Browser Bundle](./src/core/runtime/libp2p-browser.js) - [libp2p baseclass](https://github.com/libp2p/js-libp2p) + - [swarm](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/SWARM.md) - [`ipfs.swarm.addrs([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/SWARM.md#addrs) - [`ipfs.swarm.connect(addr, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/SWARM.md#connect) @@ -306,6 +313,7 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.start([callback])` - `ipfs.stop([callback])` - `ipfs.isOnline()` + - [config](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md) - [`ipfs.config.get([key, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md#configget) - [`ipfs.config.set(key, value, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md#configset) From 0f8675f8764e8e37087931185d81efb7c78be038 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 7 Jan 2018 18:14:49 +0000 Subject: [PATCH 03/32] chore: update deps (#1170) * chore: update aegir * chore: update deps * chore: bring back webworker * chore: update circle config --- circle.yml | 7 ++----- package.json | 10 ++++------ 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/circle.yml b/circle.yml index a132855ce9..e0338e62d4 100644 --- a/circle.yml +++ b/circle.yml @@ -1,21 +1,18 @@ +# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories. machine: node: version: stable test: post: - - npm run coverage -- --upload + - npm run coverage -- --upload --providers coveralls dependencies: pre: - google-chrome --version - curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb - - for v in $(curl http://archive.ubuntu.com/ubuntu/pool/main/n/nss/ | grep "href=" | grep "libnss3.*deb\"" -o | grep -o "libnss3.*deb" | grep "3.28" | grep "14.04"); do curl -L -o $v http://archive.ubuntu.com/ubuntu/pool/main/n/nss/$v; done && rm libnss3-tools*_i386.deb libnss3-dev*_i386.deb - sudo dpkg -i google-chrome.deb || true - - sudo dpkg -i libnss3*.deb || true - sudo apt-get update - - sudo apt-get install -f || true - - sudo dpkg -i libnss3*.deb - sudo apt-get install -f - sudo apt-get install --only-upgrade lsb-base - sudo dpkg -i google-chrome.deb diff --git a/package.json b/package.json index cb6446bfb9..5058eeed13 100644 --- a/package.json +++ b/package.json @@ -21,15 +21,13 @@ "scripts": { "lint": "aegir lint", "build": "aegir build", - "test": "aegir test -t node -t browser --no-cors", + "test": "aegir test -t node -t browser -t webworker --no-cors", "test:node": "aegir test -t node", "test:browser": "aegir test -t browser -t webworker --no-cors", - "test:node": "aegir test -t node", "test:node:core": "aegir test -t node -f test/core/**.js", "test:node:http": "aegir test -t node -f test/http-api/index.js", "test:node:gateway": "aegir test -t node -f test/gateway/index.js", "test:node:cli": "aegir test -t node -f test/cli/index.js", - "test:browser": "aegir test -t browser --no-cors", "test:bootstrapers": "IPFS_TEST=bootstrapers aegir test -t browser -f test/bootstrapers.js", "benchmark": "echo \"Error: no benchmarks yet\" && exit 1", "benchmark:node": "echo \"Error: no benchmarks yet\" && exit 1", @@ -60,7 +58,7 @@ }, "homepage": "https://github.com/ipfs/js-ipfs#readme", "devDependencies": { - "aegir": "^12.2.0", + "aegir": "^12.3.0", "buffer-loader": "0.0.1", "chai": "^4.1.2", "delay": "^2.0.0", @@ -115,14 +113,14 @@ "is-ipfs": "^0.3.2", "is-stream": "^1.1.0", "joi": "^13.0.2", - "libp2p": "~0.14.0", + "libp2p": "~0.15.0", "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", - "libp2p-secio": "~0.8.1", + "libp2p-secio": "~0.9.0", "libp2p-tcp": "~0.11.1", "libp2p-webrtc-star": "~0.13.3", "libp2p-websocket-star": "~0.7.2", From b6bb5333648570243a846a1216671577d7936cec Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 7 Jan 2018 18:29:38 +0000 Subject: [PATCH 04/32] chore: update contributors --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 5058eeed13..ad4db9bb73 100644 --- a/package.json +++ b/package.json @@ -228,6 +228,7 @@ "bitspill ", "haad ", "jbenet ", + "jonahweissman <19804455+jonahweissman@users.noreply.github.com>", "kevingzhang ", "kumavis ", "nginnever ", From 624cb47d1c3becca1001f79c7e8fdc8bfcd43480 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 7 Jan 2018 18:29:38 +0000 Subject: [PATCH 05/32] chore: release version v0.27.6 --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65a39e99c3..50cc8b4fe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +## [0.27.6](https://github.com/ipfs/js-ipfs/compare/v0.27.5...v0.27.6) (2018-01-07) + + +### Bug Fixes + +* cli files on Windows ([#1159](https://github.com/ipfs/js-ipfs/issues/1159)) ([1b98fa1](https://github.com/ipfs/js-ipfs/commit/1b98fa1)) + + + ## [0.27.5](https://github.com/ipfs/js-ipfs/compare/v0.27.4...v0.27.5) (2017-12-18) diff --git a/package.json b/package.json index ad4db9bb73..52fa0192ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipfs", - "version": "0.27.5", + "version": "0.27.6", "description": "JavaScript implementation of the IPFS specification", "bin": { "jsipfs": "src/cli/bin.js" From 863203064f83ddf3b374a6c901b520975cc869f0 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 10 Jan 2018 18:31:54 +0000 Subject: [PATCH 06/32] docs: add missing pointers to the Files API calls --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0c42314fec..c4ea15efa5 100644 --- a/README.md +++ b/README.md @@ -239,7 +239,11 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.files.addReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addreadablestream) - [`ipfs.files.addPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addpullstream) - [`ipfs.files.cat(multihash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) + - [`ipfs.files.catReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catreadablestream) + - [`ipfs.files.catPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catpullstream) - [`ipfs.files.get(hash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) + - [`ipfs.files.getReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getreadablestream) + - [`ipfs.files.getPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getpullstream) - [block](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md) - [`ipfs.block.get(cid, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md#get) From 5c4e9a1a6d3e808a696d97f3d9e89fc3074290f3 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 10 Jan 2018 18:41:35 +0000 Subject: [PATCH 07/32] docs: fix api func signatures --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c4ea15efa5..220bee1029 100644 --- a/README.md +++ b/README.md @@ -238,12 +238,12 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.files.add(data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#add) - [`ipfs.files.addReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addreadablestream) - [`ipfs.files.addPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addpullstream) - - [`ipfs.files.cat(multihash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) - - [`ipfs.files.catReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catreadablestream) - - [`ipfs.files.catPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catpullstream) - - [`ipfs.files.get(hash, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) - - [`ipfs.files.getReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getreadablestream) - - [`ipfs.files.getPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getpullstream) + - [`ipfs.files.cat(ipfsPath, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) + - [`ipfs.files.catReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catreadablestream) + - [`ipfs.files.catPullStream(ipfsPathm, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catpullstream) + - [`ipfs.files.get(ipfsPath, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) + - [`ipfs.files.getReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getreadablestream) + - [`ipfs.files.getPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getpullstream) - [block](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md) - [`ipfs.block.get(cid, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md#get) From fadead15b099a4bcc180ff780b373dc015eada08 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 10 Jan 2018 18:44:21 +0000 Subject: [PATCH 08/32] docs: fix typo --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 220bee1029..bef1e12285 100644 --- a/README.md +++ b/README.md @@ -238,10 +238,10 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.files.add(data, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#add) - [`ipfs.files.addReadableStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addreadablestream) - [`ipfs.files.addPullStream([options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#addpullstream) - - [`ipfs.files.cat(ipfsPath, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) + - [`ipfs.files.cat(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#cat) - [`ipfs.files.catReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catreadablestream) - - [`ipfs.files.catPullStream(ipfsPathm, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catpullstream) - - [`ipfs.files.get(ipfsPath, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) + - [`ipfs.files.catPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#catpullstream) + - [`ipfs.files.get(ipfsPath, [options], [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#get) - [`ipfs.files.getReadableStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getreadablestream) - [`ipfs.files.getPullStream(ipfsPath, [options])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/FILES.md#getpullstream) From 639024caefbc05a9a7af124815df3a0ca4110ff2 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 16 Jan 2018 14:01:05 +0000 Subject: [PATCH 09/32] feat: /api/v0/dns (#1172) --- .gitignore | 1 + package.json | 37 +++++++++++++++++---------------- src/cli/commands/dns.js | 24 +++++++++++++++++++++ src/core/components/dns.js | 20 ++++++++++++++++++ src/core/components/index.js | 1 + src/core/index.js | 1 + src/core/runtime/dns-browser.js | 25 ++++++++++++++++++++++ src/core/runtime/dns-nodejs.js | 21 +++++++++++++++++++ src/http/api/resources/dns.js | 24 +++++++++++++++++++++ src/http/api/resources/index.js | 1 + src/http/api/routes/dns.js | 13 ++++++++++++ src/http/api/routes/index.js | 1 + test/cli/commands.js | 2 +- test/cli/dns.js | 22 ++++++++++++++++++++ test/http-api/extra/dns.js | 19 +++++++++++++++++ test/http-api/spec/dns.js | 24 +++++++++++++++++++++ 16 files changed, 217 insertions(+), 19 deletions(-) create mode 100644 src/cli/commands/dns.js create mode 100644 src/core/components/dns.js create mode 100644 src/core/runtime/dns-browser.js create mode 100644 src/core/runtime/dns-nodejs.js create mode 100644 src/http/api/resources/dns.js create mode 100644 src/http/api/routes/dns.js create mode 100644 test/cli/dns.js create mode 100644 test/http-api/extra/dns.js create mode 100644 test/http-api/spec/dns.js diff --git a/.gitignore b/.gitignore index 18ddbab6a9..7455bdffdb 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,4 @@ test/test-data/go-ipfs-repo/LOG.old # while testing npm5 package-lock.json +yarn.lock diff --git a/package.json b/package.json index 52fa0192ff..7ec29b7b17 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "./src/core/runtime/config-nodejs.json": "./src/core/runtime/config-browser.json", "./src/core/runtime/libp2p-nodejs.js": "./src/core/runtime/libp2p-browser.js", "./src/core/runtime/repo-nodejs.js": "./src/core/runtime/repo-browser.js", + "./src/core/runtime/dns-nodejs.js": "./src/core/runtime/dns-browser.js", "./test/utils/create-repo-nodejs.js": "./test/utils/create-repo-browser.js", "stream": "readable-stream" }, @@ -66,14 +67,14 @@ "dir-compare": "^1.4.0", "dirty-chai": "^2.0.1", "eslint-plugin-react": "^7.5.1", - "execa": "^0.8.0", + "execa": "^0.9.0", "expose-loader": "^0.7.4", "form-data": "^2.3.1", "hat": "0.0.3", - "interface-ipfs-core": "~0.36.15", + "interface-ipfs-core": "~0.40.0", "left-pad": "^1.2.0", "lodash": "^4.17.4", - "mocha": "^4.0.1", + "mocha": "^4.1.0", "ncp": "^2.0.0", "nexpect": "^0.5.0", "pre-commit": "^1.2.2", @@ -91,28 +92,28 @@ "boom": "^7.1.1", "bs58": "^4.0.1", "byteman": "^1.3.5", - "cids": "^0.5.2", + "cids": "~0.5.2", "debug": "^3.1.0", "file-type": "^7.4.0", "filesize": "^3.5.11", "fsm-event": "^2.1.0", - "get-folder-size": "^1.0.0", + "get-folder-size": "^1.0.1", "glob": "^7.1.2", - "hapi": "^16.2.2", + "hapi": "^16.6.2", "hapi-set-header": "^1.0.2", "hoek": "^5.0.2", - "ipfs-api": "^17.2.4", + "ipfs-api": "^17.3.0", "ipfs-bitswap": "~0.18.0", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", "ipfs-multipart": "~0.1.0", - "ipfs-repo": "~0.18.4", + "ipfs-repo": "~0.18.5", "ipfs-unixfs": "~0.1.14", - "ipfs-unixfs-engine": "~0.24.1", + "ipfs-unixfs-engine": "~0.24.2", "ipld-resolver": "~0.14.1", "is-ipfs": "^0.3.2", "is-stream": "^1.1.0", - "joi": "^13.0.2", + "joi": "^13.1.0", "libp2p": "~0.15.0", "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", @@ -121,7 +122,7 @@ "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", "libp2p-secio": "~0.9.0", - "libp2p-tcp": "~0.11.1", + "libp2p-tcp": "~0.11.2", "libp2p-webrtc-star": "~0.13.3", "libp2p-websocket-star": "~0.7.2", "libp2p-websockets": "~0.10.4", @@ -132,13 +133,13 @@ "mafmt": "^3.0.2", "mime-types": "^2.1.17", "mkdirp": "~0.5.1", - "multiaddr": "^3.0.1", - "multihashes": "~0.4.12", + "multiaddr": "^3.0.2", + "multihashes": "~0.4.13", "once": "^1.4.0", "path-exists": "^3.0.0", "peer-book": "~0.5.2", - "peer-id": "~0.10.3", - "peer-info": "~0.11.3", + "peer-id": "~0.10.4", + "peer-info": "~0.11.4", "progress": "^2.0.0", "promisify-es6": "^1.0.3", "pull-abortable": "^4.1.1", @@ -146,7 +147,7 @@ "pull-file": "^1.1.0", "pull-ndjson": "^0.1.1", "pull-paramap": "^1.2.2", - "pull-pushable": "^2.1.1", + "pull-pushable": "^2.1.2", "pull-sort": "^1.0.1", "pull-stream": "^3.6.1", "pull-stream-to-stream": "^1.3.4", @@ -159,8 +160,8 @@ "temp": "~0.8.3", "through2": "^2.0.3", "update-notifier": "^2.3.0", - "yargs": "^10.0.3", - "yargs-parser": "^8.0.0" + "yargs": "^10.1.1", + "yargs-parser": "^8.1.0" }, "optionalDependencies": { "prom-client": "^10.2.2", diff --git a/src/cli/commands/dns.js b/src/cli/commands/dns.js new file mode 100644 index 0000000000..5be09d12e1 --- /dev/null +++ b/src/cli/commands/dns.js @@ -0,0 +1,24 @@ +'use strict' +const print = require('../utils').print + +module.exports = { + command: 'dns ', + + describe: 'Resolve DNS links', + + builder: { + format: { + type: 'string' + } + }, + + handler (argv) { + argv.ipfs.dns(argv['domain'], (err, path) => { + if (err) { + throw err + } + + print(path) + }) + } +} diff --git a/src/core/components/dns.js b/src/core/components/dns.js new file mode 100644 index 0000000000..4895f01667 --- /dev/null +++ b/src/core/components/dns.js @@ -0,0 +1,20 @@ +'use strict' + +// dns-nodejs gets replaced by dns-browser when webpacked/browserified +const dns = require('../runtime/dns-nodejs') +const promisify = require('promisify-es6') + +module.exports = () => { + return promisify((domain, opts, callback) => { + if (typeof domain !== 'string') { + return callback(new Error('Invalid arguments, domain must be a string')) + } + + if (typeof opts === 'function') { + callback = opts + opts = {} + } + + dns(domain, opts, callback) + }) +} diff --git a/src/core/components/index.js b/src/core/components/index.js index e4fb45464f..248243a88e 100644 --- a/src/core/components/index.js +++ b/src/core/components/index.js @@ -20,3 +20,4 @@ exports.files = require('./files') exports.bitswap = require('./bitswap') exports.pubsub = require('./pubsub') exports.dht = require('./dht') +exports.dns = require('./dns') diff --git a/src/core/index.js b/src/core/index.js index 2fb4825e54..fa60876061 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -94,6 +94,7 @@ class IPFS extends EventEmitter { this.ping = components.ping(this) this.pubsub = components.pubsub(this) this.dht = components.dht(this) + this.dns = components.dns(this) if (this._options.EXPERIMENTAL.pubsub) { this.log('EXPERIMENTAL pubsub is enabled') diff --git a/src/core/runtime/dns-browser.js b/src/core/runtime/dns-browser.js new file mode 100644 index 0000000000..c68de233fe --- /dev/null +++ b/src/core/runtime/dns-browser.js @@ -0,0 +1,25 @@ +'use strict' + +module.exports = (domain, opts, callback) => { + domain = encodeURIComponent(domain) + let url = `https://ipfs.io/api/v0/dns?arg=${domain}` + + for (const prop in opts) { + url += `&${prop}=${opts[prop]}` + } + + self.fetch(url, {mode: 'cors'}) + .then((response) => { + return response.json() + }) + .then((response) => { + if (response.Path) { + return callback(null, response.Path) + } else { + return callback(new Error(response.Message)) + } + }) + .catch((error) => { + callback(error) + }) +} diff --git a/src/core/runtime/dns-nodejs.js b/src/core/runtime/dns-nodejs.js new file mode 100644 index 0000000000..8f6bb132bd --- /dev/null +++ b/src/core/runtime/dns-nodejs.js @@ -0,0 +1,21 @@ +'use strict' + +const dns = require('dns') + +module.exports = (domain, opts, callback) => { + dns.resolveTxt(domain, (err, records) => { + if (err) { + return callback(err, null) + } + + // TODO: implement recursive option + + for (const record of records) { + if (record[0].startsWith('dnslink=')) { + return callback(null, record[0].substr(8, record[0].length - 1)) + } + } + + callback(new Error('domain does not have a txt dnslink entry')) + }) +} diff --git a/src/http/api/resources/dns.js b/src/http/api/resources/dns.js new file mode 100644 index 0000000000..92549e68b7 --- /dev/null +++ b/src/http/api/resources/dns.js @@ -0,0 +1,24 @@ +'use strict' + +const boom = require('boom') + +exports = module.exports + +exports.get = (request, reply) => { + if (!request.query.arg) { + return reply({ + Message: "Argument 'domain' is required", + Code: 0 + }).code(400).takeover() + } + + request.server.app.ipfs.dns(request.query.arg, (err, path) => { + if (err) { + return reply(boom.badRequest(err)) + } + + return reply({ + Path: path + }) + }) +} diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index 37bb316cab..16b0f17128 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -12,3 +12,4 @@ exports.bitswap = require('./bitswap') exports.file = require('./file') exports.files = require('./files') exports.pubsub = require('./pubsub') +exports.dns = require('./dns') diff --git a/src/http/api/routes/dns.js b/src/http/api/routes/dns.js new file mode 100644 index 0000000000..dd3f074025 --- /dev/null +++ b/src/http/api/routes/dns.js @@ -0,0 +1,13 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/dns', + handler: resources.dns.get + }) +} diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index 08756fc91c..908c0c0878 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -15,4 +15,5 @@ module.exports = (server) => { require('./pubsub')(server) require('./debug')(server) require('./webui')(server) + require('./dns')(server) } diff --git a/test/cli/commands.js b/test/cli/commands.js index 558cbcc8b4..3a2d85a418 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,7 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 59 +const commandCount = 60 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/cli/dns.js b/test/cli/dns.js new file mode 100644 index 0000000000..ae66c6c8c3 --- /dev/null +++ b/test/cli/dns.js @@ -0,0 +1,22 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const runOnAndOff = require('../utils/on-and-off') + +describe('dns', () => runOnAndOff((thing) => { + let ipfs + + before(function () { + this.timeout(60 * 1000) + ipfs = thing.ipfs + }) + + it('resolve ipfs.io dns', function () { + this.timeout(60 * 1000) + + return ipfs('dns ipfs.io').then((res) => { + expect(res.substr(0, 6)).to.eql('/ipfs/') + }) + }) +})) diff --git a/test/http-api/extra/dns.js b/test/http-api/extra/dns.js new file mode 100644 index 0000000000..bb6ab6046f --- /dev/null +++ b/test/http-api/extra/dns.js @@ -0,0 +1,19 @@ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) + +module.exports = (ctl) => { + describe('.dns', () => { + it('resolve ipfs.io dns', (done) => { + ctl.dns('ipfs.io', (err, result) => { + expect(err).to.not.exist() + expect(result).to.exist() + done() + }) + }) + }) +} diff --git a/test/http-api/spec/dns.js b/test/http-api/spec/dns.js new file mode 100644 index 0000000000..bf84eb6b07 --- /dev/null +++ b/test/http-api/spec/dns.js @@ -0,0 +1,24 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect + +module.exports = (http) => { + describe('/dns', () => { + let api + + before(() => { + api = http.api.server.select('API') + }) + + it('resolve ipfs.io dns', (done) => { + api.inject({ + method: 'GET', + url: '/api/v0/dns?arg=ipfs.io' + }, (res) => { + expect(res.result).to.have.property('Path') + done() + }) + }) + }) +} From 1620dd2d05829a4ae7b4bcffd6f51d16db4f7a22 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 16 Jan 2018 06:59:20 -0800 Subject: [PATCH 10/32] chore: update timeout on daemon cli test --- test/cli/daemon.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/cli/daemon.js b/test/cli/daemon.js index 4e284656f8..ae4bf9caf3 100644 --- a/test/cli/daemon.js +++ b/test/cli/daemon.js @@ -104,7 +104,9 @@ describe('daemon', () => { }).catch(done) }) - it('gives error if user hasn\'t run init before', (done) => { + it('gives error if user hasn\'t run init before', function (done) { + this.timeout(100 * 1000) + const expectedError = 'no initialized ipfs repo found in ' + repoPath ipfs('daemon').catch((err) => { From 5a517fdadcfc715fd39df3d4ab588b126722acf6 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 16 Jan 2018 06:59:47 -0800 Subject: [PATCH 11/32] chore: update contributors From d798d597b558f46af8df8d571cf589bb93d36897 Mon Sep 17 00:00:00 2001 From: David Dias Date: Tue, 16 Jan 2018 06:59:47 -0800 Subject: [PATCH 12/32] chore: release version v0.27.7 --- CHANGELOG.md | 10 ++++++++++ package.json | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50cc8b4fe9..774d7509d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ + +## [0.27.7](https://github.com/ipfs/js-ipfs/compare/v0.27.6...v0.27.7) (2018-01-16) + + +### Features + +* /api/v0/dns ([#1172](https://github.com/ipfs/js-ipfs/issues/1172)) ([639024c](https://github.com/ipfs/js-ipfs/commit/639024c)) + + + ## [0.27.6](https://github.com/ipfs/js-ipfs/compare/v0.27.5...v0.27.6) (2018-01-07) diff --git a/package.json b/package.json index 7ec29b7b17..937b07c496 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ipfs", - "version": "0.27.6", + "version": "0.27.7", "description": "JavaScript implementation of the IPFS specification", "bin": { "jsipfs": "src/cli/bin.js" From 8c63f8f5c61448a4bed289af863cee7021d4a935 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Tue, 23 Jan 2018 16:30:06 +0100 Subject: [PATCH 13/32] fix(cli): show help for subcommands If subcommands are called, e.g. `jsipfs dag` there was no output at all. Now the help message (which you also get with `--help` is displayed. --- src/cli/commands/bitswap.js | 3 +-- src/cli/commands/block.js | 2 +- src/cli/commands/bootstrap.js | 2 +- src/cli/commands/dag.js | 2 +- src/cli/commands/file.js | 2 +- src/cli/commands/files.js | 2 +- src/cli/commands/object.js | 2 +- src/cli/commands/pubsub.js | 2 +- src/cli/commands/repo.js | 2 +- src/cli/commands/swarm.js | 2 +- 10 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/cli/commands/bitswap.js b/src/cli/commands/bitswap.js index c262ffc77b..b03e5b3623 100644 --- a/src/cli/commands/bitswap.js +++ b/src/cli/commands/bitswap.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'bitswap', + command: 'bitswap ', description: 'Interact with the bitswap agent.', @@ -10,6 +10,5 @@ module.exports = { }, handler (argv) { - console.log('Type `jsipfs bitswap --help` for more information about this command') } } diff --git a/src/cli/commands/block.js b/src/cli/commands/block.js index 599e202b7a..e843a00cb9 100644 --- a/src/cli/commands/block.js +++ b/src/cli/commands/block.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'block', + command: 'block ', description: 'Manipulate raw IPFS blocks.', diff --git a/src/cli/commands/bootstrap.js b/src/cli/commands/bootstrap.js index 0e2ad80d85..8c3324e466 100644 --- a/src/cli/commands/bootstrap.js +++ b/src/cli/commands/bootstrap.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'bootstrap', + command: 'bootstrap ', description: 'Show or edit the list of bootstrap peers.', diff --git a/src/cli/commands/dag.js b/src/cli/commands/dag.js index d3653920fc..3f15156884 100644 --- a/src/cli/commands/dag.js +++ b/src/cli/commands/dag.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'dag', + command: 'dag ', description: 'Interact with ipld dag objects.', diff --git a/src/cli/commands/file.js b/src/cli/commands/file.js index 5bc4dcf93f..0c178f0cd2 100644 --- a/src/cli/commands/file.js +++ b/src/cli/commands/file.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'file', + command: 'file ', description: 'Interact with IPFS objects representing Unix filesystems.', diff --git a/src/cli/commands/files.js b/src/cli/commands/files.js index b72d78534f..09ca4de380 100644 --- a/src/cli/commands/files.js +++ b/src/cli/commands/files.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'files', + command: 'files ', description: 'Operations over files (add, cat, get, ls, etc)', diff --git a/src/cli/commands/object.js b/src/cli/commands/object.js index 9f29944eff..753e934e07 100644 --- a/src/cli/commands/object.js +++ b/src/cli/commands/object.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'object', + command: 'object ', description: 'Interact with ipfs objects.', diff --git a/src/cli/commands/pubsub.js b/src/cli/commands/pubsub.js index dac25c7690..aa282c323f 100644 --- a/src/cli/commands/pubsub.js +++ b/src/cli/commands/pubsub.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'pubsub', + command: 'pubsub ', description: 'pubsub commands', diff --git a/src/cli/commands/repo.js b/src/cli/commands/repo.js index e67ebfa3e7..18873a7f44 100644 --- a/src/cli/commands/repo.js +++ b/src/cli/commands/repo.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'repo', + command: 'repo ', description: 'Manipulate the IPFS repo.', diff --git a/src/cli/commands/swarm.js b/src/cli/commands/swarm.js index dc7cd291d1..ea5d2d5080 100644 --- a/src/cli/commands/swarm.js +++ b/src/cli/commands/swarm.js @@ -1,7 +1,7 @@ 'use strict' module.exports = { - command: 'swarm', + command: 'swarm ', description: 'Swarm inspection tool.', From e776dfdb4de6be4ac818395b03b719dda7b4c483 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Tue, 23 Jan 2018 19:54:32 +0100 Subject: [PATCH 14/32] chore: change from pre-commit to pre-push hooks Instead of running the linting and tests on pre-commit, do it on pre-push. That makes it less frequent (and annoying) while doing local development. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 937b07c496..0996573523 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "coverage": "aegir coverage", "coverage-publish": "aegir-coverage publish" }, - "pre-commit": [ + "pre-push": [ "lint", "test" ], From bbb7cc5620681a95225161acf09955195d24ba4d Mon Sep 17 00:00:00 2001 From: Victor Bjelkholm Date: Tue, 23 Jan 2018 17:36:34 +0100 Subject: [PATCH 15/32] fix: (cli/init) use cross-platform path separator This fixes the command "init" on windows. Before this change, none of the files where actually added to your local repository. With this change, files are correctly added to the repository as windows uses "\" as the path separator instead of "/" (posix) --- src/core/components/init-assets.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/init-assets.js b/src/core/components/init-assets.js index af47565d20..945c47f5b4 100644 --- a/src/core/components/init-assets.js +++ b/src/core/components/init-assets.js @@ -11,7 +11,7 @@ const CID = require('cids') // Add the default assets to the repo. module.exports = function addDefaultAssets (self, log, callback) { const initDocsPath = path.join(__dirname, '../../init-files/init-docs') - const index = initDocsPath.lastIndexOf('/') + const index = initDocsPath.lastIndexOf(path.sep) pull( pull.values([initDocsPath]), From d16a129956bfce191dbfce48c92f99a9717feeaf Mon Sep 17 00:00:00 2001 From: Dmitriy Ryajov Date: Wed, 24 Jan 2018 11:18:00 -0600 Subject: [PATCH 16/32] feat: reworking tests with new ipfsd-ctl (#1167) --- .aegir.js | 38 ++--- package.json | 7 +- test/cli/pubsub.js | 56 +++++-- test/cli/swarm.js | 30 +++- test/core/bitswap.spec.js | 93 ++++++----- test/core/bootstrap.spec.js | 37 ++--- test/core/circuit-relay.spec.js | 145 ------------------ test/core/files-sharding.spec.js | 34 ++-- test/core/interface/block.js | 28 +++- test/core/interface/config.js | 29 +++- test/core/interface/dag.js | 29 +++- test/core/interface/dht.js | 24 ++- test/core/interface/files.js | 28 +++- test/core/interface/generic.js | 29 +++- test/core/interface/object.js | 29 +++- test/core/interface/pubsub.js | 29 +++- test/core/interface/swarm.js | 39 ++++- test/core/kad-dht.node.js | 43 ++++-- test/http-api/interface/block.js | 23 ++- test/http-api/interface/config.js | 23 ++- test/http-api/interface/files.js | 23 ++- test/http-api/interface/object.js | 23 ++- test/http-api/interface/pubsub.js | 24 ++- test/http-api/interface/swarm.js | 33 +++- test/utils/another-daemon-spawner.js | 73 --------- .../ipfs-factory-daemon/default-config.json | 41 ----- test/utils/ipfs-factory-daemon/index.js | 79 ---------- .../ipfs-factory-instance/default-config.json | 29 ---- test/utils/ipfs-factory-instance/index.js | 63 -------- test/utils/on-and-off.js | 17 +- 30 files changed, 522 insertions(+), 676 deletions(-) delete mode 100644 test/core/circuit-relay.spec.js delete mode 100644 test/utils/another-daemon-spawner.js delete mode 100644 test/utils/ipfs-factory-daemon/default-config.json delete mode 100644 test/utils/ipfs-factory-daemon/index.js delete mode 100644 test/utils/ipfs-factory-instance/default-config.json delete mode 100644 test/utils/ipfs-factory-instance/index.js diff --git a/.aegir.js b/.aegir.js index 148ab3fbb8..6a0af49287 100644 --- a/.aegir.js +++ b/.aegir.js @@ -1,41 +1,23 @@ 'use strict' -const parallel = require('async/parallel') -const ads = require('./test/utils/another-daemon-spawner') -const js = ads.spawnJsNode -const stop = ads.stopNodes - -/* - * spawns a daemon with ports numbers starting in 10 and ending in `num` - */ -function start (done) { - const base = '/ip4/127.0.0.1/tcp' - if (!process.env.IPFS_TEST) { - parallel([ - (cb) => js([`${base}/10007`, `${base}/20007/ws`], true, 31007, 32007, cb), - (cb) => js([`${base}/10008`, `${base}/20008/ws`], true, 31008, 32008, cb), - (cb) => js([`${base}/10012`, `${base}/20012/ws`], true, 31012, 32012, cb), - (cb) => js([`${base}/10013`, `${base}/20013/ws`], true, 31013, 32013, cb), - (cb) => js([`${base}/10014`, `${base}/20014/ws`], true, 31014, 32014, cb), - (cb) => js([`${base}/10015`, `${base}/20015/ws`], true, 31015, 32015, cb) - ], done) - } else if (process.env.IPFS_TEST === 'bootstrapers') { - done() - } -} +const createServer = require('ipfsd-ctl').createServer +const server = createServer() module.exports = { karma: { files: [{ pattern: 'node_modules/interface-ipfs-core/test/fixtures/**/*', watched: false, served: true, - included: false, - singleRun: false - }] + included: false + }], + browserNoActivityTimeout: 100 * 1000, + singleRun: true }, hooks: { - pre: start, - post: stop + browser: { + pre: server.start.bind(server), + post: server.stop.bind(server) + } } } diff --git a/package.json b/package.json index 0996573523..dc7d2a1519 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "build": "aegir build", "test": "aegir test -t node -t browser -t webworker --no-cors", "test:node": "aegir test -t node", - "test:browser": "aegir test -t browser -t webworker --no-cors", + "test:browser": "aegir test -t browser --no-cors", + "test:webworker": "aegir test -t webworker --no-cors", "test:node:core": "aegir test -t node -f test/core/**.js", "test:node:http": "aegir test -t node -f test/http-api/index.js", "test:node:gateway": "aegir test -t node -f test/gateway/index.js", @@ -70,8 +71,10 @@ "execa": "^0.9.0", "expose-loader": "^0.7.4", "form-data": "^2.3.1", + "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", - "interface-ipfs-core": "~0.40.0", + "interface-ipfs-core": "~0.41.0", + "ipfsd-ctl": "^0.27.0", "left-pad": "^1.2.0", "lodash": "^4.17.4", "mocha": "^4.1.0", diff --git a/test/cli/pubsub.js b/test/cli/pubsub.js index 3df5bf8417..8bf14731fa 100644 --- a/test/cli/pubsub.js +++ b/test/cli/pubsub.js @@ -8,16 +8,28 @@ const expect = chai.expect chai.use(dirtyChai) const delay = require('delay') const series = require('async/series') -const InstanceFactory = require('../utils/ipfs-factory-instance') -const DaemonFactory = require('../utils/ipfs-factory-daemon') const ipfsExec = require('../utils/ipfs-exec') +const IPFS = require('../../src') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'js' }) + +const config = { + Bootstrap: [], + Discovery: { + MDNS: { + Enabled: + false + } + } +} describe('pubsub', function () { - this.timeout(40 * 1000) + this.timeout(80 * 1000) - let instanceFactory - let daemonFactory let node + let ipfsdA + let ipfsdB let cli let httpApi @@ -28,26 +40,38 @@ describe('pubsub', function () { before(function (done) { this.timeout(60 * 1000) - instanceFactory = new InstanceFactory() - instanceFactory.spawnNode((err, _node) => { - expect(err).to.not.exist() - node = _node - done() - }) + DaemonFactory + .create({ type: 'proc' }) + .spawn({ + exec: IPFS, + config, + args: ['--enable-pubsub-experiment'] + }, (err, _ipfsd) => { + expect(err).to.not.exist() + ipfsdA = _ipfsd + node = _ipfsd.api + done() + }) }) - after((done) => instanceFactory.dismantle(done)) + after((done) => ipfsdB.stop(done)) before((done) => { - daemonFactory = new DaemonFactory() - daemonFactory.spawnNode((err, _node) => { + df.spawn({ + args: ['--enable-pubsub-experiment'], + exec: `./src/cli/bin.js`, + config + }, (err, _ipfsd) => { expect(err).to.not.exist() - httpApi = _node + httpApi = _ipfsd.api + ipfsdB = _ipfsd + httpApi.repoPath = ipfsdB.repoPath done() }) }) - after((done) => daemonFactory.dismantle(done)) + after((done) => ipfsdA.stop(done)) + after((done) => ipfsdB.stop(done)) before((done) => { cli = ipfsExec(httpApi.repoPath) diff --git a/test/cli/swarm.js b/test/cli/swarm.js index d2c69846be..424734c194 100644 --- a/test/cli/swarm.js +++ b/test/cli/swarm.js @@ -8,34 +8,48 @@ const expect = chai.expect chai.use(dirtyChai) const series = require('async/series') const ipfsExec = require('../utils/ipfs-exec') -const Factory = require('../utils/ipfs-factory-daemon') + +const parallel = require('async/parallel') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'js' }) + +const config = { + Bootstrap: [], + Discovery: { + MDNS: { + Enabled: + false + } + } +} describe('swarm', () => { - let factory let bMultiaddr let ipfsA + let nodes = [] before(function (done) { // CI takes longer to instantiate the daemon, so we need to increase the // timeout for the before step this.timeout(80 * 1000) - factory = new Factory() - series([ (cb) => { - factory.spawnNode((err, node) => { + df.spawn({ exec: `./src/cli/bin.js`, config }, (err, node) => { expect(err).to.not.exist() ipfsA = ipfsExec(node.repoPath) + nodes.push(node) cb() }) }, (cb) => { - factory.spawnNode((err, node) => { + df.spawn({ exec: `./src/cli/bin.js`, config }, (err, node) => { expect(err).to.not.exist() - node.id((err, id) => { + node.api.id((err, id) => { expect(err).to.not.exist() bMultiaddr = id.addresses[0] + nodes.push(node) cb() }) }) @@ -43,7 +57,7 @@ describe('swarm', () => { ], done) }) - after((done) => factory.dismantle(done)) + after((done) => parallel(nodes.map((node) => (cb) => node.stop(cb)), done)) describe('daemon on (through http-api)', function () { this.timeout(60 * 1000) diff --git a/test/core/bitswap.spec.js b/test/core/bitswap.spec.js index 2dffff99bc..b06b4c41f8 100644 --- a/test/core/bitswap.spec.js +++ b/test/core/bitswap.spec.js @@ -10,14 +10,17 @@ const _ = require('lodash') const series = require('async/series') const waterfall = require('async/waterfall') const parallel = require('async/parallel') -const leftPad = require('left-pad') const Block = require('ipfs-block') -const API = require('ipfs-api') const multiaddr = require('multiaddr') const isNode = require('detect-node') const multihashing = require('multihashing-async') const CID = require('cids') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'js' }) + +const dfProc = DaemonFactory.create({ type: 'proc' }) + // This gets replaced by '../utils/create-repo-browser.js' in the browser const createTempRepo = require('../utils/create-repo-nodejs.js') @@ -63,13 +66,27 @@ function connectNodes (remoteNode, inProcNode, callback) { ], callback) } -function addNode (num, inProcNode, callback) { - num = leftPad(num, 3, 0) - - const apiUrl = `/ip4/127.0.0.1/tcp/31${num}` - const remoteNode = new API(apiUrl) - - connectNodes(remoteNode, inProcNode, (err) => callback(err, remoteNode)) +let nodes = [] + +function addNode (inProcNode, callback) { + df.spawn({ + exec: `./src/cli/bin.js`, + config: { + Addresses: { + Swarm: [`/ip4/127.0.0.1/tcp/0/ws`] + }, + Discovery: { + MDNS: { + Enabled: false + } + }, + Bootstrap: [] + } + }, (err, ipfsd) => { + expect(err).to.not.exist() + nodes.push(ipfsd) + connectNodes(ipfsd.api, inProcNode, (err) => callback(err, ipfsd.api)) + }) } describe('bitswap', function () { @@ -80,23 +97,20 @@ describe('bitswap', function () { beforeEach(function (done) { this.timeout(60 * 1000) - let options = { - repo: createTempRepo(), - config: { - Addresses: { - Swarm: [] - }, - Discovery: { - MDNS: { - Enabled: false - } - }, - Bootstrap: [] - } + let config = { + Addresses: { + Swarm: [] + }, + Discovery: { + MDNS: { + Enabled: false + } + }, + Bootstrap: [] } if (isNode) { - options = Object.assign(options, { + config = Object.assign({}, config, { config: { Addresses: { Swarm: ['/ip4/127.0.0.1/tcp/0'] @@ -105,25 +119,34 @@ describe('bitswap', function () { }) } - inProcNode = new IPFS(options) - inProcNode.on('ready', () => done()) + dfProc.spawn({ exec: IPFS, config }, (err, _ipfsd) => { + expect(err).to.not.exist() + nodes.push(_ipfsd) + inProcNode = _ipfsd.api + done() + }) }) afterEach(function (done) { - this.timeout(60 * 1000) - setTimeout(() => inProcNode.stop(() => done()), 500) + this.timeout(80 * 1000) + const tasks = nodes.map((node) => (cb) => node.stop(cb)) + parallel(tasks, (err) => { + expect(err).to.not.exist() + nodes = [] + done() + }) }) describe('transfer a block between', () => { it('2 peers', function (done) { - this.timeout(40 * 1000) + this.timeout(80 * 1000) let remoteNode let block waterfall([ (cb) => parallel([ (cb) => makeBlock(cb), - (cb) => addNode(13, inProcNode, cb) + (cb) => addNode(inProcNode, cb) ], cb), (res, cb) => { block = res[0] @@ -140,7 +163,7 @@ describe('bitswap', function () { }) it('3 peers', function (done) { - this.timeout(60 * 1000) + this.timeout(80 * 1000) let blocks const remoteNodes = [] @@ -151,11 +174,11 @@ describe('bitswap', function () { blocks = _blocks cb() }), - (cb) => addNode(8, inProcNode, (err, _ipfs) => { + (cb) => addNode(inProcNode, (err, _ipfs) => { remoteNodes.push(_ipfs) cb(err) }), - (cb) => addNode(7, inProcNode, (err, _ipfs) => { + (cb) => addNode(inProcNode, (err, _ipfs) => { remoteNodes.push(_ipfs) cb(err) }), @@ -193,10 +216,10 @@ describe('bitswap', function () { waterfall([ // 0. Start node - (cb) => addNode(12, inProcNode, cb), + (cb) => addNode(inProcNode, cb), // 1. Add file to tmp instance (remote, cb) => { - remote.files.add([{path: 'awesome.txt', content: file}], cb) + remote.files.add([{ path: 'awesome.txt', content: file }], cb) }, // 2. Request file from local instance (filesAdded, cb) => inProcNode.files.cat(filesAdded[0].hash, cb) @@ -247,7 +270,7 @@ describe('bitswap', function () { describe('while online', () => { before(function (done) { - this.timeout(40 * 1000) + this.timeout(80 * 1000) node.start(() => done()) }) diff --git a/test/core/bootstrap.spec.js b/test/core/bootstrap.spec.js index 3f291c5696..6abe498cf2 100644 --- a/test/core/bootstrap.spec.js +++ b/test/core/bootstrap.spec.js @@ -7,42 +7,37 @@ const expect = chai.expect chai.use(dirtyChai) const isNode = require('detect-node') +const IPFS = require('../../src') -// This gets replaced by `create-repo-browser.js` in the browser -const createTempRepo = require('../utils/create-repo-nodejs.js') - -const IPFS = require('../../src/core') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc' }) describe('bootstrap', () => { - if (!isNode) { return } + if (!isNode) { + return + } let node + let ipfsd before(function (done) { this.timeout(40 * 1000) - node = new IPFS({ - repo: createTempRepo(), - init: { - bits: 1024 - }, - EXPERIMENTAL: { - pubsub: true - }, + df.spawn({ + exec: IPFS, config: { Addresses: { Swarm: ['/ip4/127.0.0.1/tcp/0'] } } - }) - - node.on('error', (err) => { + }, (err, _ipfsd) => { expect(err).to.not.exist() + ipfsd = _ipfsd + node = _ipfsd.api + done() }) - - node.on('start', done) }) - after((done) => node.stop(done)) + after((done) => ipfsd.stop(done)) const defaultList = [ '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', @@ -80,7 +75,7 @@ describe('bootstrap', () => { it('add a peer to the bootstrap list', (done) => { node.bootstrap.add('/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT', (err, res) => { expect(err).to.not.exist() - expect(res).to.be.eql({Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT']}) + expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT'] }) node.bootstrap.list((err, list) => { expect(err).to.not.exist() expect(list.Peers).to.deep.equal(updatedList) @@ -92,7 +87,7 @@ describe('bootstrap', () => { it('remove a peer from the bootstrap list', (done) => { node.bootstrap.rm('/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT', (err, res) => { expect(err).to.not.exist() - expect(res).to.be.eql({Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT']}) + expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT'] }) node.bootstrap.list((err, list) => { expect(err).to.not.exist() expect(list.Peers).to.deep.equal(defaultList) diff --git a/test/core/circuit-relay.spec.js b/test/core/circuit-relay.spec.js deleted file mode 100644 index 4934b5cadb..0000000000 --- a/test/core/circuit-relay.spec.js +++ /dev/null @@ -1,145 +0,0 @@ -/* eslint max-nested-callbacks: ["error", 8] */ -/* eslint-env mocha */ -'use strict' - -const chai = require('chai') -const dirtyChai = require('dirty-chai') -const expect = chai.expect -chai.use(dirtyChai) -const parallel = require('async/parallel') -const series = require('async/series') -const waterfall = require('async/waterfall') -const API = require('ipfs-api') -const bl = require('bl') -const PeerInfo = require('peer-info') -const PeerId = require('peer-id') -const multiaddr = require('multiaddr') -const isNode = require('detect-node') -const crypto = require('crypto') -const IPFSFactory = require('../utils/ipfs-factory-instance') - -function peerInfoFromObj (obj, callback) { - waterfall([ - (cb) => PeerInfo.create(PeerId.createFromB58String(obj.id), cb), - (peer, cb) => { - obj.addresses.forEach((a) => peer.multiaddrs.add(multiaddr(a))) - cb(null, peer) - } - ], callback) -} - -describe.skip('circuit', function () { - this.timeout(40 * 1000) - - let factory - - let jsRelay = new API(`/ip4/127.0.0.1/tcp/31015`) - // let goRelay = new API(`/ip4/127.0.0.1/tcp/33031`) - let node1 - let node2 - - let jsRelayId - let goRelayId - - // let nodeId1 - let nodeId2 - - before(function (done) { - this.timeout(40 * 1000) - - factory = new IPFSFactory() - - const base = { - EXPERIMENTAL: { - Relay: { - Enabled: true - } - }, - Addresses: { - Swarm: [] - } - } - - parallel([ - (cb) => factory.spawnNode(null, Object.assign(base, { - Addresses: { - Swarm: [ (isNode ? `/ip4/127.0.0.1/tcp/0` : '') ] - } - }), cb), - (cb) => factory.spawnNode(null, Object.assign(base, { - Addresses: { - Swarm: [ (isNode ? `/ip4/127.0.0.1/tcp/0/ws` : '') ] - } - }), cb) - ], (err, nodes) => { - expect(err).to.not.exist() - node1 = nodes[0] - node2 = nodes[1] - - parallel([ - (cb) => jsRelay.id(cb), - // (cb) => goRelay.id(cb), - (cb) => node1.id(cb), - (cb) => node2.id(cb) - ], (err, res2) => { - expect(err).to.not.exist() - parallel([ - (cb) => peerInfoFromObj(res2[0], cb), - // (cb) => peerInfoFromObj(res2[1], cb), - (cb) => peerInfoFromObj(res2[1], cb), - (cb) => peerInfoFromObj(res2[2], cb) - ], (err, res3) => { - expect(err).to.not.exist() - jsRelayId = res3[0] - // goRelayId = res3[1] - // nodeId1 = res3[2] - nodeId2 = res3[2] - done() - }) - }) - }) - }) - - after((done) => factory.dismantle(done)) - - // TODO: 1) figure out why this test hangs randomly - // TODO: 2) move this test to the interop batch - it.skip('node1 <-> goRelay <-> node2', (done) => { - const data = crypto.randomBytes(128) - - series([ - (cb) => node1.swarm.connect(goRelayId, cb), - (cb) => setTimeout(cb, 1000), - (cb) => node2.swarm.connect(goRelayId, cb), - (cb) => setTimeout(cb, 1000), - (cb) => node1.swarm.connect(nodeId2, cb) - ], (err) => { - expect(err).to.not.exist() - waterfall([ - (cb) => node1.files.add(data, cb), - (filesAdded, cb) => node2.files.cat(filesAdded[0].hash, cb), - (stream, cb) => stream.pipe(bl(cb)) - ], done) - }) - }) - - it('node1 <-> jsRelay <-> node2', (done) => { - const data = crypto.randomBytes(128) - - series([ - (cb) => node1.swarm.connect(jsRelayId, cb), - (cb) => setTimeout(cb, 1000), - (cb) => node2.swarm.connect(jsRelayId, cb), - (cb) => setTimeout(cb, 1000), - (cb) => node1.swarm.connect(nodeId2, cb) - ], (err) => { - expect(err).to.not.exist() - - waterfall([ - (cb) => node1.files.add(data, cb), - (filesAdded, cb) => node2.files.cat(filesAdded[0].hash, cb), - (stream, cb) => stream.pipe(bl(cb)) - ], done) - }) - }) -}) diff --git a/test/core/files-sharding.spec.js b/test/core/files-sharding.spec.js index aaf97c8b64..156dbf4442 100644 --- a/test/core/files-sharding.spec.js +++ b/test/core/files-sharding.spec.js @@ -9,7 +9,9 @@ chai.use(dirtyChai) const pull = require('pull-stream') const IPFS = require('../../src/core') -const createTempRepo = require('../utils/create-repo-nodejs.js') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc' }) describe('files directory (sharding tests)', () => { function createTestFiles () { @@ -27,12 +29,13 @@ describe('files directory (sharding tests)', () => { describe('without sharding', () => { let ipfs + let ipfsd before(function (done) { this.timeout(40 * 1000) - ipfs = new IPFS({ - repo: createTempRepo(), + df.spawn({ + exec: IPFS, config: { Addresses: { Swarm: [] @@ -44,13 +47,17 @@ describe('files directory (sharding tests)', () => { } } } + }, (err, _ipfsd) => { + expect(err).to.not.exist() + ipfsd = _ipfsd + ipfs = _ipfsd.api + done() }) - ipfs.once('ready', done) }) after(function (done) { this.timeout(40 * 1000) - ipfs.stop(done) + ipfsd.stop(done) }) it('should be able to add dir without sharding', function (done) { @@ -72,12 +79,14 @@ describe('files directory (sharding tests)', () => { describe('with sharding', () => { let ipfs + let ipfsd before(function (done) { this.timeout(40 * 1000) - ipfs = new IPFS({ - repo: createTempRepo(), + df.spawn({ + exec: IPFS, + args: ['--enable-sharding-experiment'], config: { Addresses: { Swarm: [] @@ -88,17 +97,18 @@ describe('files directory (sharding tests)', () => { Enabled: false } } - }, - EXPERIMENTAL: { - sharding: true } + }, (err, _ipfsd) => { + expect(err).to.not.exist() + ipfsd = _ipfsd + ipfs = _ipfsd.api + done() }) - ipfs.once('ready', done) }) after(function (done) { this.timeout(40 * 1000) - ipfs.stop(done) + ipfsd.stop(done) }) it('should be able to add dir with sharding', function (done) { diff --git a/test/core/interface/block.js b/test/core/interface/block.js index fafb7f7e70..5246ce3734 100644 --- a/test/core/interface/block.js +++ b/test/core/interface/block.js @@ -2,17 +2,31 @@ 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') -let factory +const IPFS = require('../../../src') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) + +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/config.js b/test/core/interface/config.js index 80b0c76d9e..1408e2281f 100644 --- a/test/core/interface/config.js +++ b/test/core/interface/config.js @@ -1,19 +1,32 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/dag.js b/test/core/interface/dag.js index cab259b00a..4e384cb105 100644 --- a/test/core/interface/dag.js +++ b/test/core/interface/dag.js @@ -1,19 +1,32 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/dht.js b/test/core/interface/dht.js index 28e6bb7658..532f3f4829 100644 --- a/test/core/interface/dht.js +++ b/test/core/interface/dht.js @@ -1,22 +1,32 @@ /* eslint-env mocha */ - 'use strict' /* const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { setup: function (callback) { - factory = new IPFSFactory() - callback(null, factory) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - factory.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } - test.dht(common) */ diff --git a/test/core/interface/files.js b/test/core/interface/files.js index 5c7c7f391c..29fc97c530 100644 --- a/test/core/interface/files.js +++ b/test/core/interface/files.js @@ -2,17 +2,31 @@ 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') -let factory +const IPFS = require('../../../src') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) + +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/generic.js b/test/core/interface/generic.js index d2c8825a11..9af526e58b 100644 --- a/test/core/interface/generic.js +++ b/test/core/interface/generic.js @@ -1,19 +1,32 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/object.js b/test/core/interface/object.js index 97ac3e3b64..32ef8e0251 100644 --- a/test/core/interface/object.js +++ b/test/core/interface/object.js @@ -1,19 +1,32 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/pubsub.js b/test/core/interface/pubsub.js index 4264b0c96b..2425f862d9 100644 --- a/test/core/interface/pubsub.js +++ b/test/core/interface/pubsub.js @@ -2,17 +2,32 @@ 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') -let factory +const IPFS = require('../../../src') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) + +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn({ args: ['--enable-pubsub-experiment'] }, + (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/interface/swarm.js b/test/core/interface/swarm.js index 15da9f484a..d5158701d8 100644 --- a/test/core/interface/swarm.js +++ b/test/core/interface/swarm.js @@ -1,19 +1,42 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const IPFSFactory = require('../../utils/ipfs-factory-instance') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') -let factory +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const nodes = [] const common = { - setup: function (cb) { - factory = new IPFSFactory() - cb(null, factory) + setup: function (callback) { + callback(null, { + spawnNode: (repoPath, config, cb) => { + if (typeof repoPath === 'function') { + cb = repoPath + repoPath = undefined + } + + if (typeof config === 'function') { + cb = config + config = undefined + } + + df.spawn({ repoPath, config }, (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, - teardown: function (cb) { - factory.dismantle(cb) + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/core/kad-dht.node.js b/test/core/kad-dht.node.js index 1bd0123575..db91cdc168 100644 --- a/test/core/kad-dht.node.js +++ b/test/core/kad-dht.node.js @@ -7,10 +7,29 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const parallel = require('async/parallel') -const IPFSFactory = require('../utils/ipfs-factory-instance') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'js' }) + +const config = { + Addresses: { + Swarm: [`/ip4/127.0.0.1/tcp/0`, `/ip4/127.0.0.1/tcp/0/ws`], + API: `/ip4/127.0.0.1/tcp/0`, + Gateway: `/ip4/127.0.0.1/tcp/0` + }, + Bootstrap: [], + Discovery: { + MDNS: { + Enabled: false + } + } +} + +function createNode (callback) { + df.spawn({ exec: './src/cli/bin.js', config }, callback) +} describe('verify that kad-dht is doing its thing', () => { - let factory let nodeA let nodeB let nodeC @@ -18,18 +37,18 @@ describe('verify that kad-dht is doing its thing', () => { let addrB let addrC + let nodes before((done) => { - factory = new IPFSFactory() - parallel([ - (cb) => factory.spawnNode(cb), - (cb) => factory.spawnNode(cb), - (cb) => factory.spawnNode(cb) - ], (err, nodes) => { + (cb) => createNode(cb), + (cb) => createNode(cb), + (cb) => createNode(cb) + ], (err, _nodes) => { expect(err).to.not.exist() - nodeA = nodes[0] - nodeB = nodes[1] - nodeC = nodes[2] + nodes = _nodes + nodeA = _nodes[0].api + nodeB = _nodes[1].api + nodeC = _nodes[2].api parallel([ (cb) => nodeA.id(cb), (cb) => nodeB.id(cb), @@ -47,7 +66,7 @@ describe('verify that kad-dht is doing its thing', () => { }) }) - after((done) => factory.dismantle(done)) + after((done) => parallel(nodes.map((node) => (cb) => node.stop(cb)), done)) it.skip('add a file in C, fetch through B in A', function (done) { this.timeout(10 * 1000) diff --git a/test/http-api/interface/block.js b/test/http-api/interface/block.js index db39d378c6..9b5af8aa1a 100644 --- a/test/http-api/interface/block.js +++ b/test/http-api/interface/block.js @@ -1,19 +1,30 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/config.js b/test/http-api/interface/config.js index 30837f8b86..2dc5e28c9f 100644 --- a/test/http-api/interface/config.js +++ b/test/http-api/interface/config.js @@ -1,19 +1,30 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/files.js b/test/http-api/interface/files.js index 84b150f79f..8b67070415 100644 --- a/test/http-api/interface/files.js +++ b/test/http-api/interface/files.js @@ -1,19 +1,30 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/object.js b/test/http-api/interface/object.js index e00df72564..5db1e53f97 100644 --- a/test/http-api/interface/object.js +++ b/test/http-api/interface/object.js @@ -1,19 +1,30 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/pubsub.js b/test/http-api/interface/pubsub.js index ab474fac9f..b058c1a63c 100644 --- a/test/http-api/interface/pubsub.js +++ b/test/http-api/interface/pubsub.js @@ -1,19 +1,31 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (cb) => { + df.spawn({ args: ['--enable-pubsub-experiment'] }, + (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/http-api/interface/swarm.js b/test/http-api/interface/swarm.js index eeca079124..e2a9b657c7 100644 --- a/test/http-api/interface/swarm.js +++ b/test/http-api/interface/swarm.js @@ -1,19 +1,40 @@ /* eslint-env mocha */ - 'use strict' const test = require('interface-ipfs-core') -const FactoryClient = require('./../../utils/ipfs-factory-daemon') +const parallel = require('async/parallel') -let fc +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const nodes = [] const common = { setup: function (callback) { - fc = new FactoryClient() - callback(null, fc) + callback(null, { + spawnNode: (repoPath, config, cb) => { + if (typeof repoPath === 'function') { + cb = repoPath + repoPath = undefined + } + + if (typeof config === 'function') { + cb = config + config = undefined + } + + df.spawn({ repoPath, config }, (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) }, teardown: function (callback) { - fc.dismantle(callback) + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) } } diff --git a/test/utils/another-daemon-spawner.js b/test/utils/another-daemon-spawner.js deleted file mode 100644 index 5d55be3295..0000000000 --- a/test/utils/another-daemon-spawner.js +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-env mocha */ - -'use strict' - -const waterfall = require('async/waterfall') -const series = require('async/series') - -const relayConfig = require('./ipfs-factory-daemon/default-config.json') -const Factory = require('./ipfs-factory-daemon') - -const nodes = [] -const factory = new Factory() -exports = module.exports - -exports.spawnJsNode = (addrs, hop, api, gateway, callback) => { - let relayPeer - let relayAddrs - - if (typeof hop === 'function') { - callback = hop - hop = false - } - if (typeof api === 'function') { - callback = api - api = 0 - } - if (typeof gateway === 'function') { - callback = gateway - gateway = 0 - } - - api = api || 0 - gateway = gateway || 0 - - callback = callback || function noop () {} - - waterfall([ - (cb) => factory.spawnNode(null, Object.assign(relayConfig, { - Addresses: { - Swarm: addrs, - API: `/ip4/0.0.0.0/tcp/${api}`, - Gateway: `/ip4/0.0.0.0/tcp/${gateway}` - }, - EXPERIMENTAL: { - Swarm: { - DisableRelay: false, - EnableRelayHop: hop - } - } - }), cb), - (node, cb) => { - relayPeer = node - relayPeer.swarm.localAddrs(cb) - }, - (addrs, cb) => { - relayAddrs = addrs - cb() - } - ], (err) => { - if (err) { - return callback(err) - } - callback(null, relayPeer, relayAddrs) - }) -} - -exports.stopNodes = (callback) => { - series([ - (cb) => factory.dismantle(cb) - ].concat(nodes.map((node) => (cb) => { - setTimeout(() => node.stop(cb), 100) - })), callback) -} diff --git a/test/utils/ipfs-factory-daemon/default-config.json b/test/utils/ipfs-factory-daemon/default-config.json deleted file mode 100644 index f2203594df..0000000000 --- a/test/utils/ipfs-factory-daemon/default-config.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "Identity": { - "PeerID": "", - "PrivKey": "" - }, - "Addresses": { - "Swarm": [ - "/ip4/127.0.0.1/tcp/0" - ], - "API": "/ip4/127.0.0.1/tcp/0", - "Gateway": "/ip4/127.0.0.1/tcp/0" - }, - "Version": { - "Current": "jsipfs-dev", - "Check": "error", - "CheckDate": "0001-01-01T00:00:00Z", - "CheckPeriod": "172800000000000", - "AutoUpdate": "minor" - }, - "Discovery": { - "MDNS": { - "Enabled": false, - "Interval": 10 - }, - "webRTCStar": { - "Enabled": false - } - }, - "Bootstrap": [], - "Gateway": { - "HTTPHeaders": null, - "RootRedirect": "", - "Writable": false - }, - "API": { - "HTTPHeaders": null - }, - "Swarm": { - "AddrFilters": null - } -} diff --git a/test/utils/ipfs-factory-daemon/index.js b/test/utils/ipfs-factory-daemon/index.js deleted file mode 100644 index 2dde6d4eef..0000000000 --- a/test/utils/ipfs-factory-daemon/index.js +++ /dev/null @@ -1,79 +0,0 @@ -'use strict' - -const PeerId = require('peer-id') -const IPFSAPI = require('ipfs-api') -const clean = require('../clean') -const HttpApi = require('../../../src/http') -const series = require('async/series') -const eachSeries = require('async/eachSeries') -const defaultConfig = require('./default-config.json') -const os = require('os') -const hat = require('hat') - -class Factory { - constructor () { - this.daemonsSpawned = [] - } - - /* yields a new started node */ - spawnNode (repoPath, suppliedConfig, callback) { - if (typeof repoPath === 'function') { - callback = repoPath - repoPath = undefined - } - if (typeof suppliedConfig === 'function') { - callback = suppliedConfig - suppliedConfig = {} - } - - repoPath = repoPath || os.tmpdir() + '/ipfs-' + hat() - - let daemon - let ctl - let config - - series([ - (cb) => { - // prepare config for node - - config = Object.assign({}, defaultConfig, suppliedConfig) - - PeerId.create({ bits: 1024 }, (err, id) => { - if (err) { return cb(err) } - - const peerId = id.toJSON() - config.Identity.PeerID = peerId.id - config.Identity.PrivKey = peerId.privKey - cb() - }) - }, - (cb) => { - daemon = new HttpApi(repoPath, config, {enablePubsubExperiment: true}) - daemon.repoPath = repoPath - this.daemonsSpawned.push(daemon) - - daemon.start(true, cb) - }, - (cb) => { - ctl = IPFSAPI(daemon.apiMultiaddr) - ctl.repoPath = repoPath - ctl.apiMultiaddr = daemon.apiMultiaddr - cb() - } - ], (err) => callback(err, ctl)) - } - - dismantle (callback) { - eachSeries(this.daemonsSpawned, (d, cb) => { - d.stop((err) => { - clean(d.repoPath) - if (err) { - console.error('error stopping', err) - } - cb(err) - }) - }, callback) - } -} - -module.exports = Factory diff --git a/test/utils/ipfs-factory-instance/default-config.json b/test/utils/ipfs-factory-instance/default-config.json deleted file mode 100644 index 677c7c85d9..0000000000 --- a/test/utils/ipfs-factory-instance/default-config.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "Addresses": { - "Swarm": [ - "/ip4/127.0.0.1/tcp/0" - ], - "API": "/ip4/127.0.0.1/tcp/0", - "Gateway": "/ip4/127.0.0.1/tcp/0" - }, - "Version": { - "Current": "jsipfs-dev", - "Check": "error", - "CheckDate": "0001-01-01T00:00:00Z", - "CheckPeriod": "172800000000000", - "AutoUpdate": "minor" - }, - "Discovery": { - "MDNS": { - "Enabled": false, - "Interval": 10 - }, - "webRTCStar": { - "Enabled": false - } - }, - "Bootstrap": [], - "API": { - "HTTPHeaders": null - } -} diff --git a/test/utils/ipfs-factory-instance/index.js b/test/utils/ipfs-factory-instance/index.js deleted file mode 100644 index 568a1710a7..0000000000 --- a/test/utils/ipfs-factory-instance/index.js +++ /dev/null @@ -1,63 +0,0 @@ -'use strict' - -const series = require('async/series') -const each = require('async/each') -const hat = require('hat') -const os = require('os') -const path = require('path') - -const defaultConfig = require('./default-config.json') -const IPFS = require('../../../src/core') -const createTempRepo = require('../create-repo-nodejs') - -module.exports = Factory - -function Factory () { - if (!(this instanceof Factory)) { - return new Factory() - } - - const nodes = [] - - /* yields a new started node instance */ - this.spawnNode = (repoPath, suppliedConfig, callback) => { - if (typeof repoPath === 'function') { - callback = repoPath - repoPath = undefined - } - - if (typeof suppliedConfig === 'function') { - callback = suppliedConfig - suppliedConfig = {} - } - - if (!repoPath) { - repoPath = path.join(os.tmpdir(), '.ipfs-' + hat()) - } - - const config = Object.assign({}, defaultConfig, suppliedConfig) - - const repo = createTempRepo(repoPath) - const node = new IPFS({ - repo: repo, - init: { bits: 1024 }, - config: config, - EXPERIMENTAL: { - pubsub: true, - dht: true - } - }) - - node.once('ready', () => { - nodes.push({ repo: repo, ipfs: node }) - callback(null, node) - }) - } - - this.dismantle = function (callback) { - series([ - (cb) => each(nodes, (el, cb) => el.ipfs.stop(cb), cb), - (cb) => each(nodes, (el, cb) => el.repo.teardown(cb), cb) - ], callback) - } -} diff --git a/test/utils/on-and-off.js b/test/utils/on-and-off.js index 8a79c660ef..4aa6344eeb 100644 --- a/test/utils/on-and-off.js +++ b/test/utils/on-and-off.js @@ -1,7 +1,6 @@ /* eslint-env mocha */ 'use strict' -const Factory = require('../utils/ipfs-factory-daemon') const hat = require('hat') const chai = require('chai') const dirtyChai = require('dirty-chai') @@ -12,6 +11,9 @@ const ipfsExec = require('../utils/ipfs-exec') const clean = require('../utils/clean') const os = require('os') +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create() + function off (tests) { describe('daemon off (directly to core)', () => { let thing = {} @@ -27,7 +29,7 @@ function off (tests) { }) after(function (done) { - this.timeout(26 * 1000) + this.timeout(20 * 1000) clean(repoPath) setImmediate(done) }) @@ -38,19 +40,18 @@ function off (tests) { function on (tests) { describe('daemon on (through http-api)', () => { - let factory let thing = {} + let ipfsd before(function (done) { // CI takes longer to instantiate the daemon, // so we need to increase the timeout for the // before step this.timeout(60 * 1000) - factory = new Factory() - - factory.spawnNode((err, node) => { + df.spawn({ type: 'js', exec: `./src/cli/bin.js` }, (err, node) => { expect(err).to.not.exist() + ipfsd = node thing.ipfs = ipfsExec(node.repoPath) thing.ipfs.repoPath = node.repoPath done() @@ -58,8 +59,8 @@ function on (tests) { }) after(function (done) { - this.timeout(60 * 1000) - factory.dismantle(done) + this.timeout(15 * 1000) + ipfsd.stop(done) }) tests(thing) From cfa38cab7e71998cb16b13f1480ed3ad52728eea Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 26 Jan 2018 09:04:04 +0000 Subject: [PATCH 17/32] tests: add stats and update interface-ipfs-core (#1189) * tests: add stats and update interface-ipfs-core * chore: update interface-ipfs-core --- package.json | 2 +- test/core/interface/interface.spec.js | 1 + test/core/interface/stats.js | 33 +++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 test/core/interface/stats.js diff --git a/package.json b/package.json index dc7d2a1519..de9635ca59 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "form-data": "^2.3.1", "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", - "interface-ipfs-core": "~0.41.0", + "interface-ipfs-core": "~0.42.1", "ipfsd-ctl": "^0.27.0", "left-pad": "^1.2.0", "lodash": "^4.17.4", diff --git a/test/core/interface/interface.spec.js b/test/core/interface/interface.spec.js index 23e7dab09f..96815d2596 100644 --- a/test/core/interface/interface.spec.js +++ b/test/core/interface/interface.spec.js @@ -11,6 +11,7 @@ describe('interface-ipfs-core tests', () => { require('./generic') require('./object') require('./dag') + require('./stats') if (isNode) { require('./swarm') require('./pubsub') diff --git a/test/core/interface/stats.js b/test/core/interface/stats.js new file mode 100644 index 0000000000..ea8c10a68b --- /dev/null +++ b/test/core/interface/stats.js @@ -0,0 +1,33 @@ +/* eslint-env mocha */ +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) + +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.stats(common) From 3bca16536373eb6c4ca354f348ce7219026961e5 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Date: Fri, 26 Jan 2018 13:41:41 -0200 Subject: [PATCH 18/32] feat: Add /ip6 addresses to bootstrap Closes #706 License: MIT Signed-off-by: Paulo Rodrigues --- src/core/runtime/config-nodejs.json | 10 ++++++++++ test/cli/bootstrap.js | 22 +++++++++++++++++++++- test/core/bootstrap.spec.js | 20 ++++++++++++++++++++ test/fixtures/go-ipfs-repo/config | 10 ++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/core/runtime/config-nodejs.json b/src/core/runtime/config-nodejs.json index 9def4689e8..d1fc0f625d 100644 --- a/src/core/runtime/config-nodejs.json +++ b/src/core/runtime/config-nodejs.json @@ -17,6 +17,7 @@ } }, "Bootstrap": [ + "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", @@ -24,6 +25,15 @@ "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", + "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", + "/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", + "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", + "/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", + "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", + "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", + "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", + "/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", + "/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", "/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic", "/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6" ] diff --git a/test/cli/bootstrap.js b/test/cli/bootstrap.js index 85b7851dcb..8807a12411 100644 --- a/test/cli/bootstrap.js +++ b/test/cli/bootstrap.js @@ -1,4 +1,4 @@ -/* eslint max-nested-callbacks: ["error", 8] */ +/* eslint max-nested-callbacks: ['error', 8] */ /* eslint-env mocha */ 'use strict' @@ -13,6 +13,7 @@ describe('bootstrap', () => runOnAndOff((thing) => { }) const defaultList = [ + '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', '/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', '/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', @@ -20,11 +21,21 @@ describe('bootstrap', () => runOnAndOff((thing) => { '/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', '/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', '/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', + '/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', + '/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', + '/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', + '/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', + '/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', + '/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', + '/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6' ] const updatedList = [ + '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', '/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', '/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', @@ -32,6 +43,15 @@ describe('bootstrap', () => runOnAndOff((thing) => { '/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', '/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', '/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', + '/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', + '/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', + '/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', + '/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', + '/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', + '/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', + '/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6', '/ip4/111.111.111.111/tcp/1001/ipfs/QmcyFFKfLDGJKwufn2GeitxvhricsBQyNKTkrD14psikoD' diff --git a/test/core/bootstrap.spec.js b/test/core/bootstrap.spec.js index 6abe498cf2..e18ce0e8c0 100644 --- a/test/core/bootstrap.spec.js +++ b/test/core/bootstrap.spec.js @@ -40,6 +40,7 @@ describe('bootstrap', () => { after((done) => ipfsd.stop(done)) const defaultList = [ + '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', '/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', '/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', @@ -47,11 +48,21 @@ describe('bootstrap', () => { '/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', '/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', '/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', + '/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', + '/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', + '/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', + '/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', + '/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', + '/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', + '/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6' ] const updatedList = [ + '/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', '/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ', '/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', '/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', @@ -59,6 +70,15 @@ describe('bootstrap', () => { '/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', '/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', '/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', + '/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z', + '/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM', + '/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', + '/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', + '/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', + '/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', + '/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', + '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6', '/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT' diff --git a/test/fixtures/go-ipfs-repo/config b/test/fixtures/go-ipfs-repo/config index ab2f4da607..7498da51bf 100644 --- a/test/fixtures/go-ipfs-repo/config +++ b/test/fixtures/go-ipfs-repo/config @@ -47,6 +47,7 @@ "ResolveCacheSize":128 }, "Bootstrap":[ + "/ip4/104.236.176.52/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", "/ip4/162.243.248.213/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", @@ -54,6 +55,15 @@ "/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", "/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", "/ip4/178.62.61.185/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", + "/ip4/104.236.151.122/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", + "/ip6/2604:a880:1:20::1f9:9001/tcp/4001/ipfs/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z", + "/ip6/2604:a880:1:20::203:d001/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", + "/ip6/2604:a880:0:1010::23:d001/tcp/4001/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm", + "/ip6/2400:6180:0:d0::151:6001/tcp/4001/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu", + "/ip6/2604:a880:800:10::4a:5001/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64", + "/ip6/2a03:b0c0:0:1010::23:1001/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd", + "/ip6/2a03:b0c0:1:d0::e7:1/tcp/4001/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3", + "/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx", "/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic", "/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6" ], From d945fceeb09c1c4289a61edb40209271e8318d25 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Wed, 31 Jan 2018 07:48:08 +1300 Subject: [PATCH 19/32] feat: Implementation of the ipfs.key API (#1133) --- README.md | 17 +++++ package.json | 3 +- src/cli/bin.js | 7 +- src/cli/commands/init.js | 1 + src/cli/commands/key.js | 14 ++++ src/cli/commands/key/export.js | 37 ++++++++++ src/cli/commands/key/gen.js | 35 +++++++++ src/cli/commands/key/import.js | 34 +++++++++ src/cli/commands/key/list.js | 20 +++++ src/cli/commands/key/rename.js | 20 +++++ src/cli/commands/key/rm.js | 20 +++++ src/cli/utils.js | 7 +- src/core/boot.js | 5 +- src/core/components/index.js | 1 + src/core/components/init.js | 18 ++++- src/core/components/key.js | 46 ++++++++++++ src/core/components/no-keychain.js | 24 ++++++ src/core/components/pre-start.js | 47 +++++++++++- src/core/index.js | 1 + src/http/api/resources/index.js | 1 + src/http/api/resources/key.js | 102 ++++++++++++++++++++++++++ src/http/api/routes/index.js | 1 + src/http/api/routes/key.js | 43 +++++++++++ src/http/index.js | 1 + test/cli/commands.js | 3 +- test/cli/files.js | 1 + test/cli/key.js | 53 +++++++++++++ test/core/init.spec.js | 8 +- test/core/interface/interface.spec.js | 1 + test/core/interface/key.js | 36 +++++++++ test/core/key-exchange.js | 51 +++++++++++++ test/http-api/index.js | 6 +- test/http-api/interface/key.js | 35 +++++++++ 33 files changed, 683 insertions(+), 16 deletions(-) create mode 100644 src/cli/commands/key.js create mode 100644 src/cli/commands/key/export.js create mode 100644 src/cli/commands/key/gen.js create mode 100644 src/cli/commands/key/import.js create mode 100644 src/cli/commands/key/list.js create mode 100644 src/cli/commands/key/rename.js create mode 100644 src/cli/commands/key/rm.js create mode 100644 src/core/components/key.js create mode 100644 src/core/components/no-keychain.js create mode 100644 src/http/api/resources/key.js create mode 100644 src/http/api/routes/key.js create mode 100644 test/cli/key.js create mode 100644 test/core/interface/key.js create mode 100644 test/core/key-exchange.js create mode 100644 test/http-api/interface/key.js diff --git a/README.md b/README.md index bef1e12285..4d3ccc8f52 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,8 @@ const node = new IPFS({ // }, start: true, // default // start: false, + pass: undefined // default + // pass: 'pass phrase for key access', EXPERIMENTAL: { // enable experimental features pubsub: true, sharding: true, // enable dir sharding @@ -275,6 +277,17 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.object.patch.setData(multihash, data, [options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/OBJECT.md#objectpatchsetdata) - [pin (not implemented, yet!)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) +#### `Crypto and Key Management` + +- [key](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/KEY.md) + - `ipfs.key.export(name, password, [callback])` + - `ipfs.key.gen(name, options, [callback])` + - `ipfs.key.import(name, pem, password, [callback])` + - `ipfs.key.list([callback])` + - `ipfs.key.rename(oldName, newName, [callback])` + - `ipfs.key.rm(name, [callback])` +- [crypto (not yet implemented)](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC) + #### `Network` - [bootstrap](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) @@ -523,6 +536,10 @@ If you find any other issue, please check the [`Electron Support` issue](https:/ | [`is-ipfs`](https://github.com/ipfs/is-ipfs) | [![npm](https://img.shields.io/npm/v/is-ipfs.svg?maxAge=86400&style=flat-square)](//github.com/ipfs/is-ipfs/releases) | [![Dep](https://david-dm.org/ipfs/is-ipfs.svg?style=flat-square)](https://david-dm.org/ipfs/is-ipfs) | [![devDep](https://david-dm.org/ipfs/is-ipfs/dev-status.svg?style=flat-square)](https://david-dm.org/ipfs/is-ipfs?type=dev) | [![Travis](https://travis-ci.org/ipfs/is-ipfs.svg?branch=master)](https://travis-ci.org/ipfs/is-ipfs) | | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/ipfs/is-ipfs?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/ipfs/is-ipfs/badge.svg?branch=master)](https://coveralls.io/github/ipfs/is-ipfs?branch=master) | | [`multihashing`](//github.com/multiformats/js-multihashing) | [![npm](https://img.shields.io/npm/v/multihashing.svg?maxAge=86400&style=flat-square)](//github.com/multiformats/js-multihashing/releases) | [![Dep](https://david-dm.org/multiformats/js-multihashing.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing) | [![devDep](https://david-dm.org/multiformats/js-multihashing/dev-status.svg?style=flat-square)](https://david-dm.org/multiformats/js-multihashing?type=dev) | [![Travis](https://travis-ci.org/multiformats/js-multihashing.svg?branch=master)](https://travis-ci.org/multiformats/js-multihashing) | [![Circle CI](https://circleci.com/gh/multiformats/js-multihashing.svg?style=svg)](https://circleci.com/gh/jbenet/js-multihashing) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/multiformats/js-multihashing?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/jbenet/js-multihashing/badge.svg?branch=master)](https://coveralls.io/github/jbenet/js-multihashing?branch=master) | | [`mafmt`](//github.com/whyrusleeping/js-mafmt) | [![npm](https://img.shields.io/npm/v/mafmt.svg?maxAge=86400&style=flat-square)](//github.com/whyrusleeping/js-mafmt/releases) | [![Dep](https://david-dm.org/whyrusleeping/js-mafmt.svg?style=flat-square)](https://david-dm.org/whyrusleeping/js-mafmt) | [![devDep](https://david-dm.org/whyrusleeping/js-mafmt/dev-status.svg?style=flat-square)](https://david-dm.org/whyrusleeping/js-mafmt?type=dev) | [![Travis](https://travis-ci.org/whyrusleeping/js-mafmt.svg?branch=master)](https://travis-ci.org/whyrusleeping/js-mafmt) | [![Circle CI](https://circleci.com/gh/whyrusleeping/js-mafmt.svg?style=svg)](https://circleci.com/gh/whyrusleeping/js-mafmt) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/whyrusleeping/js-mafmt?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/whyrusleeping/js-mafmt/badge.svg?branch=master)](https://coveralls.io/github/whyrusleeping/js-mafmt?branch=master) | +| **Crypto** +| [`libp2p-crypto`](https://github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Dep](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![devDep](https://david-dm.org/libp2p/js-libp2p-crypto/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto?type=dev) | [![Travis](https://travis-ci.org/libp2p/js-libp2p-crypto.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-crypto) | [![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-crypto.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-crypto) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/libp2p/js-libp2p-crypto?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-crypto/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-crypto?branch=master) | +| [`libp2p-keychain`](https://github.com/libp2p/js-libp2p-keychain) | [![npm](https://img.shields.io/npm/v/libp2p-keychain.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-keychain/releases) | [![Dep](https://david-dm.org/libp2p/js-libp2p-keychain.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain) | [![devDep](https://david-dm.org/libp2p/js-libp2p-keychain/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-keychain?type=dev) | [![Travis](https://travis-ci.org/libp2p/js-libp2p-keychain.svg?branch=master)](https://travis-ci.org/libp2p/js-libp2p-keychain) | [![Circle CI](https://circleci.com/gh/libp2p/js-libp2p-keychain.svg?style=svg)](https://circleci.com/gh/libp2p/js-libp2p-keychain) | ![Appveyor CI](https://ci.appveyor.com/api/projects/status/github/libp2p/js-libp2p-keychain?svg=true) | [![Coverage Status](https://coveralls.io/repos/github/libp2p/js-libp2p-keychain/badge.svg?branch=master)](https://coveralls.io/github/libp2p/js-libp2p-keychain?branch=master) | + ## Development diff --git a/package.json b/package.json index de9635ca59..fa3e7acf7e 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", "interface-ipfs-core": "~0.42.1", - "ipfsd-ctl": "^0.27.0", + "ipfsd-ctl": "~0.27.2", "left-pad": "^1.2.0", "lodash": "^4.17.4", "mocha": "^4.1.0", @@ -121,6 +121,7 @@ "libp2p-circuit": "~0.1.4", "libp2p-floodsub": "~0.13.1", "libp2p-kad-dht": "~0.6.0", + "libp2p-keychain": "~0.3.0", "libp2p-mdns": "~0.9.1", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", diff --git a/src/cli/bin.js b/src/cli/bin.js index 3ea4ecc812..67e60f8362 100755 --- a/src/cli/bin.js +++ b/src/cli/bin.js @@ -21,6 +21,11 @@ const cli = yargs default: false, coerce: ('silent', silent => silent ? utils.disablePrinting() : silent) }) + .option('pass', { + desc: 'Pass phrase for the keys', + type: 'string', + default: '' + }) .commandDir('commands') .demandCommand(1) .fail((msg, err, yargs) => { @@ -59,7 +64,7 @@ if (args[0] === 'daemon' || args[0] === 'init') { if (err) { throw err } - utils.getIPFS(argv.api, (err, ipfs, cleanup) => { + utils.getIPFS(argv, (err, ipfs, cleanup) => { if (err) { throw err } cli diff --git a/src/cli/commands/init.js b/src/cli/commands/init.js index b53639fec0..741a313750 100644 --- a/src/cli/commands/init.js +++ b/src/cli/commands/init.js @@ -38,6 +38,7 @@ module.exports = { node.init({ bits: argv.bits, emptyRepo: argv.emptyRepo, + pass: argv.pass, log: print }, (err) => { if (err) { diff --git a/src/cli/commands/key.js b/src/cli/commands/key.js new file mode 100644 index 0000000000..c6d620dc61 --- /dev/null +++ b/src/cli/commands/key.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = { + command: 'key', + + description: 'Manage your keys', + + builder (yargs) { + return yargs + .commandDir('key') + }, + + handler (argv) {} +} diff --git a/src/cli/commands/key/export.js b/src/cli/commands/key/export.js new file mode 100644 index 0000000000..66adde248c --- /dev/null +++ b/src/cli/commands/key/export.js @@ -0,0 +1,37 @@ +'use strict' + +const fs = require('fs') + +module.exports = { + command: 'export ', + + describe: 'Export the key as a password protected PKCS #8 PEM file', + + builder: { + passout: { + alias: 'p', + describe: 'Password for the PEM', + type: 'string', + demandOption: true + }, + output: { + alias: 'o', + describe: 'Output file', + type: 'string', + default: 'stdout' + } + }, + + handler (argv) { + argv.ipfs.key.export(argv.name, argv.passout, (err, pem) => { + if (err) { + throw err + } + if (argv.output === 'stdout') { + process.stdout.write(pem) + } else { + fs.writeFileSync(argv.output, pem) + } + }) + } +} diff --git a/src/cli/commands/key/gen.js b/src/cli/commands/key/gen.js new file mode 100644 index 0000000000..a3f108eeaa --- /dev/null +++ b/src/cli/commands/key/gen.js @@ -0,0 +1,35 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'gen ', + + describe: 'Create a new key', + + builder: { + type: { + alias: 't', + describe: 'type of the key to create [rsa, ed25519].', + default: 'rsa' + }, + size: { + alias: 's', + describe: 'size of the key to generate.', + default: '2048' + } + }, + + handler (argv) { + const opts = { + type: argv.type, + size: argv.size + } + argv.ipfs.key.gen(argv.name, opts, (err, key) => { + if (err) { + throw err + } + print(`generated ${key.id} ${key.name}`) + }) + } +} diff --git a/src/cli/commands/key/import.js b/src/cli/commands/key/import.js new file mode 100644 index 0000000000..ae0363b25d --- /dev/null +++ b/src/cli/commands/key/import.js @@ -0,0 +1,34 @@ +'use strict' + +const fs = require('fs') +const print = require('../../utils').print + +module.exports = { + command: 'import ', + + describe: 'Import the key from a PKCS #8 PEM file', + + builder: { + passin: { + alias: 'p', + describe: 'Password for the PEM', + type: 'string' + }, + input: { + alias: 'i', + describe: 'Input PEM file', + type: 'string', + demandOption: true, + coerce: ('input', input => fs.readFileSync(input, 'utf8')) + } + }, + + handler (argv) { + argv.ipfs.key.import(argv.name, argv.input, argv.passin, (err, key) => { + if (err) { + throw err + } + print(`imported ${key.id} ${key.name}`) + }) + } +} diff --git a/src/cli/commands/key/list.js b/src/cli/commands/key/list.js new file mode 100644 index 0000000000..d50db99697 --- /dev/null +++ b/src/cli/commands/key/list.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'list', + + describe: 'List all local keys', + + builder: {}, + + handler (argv) { + argv.ipfs.key.list((err, keys) => { + if (err) { + throw err + } + keys.forEach((ki) => print(`${ki.id} ${ki.name}`)) + }) + } +} diff --git a/src/cli/commands/key/rename.js b/src/cli/commands/key/rename.js new file mode 100644 index 0000000000..9126dbbb36 --- /dev/null +++ b/src/cli/commands/key/rename.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'rename ', + + describe: 'Rename a key', + + builder: {}, + + handler (argv) { + argv.ipfs.key.rename(argv.name, argv.newName, (err, res) => { + if (err) { + throw err + } + print(`renamed to ${res.id} ${res.now}`) + }) + } +} diff --git a/src/cli/commands/key/rm.js b/src/cli/commands/key/rm.js new file mode 100644 index 0000000000..a7a5daf658 --- /dev/null +++ b/src/cli/commands/key/rm.js @@ -0,0 +1,20 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'rm ', + + describe: 'Remove a key', + + builder: {}, + + handler (argv) { + argv.ipfs.key.rm(argv.name, (err, key) => { + if (err) { + throw err + } + print(`${key.id} ${key.name}`) + }) + } +} diff --git a/src/cli/utils.js b/src/cli/utils.js index b3f2f85e9f..37cd49010f 100644 --- a/src/cli/utils.js +++ b/src/cli/utils.js @@ -38,15 +38,16 @@ function getAPICtl (apiAddr) { return APIctl(apiAddr) } -exports.getIPFS = (apiAddr, callback) => { - if (apiAddr || isDaemonOn()) { - return callback(null, getAPICtl(apiAddr), (cb) => cb()) +exports.getIPFS = (argv, callback) => { + if (argv.api || isDaemonOn()) { + return callback(null, getAPICtl(argv.api), (cb) => cb()) } const node = new IPFS({ repo: exports.getRepoPath(), init: false, start: false, + pass: argv.pass, EXPERIMENTAL: { pubsub: true } diff --git a/src/core/boot.js b/src/core/boot.js index 64f62ca631..cc7c14970e 100644 --- a/src/core/boot.js +++ b/src/core/boot.js @@ -15,7 +15,7 @@ module.exports = (self) => { const repoOpen = !self._repo.closed const customInitOptions = typeof options.init === 'object' ? options.init : {} - const initOptions = Object.assign({ bits: 2048 }, customInitOptions) + const initOptions = Object.assign({ bits: 2048, pass: self._options.pass }, customInitOptions) // Checks if a repo exists, and if so opens it // Will return callback with a bool indicating the existence @@ -30,6 +30,7 @@ module.exports = (self) => { (cb) => self._repo.open(cb), (cb) => self.preStart(cb), (cb) => { + self.log('initialized') self.state.initialized() cb(null, true) } @@ -56,8 +57,8 @@ module.exports = (self) => { if (err) { return self.emit('error', err) } + self.log('boot:done') self.emit('ready') - self.log('boot:done', err) } const tasks = [] diff --git a/src/core/components/index.js b/src/core/components/index.js index 248243a88e..4aea90db9e 100644 --- a/src/core/components/index.js +++ b/src/core/components/index.js @@ -21,3 +21,4 @@ exports.bitswap = require('./bitswap') exports.pubsub = require('./pubsub') exports.dht = require('./dht') exports.dns = require('./dns') +exports.key = require('./key') diff --git a/src/core/components/init.js b/src/core/components/init.js index 87e9072811..21504c9128 100644 --- a/src/core/components/init.js +++ b/src/core/components/init.js @@ -5,6 +5,7 @@ const waterfall = require('async/waterfall') const parallel = require('async/parallel') const promisify = require('promisify-es6') const config = require('../runtime/config-nodejs.json') +const Keychain = require('libp2p-keychain') const addDefaultAssets = require('./init-assets') @@ -36,7 +37,7 @@ module.exports = function init (self) { opts.emptyRepo = opts.emptyRepo || false opts.bits = Number(opts.bits) || 2048 opts.log = opts.log || function () {} - + let privateKey waterfall([ // Verify repo does not yet exist. (cb) => self._repo.exists(cb), @@ -57,6 +58,10 @@ module.exports = function init (self) { PeerID: keys.toB58String(), PrivKey: keys.privKey.bytes.toString('base64') } + if (opts.pass) { + privateKey = keys.privKey + config.Keychain = Keychain.generateOptions() + } opts.log('done') opts.log('peer identity: ' + config.Identity.PeerID) @@ -65,10 +70,21 @@ module.exports = function init (self) { (_, cb) => self._repo.open(cb), (cb) => { self.log('repo opened') + if (opts.pass) { + self.log('creating keychain') + const keychainOptions = Object.assign({passPhrase: opts.pass}, config.Keychain) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + self._keychain.importPeer('self', { privKey: privateKey }, cb) + } else { + cb(null, true) + } + }, + (_, cb) => { if (opts.emptyRepo) { return cb(null, true) } + self.log('adding assets') const tasks = [ // add empty unixfs dir object (go-ipfs assumes this exists) (cb) => self.object.new('unixfs-dir', cb) diff --git a/src/core/components/key.js b/src/core/components/key.js new file mode 100644 index 0000000000..b5bc5cd434 --- /dev/null +++ b/src/core/components/key.js @@ -0,0 +1,46 @@ +'use strict' + +// See https://github.com/ipfs/specs/tree/master/keystore + +const promisify = require('promisify-es6') + +module.exports = function key (self) { + return { + gen: promisify((name, opts, callback) => { + self._keychain.createKey(name, opts.type, opts.size, callback) + }), + + info: promisify((name, callback) => { + self._keychain.findKeyByName(name, callback) + }), + + list: promisify((callback) => { + self._keychain.listKeys(callback) + }), + + rm: promisify((name, callback) => { + self._keychain.removeKey(name, callback) + }), + + rename: promisify((oldName, newName, callback) => { + self._keychain.renameKey(oldName, newName, (err, key) => { + if (err) return callback(err) + const result = { + was: oldName, + now: key.name, + id: key.id, + overwrite: false + } + callback(null, result) + }) + }), + + import: promisify((name, pem, password, callback) => { + self._keychain.importKey(name, pem, password, callback) + }), + + export: promisify((name, password, callback) => { + self._keychain.exportKey(name, password, callback) + }) + } +} diff --git a/src/core/components/no-keychain.js b/src/core/components/no-keychain.js new file mode 100644 index 0000000000..6f07f4068e --- /dev/null +++ b/src/core/components/no-keychain.js @@ -0,0 +1,24 @@ +'use strict' + +function fail () { + throw new Error('Key management requires \'--pass ...\' option') +} + +class NoKeychain { + static get options () { fail() } + static generateOptions () { fail() } + + createKey () { fail() } + listKeys () { fail() } + findKeyById () { fail() } + findKeyByName () { fail() } + renameKey () { fail() } + removeKey () { fail() } + exportKey () { fail() } + importKey () { fail() } + importPeer () { fail() } + + get cms () { fail() } +} + +module.exports = NoKeychain diff --git a/src/core/components/pre-start.js b/src/core/components/pre-start.js index 32017bd4f0..2121ff6e22 100644 --- a/src/core/components/pre-start.js +++ b/src/core/components/pre-start.js @@ -4,7 +4,8 @@ const peerId = require('peer-id') const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') const waterfall = require('async/waterfall') - +const Keychain = require('libp2p-keychain') +const NoKeychain = require('./no-keychain') /* * Load stuff from Repo into memory */ @@ -12,14 +13,56 @@ module.exports = function preStart (self) { return (callback) => { self.log('pre-start') + const pass = self._options.pass waterfall([ (cb) => self._repo.config.get(cb), + (config, cb) => { + // Create keychain configuration, if needed. + if (config.Keychain) { + return cb(null, config) + } + config.Keychain = Keychain.generateOptions() + self.config.set('Keychain', config.Keychain, (err) => { + self.log('using default keychain options') + cb(err, config) + }) + }, + (config, cb) => { + // Construct the keychain + if (self._keychain) { + // most likely an init or upgrade has happened + } else if (pass) { + const keychainOptions = Object.assign({passPhrase: pass}, config.Keychain) + self._keychain = new Keychain(self._repo.keys, keychainOptions) + self.log('keychain constructed') + } else { + self._keychain = new NoKeychain() + self.log('no keychain, use --pass') + } + cb(null, config) + }, (config, cb) => { const privKey = config.Identity.PrivKey - peerId.createFromPrivKey(privKey, (err, id) => cb(err, config, id)) + peerId.createFromPrivKey(privKey, (err, id) => { + cb(err, config, id) + }) + }, + (config, id, cb) => { + // Import the private key as 'self', if needed. + if (!pass) { + return cb(null, config, id) + } + self._keychain.findKeyByName('self', (err) => { + if (err) { + self.log('Creating "self" key') + return self._keychain.importPeer('self', id, (err) => cb(err, config, id)) + } + cb(null, config, id) + }) }, (config, id, cb) => { + self.log('peer created') self._peerInfo = new PeerInfo(id) if (config.Addresses && config.Addresses.Swarm) { diff --git a/src/core/index.js b/src/core/index.js index fa60876061..b0e5719b2f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -95,6 +95,7 @@ class IPFS extends EventEmitter { this.pubsub = components.pubsub(this) this.dht = components.dht(this) this.dns = components.dns(this) + this.key = components.key(this) if (this._options.EXPERIMENTAL.pubsub) { this.log('EXPERIMENTAL pubsub is enabled') diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index 16b0f17128..42eec1d0b0 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -13,3 +13,4 @@ exports.file = require('./file') exports.files = require('./files') exports.pubsub = require('./pubsub') exports.dns = require('./dns') +exports.key = require('./key') diff --git a/src/http/api/resources/key.js b/src/http/api/resources/key.js new file mode 100644 index 0000000000..15de675c8e --- /dev/null +++ b/src/http/api/resources/key.js @@ -0,0 +1,102 @@ +'use strict' + +exports = module.exports + +function applyError (reply, err) { + reply({ + Message: err.message, + Code: 0 + }).code(500).takeover() +} + +function toKeyInfo (key) { + return { + Name: key.name, + Id: key.id + } +} + +exports.list = (request, reply) => { + const ipfs = request.server.app.ipfs + + ipfs._keychain.listKeys((err, keys) => { + if (err) { + return applyError(reply, err) + } + + keys = keys.map(toKeyInfo) + return reply({ Keys: keys }) + }) +} + +exports.rm = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + ipfs._keychain.removeKey(name, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply({ Keys: [ toKeyInfo(key) ] }) + }) +} + +exports.rename = (request, reply) => { + const ipfs = request.server.app.ipfs + const oldName = request.query.arg[0] + const newName = request.query.arg[1] + ipfs._keychain.renameKey(oldName, newName, (err, key) => { + if (err) { + return applyError(reply, err) + } + + const result = { + Was: oldName, + Now: key.name, + Id: key.id, + Overwrite: false + } + return reply(result) + }) +} + +exports.gen = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const type = request.query.type + const size = request.query.size + ipfs._keychain.createKey(name, type, size, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply(toKeyInfo(key)) + }) +} + +exports.export = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const password = request.query.password + ipfs._keychain.exportKey(name, password, (err, pem) => { + if (err) { + return applyError(reply, err) + } + + return reply(pem).type('application/x-pem-file') + }) +} + +exports.import = (request, reply) => { + const ipfs = request.server.app.ipfs + const name = request.query.arg + const pem = request.query.pem + const password = request.query.password + ipfs._keychain.importKey(name, pem, password, (err, key) => { + if (err) { + return applyError(reply, err) + } + + return reply(toKeyInfo(key)) + }) +} diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index 908c0c0878..9e405ae6b5 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -16,4 +16,5 @@ module.exports = (server) => { require('./debug')(server) require('./webui')(server) require('./dns')(server) + require('./key')(server) } diff --git a/src/http/api/routes/key.js b/src/http/api/routes/key.js new file mode 100644 index 0000000000..4493bdab39 --- /dev/null +++ b/src/http/api/routes/key.js @@ -0,0 +1,43 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/key/list', + handler: resources.key.list + }) + + api.route({ + method: '*', + path: '/api/v0/key/gen', + handler: resources.key.gen + }) + + api.route({ + method: '*', + path: '/api/v0/key/rm', + handler: resources.key.rm + }) + + api.route({ + method: '*', + path: '/api/v0/key/rename', + handler: resources.key.rename + }) + + api.route({ + method: '*', + path: '/api/v0/key/export', + handler: resources.key.export + }) + + api.route({ + method: '*', + path: '/api/v0/key/import', + handler: resources.key.import + }) +} diff --git a/src/http/index.js b/src/http/index.js index 2df407dd5d..4a985ce3c6 100644 --- a/src/http/index.js +++ b/src/http/index.js @@ -67,6 +67,7 @@ function HttpApi (repo, config, cliArgs) { init: init, start: true, config: config, + pass: cliArgs && cliArgs.pass, EXPERIMENTAL: { pubsub: cliArgs && cliArgs.enablePubsubExperiment, sharding: cliArgs && cliArgs.enableShardingExperiment diff --git a/test/cli/commands.js b/test/cli/commands.js index 3a2d85a418..1fabdc857f 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,8 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 60 - +const commandCount = 67 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/cli/files.js b/test/cli/files.js index 5a36f52a4e..738b07e317 100644 --- a/test/cli/files.js +++ b/test/cli/files.js @@ -353,6 +353,7 @@ describe('files', () => runOnAndOff((thing) => { 'Options:', ' --version Show version number [boolean]', ' --silent Write no output [boolean] [default: false]', + ' --pass Pass phrase for the keys [string] [default: ""]', ' --help Show help [boolean]', ' -v, --headers Print table headers (Hash, Size, Name).', ' [boolean] [default: false]', diff --git a/test/cli/key.js b/test/cli/key.js new file mode 100644 index 0000000000..8a39c4919c --- /dev/null +++ b/test/cli/key.js @@ -0,0 +1,53 @@ +/* eslint-env mocha */ +'use strict' + +const expect = require('chai').expect +const runOnAndOff = require('../utils/on-and-off') +const hat = require('hat') + +describe('key', () => runOnAndOff.off((thing) => { + const name = 'test-key-' + hat() + const newName = 'test-key-' + hat() + const pass = '--pass ' + hat() + let ipfs + + before(() => { + ipfs = thing.ipfs + }) + + it('gen', function () { + this.timeout(40 * 1000) + + return ipfs(`${pass} key gen ${name} --type rsa --size 2048`) + .then((out) => { + expect(out).to.include(name) + }) + }) + + it('list', function () { + this.timeout(20 * 1000) + + return ipfs(`${pass} key list`) + .then((out) => { + expect(out).to.include(name) + }) + }) + + it('rename', function () { + this.timeout(20 * 1000) + + return ipfs(`${pass} key rename ${name} ${newName}`) + .then((out) => { + expect(out).to.include(newName) + }) + }) + + it('rm', function () { + this.timeout(20 * 1000) + + return ipfs(`${pass} key rm ${newName}`) + .then((out) => { + expect(out).to.include(newName) + }) + }) +})) diff --git a/test/core/init.spec.js b/test/core/init.spec.js index 07990027f2..58916ecbe4 100644 --- a/test/core/init.spec.js +++ b/test/core/init.spec.js @@ -7,6 +7,7 @@ const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) const isNode = require('detect-node') +const hat = require('hat') const PeerId = require('peer-id') const PeerInfo = require('peer-info') const multiaddr = require('multiaddr') @@ -36,7 +37,7 @@ describe('init', () => { afterEach((done) => repo.teardown(done)) it('basic', (done) => { - ipfs.init({ bits: 512 }, (err) => { + ipfs.init({ bits: 512, pass: hat() }, (err) => { expect(err).to.not.exist() repo.exists((err, res) => { @@ -46,6 +47,7 @@ describe('init', () => { repo.config.get((err, config) => { expect(err).to.not.exist() expect(config.Identity).to.exist() + expect(config.Keychain).to.exist() done() }) }) @@ -55,7 +57,7 @@ describe('init', () => { it('set # of bits in key', function (done) { this.timeout(40 * 1000) - ipfs.init({ bits: 1024 }, (err) => { + ipfs.init({ bits: 1024, pass: hat() }, (err) => { expect(err).to.not.exist() repo.config.get((err, config) => { @@ -67,7 +69,7 @@ describe('init', () => { }) it('init docs are written', (done) => { - ipfs.init({ bits: 512 }, (err) => { + ipfs.init({ bits: 512, pass: hat() }, (err) => { expect(err).to.not.exist() const multihash = 'QmPZ9gcCEpqKTo6aq61g2nXGUhM4iCL3ewB6LDXZCtioEB' diff --git a/test/core/interface/interface.spec.js b/test/core/interface/interface.spec.js index 96815d2596..3d8e370981 100644 --- a/test/core/interface/interface.spec.js +++ b/test/core/interface/interface.spec.js @@ -12,6 +12,7 @@ describe('interface-ipfs-core tests', () => { require('./object') require('./dag') require('./stats') + require('./key') if (isNode) { require('./swarm') require('./pubsub') diff --git a/test/core/interface/key.js b/test/core/interface/key.js new file mode 100644 index 0000000000..737d412743 --- /dev/null +++ b/test/core/interface/key.js @@ -0,0 +1,36 @@ +/* eslint-env mocha */ + +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) +const options = { + args: ['--pass ipfs-is-awesome-software'] +} +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn(options, (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.key(common) diff --git a/test/core/key-exchange.js b/test/core/key-exchange.js new file mode 100644 index 0000000000..86a2781ad6 --- /dev/null +++ b/test/core/key-exchange.js @@ -0,0 +1,51 @@ +/* eslint max-nested-callbacks: ["error", 8] */ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) +const hat = require('hat') +const IPFS = require('../../src/core') + +// This gets replaced by `create-repo-browser.js` in the browser +const createTempRepo = require('../utils/create-repo-nodejs.js') + +describe('key exchange', () => { + let ipfs + let repo + let selfPem + let passwordPem = hat() + + before(function (done) { + this.timeout(20 * 1000) + repo = createTempRepo() + ipfs = new IPFS({ + repo: repo, + pass: hat() + }) + ipfs.on('ready', () => done()) + }) + + after((done) => repo.teardown(done)) + + it('exports', (done) => { + ipfs.key.export('self', passwordPem, (err, pem) => { + expect(err).to.not.exist() + expect(pem).to.exist() + selfPem = pem + done() + }) + }) + + it('imports', (done) => { + ipfs.key.import('clone', selfPem, passwordPem, (err, key) => { + expect(err).to.not.exist() + expect(key).to.exist() + expect(key).to.have.property('name', 'clone') + expect(key).to.have.property('id') + done() + }) + }) +}) diff --git a/test/http-api/index.js b/test/http-api/index.js index 374f50485c..1fa11622ad 100644 --- a/test/http-api/index.js +++ b/test/http-api/index.js @@ -6,6 +6,7 @@ const chai = require('chai') const dirtyChai = require('dirty-chai') const expect = chai.expect chai.use(dirtyChai) +const hat = require('hat') const API = require('../../src/http') const APIctl = require('ipfs-api') const ncp = require('ncp').ncp @@ -21,7 +22,10 @@ describe('HTTP API', () => { before(function (done) { this.timeout(60 * 1000) - const options = { enablePubsubExperiment: true } + const options = { + pass: hat(), + enablePubsubExperiment: true + } http.api = new API(repoTests, null, options) ncp(repoExample, repoTests, (err) => { diff --git a/test/http-api/interface/key.js b/test/http-api/interface/key.js new file mode 100644 index 0000000000..75d5cf5769 --- /dev/null +++ b/test/http-api/interface/key.js @@ -0,0 +1,35 @@ +/* eslint-env mocha */ + +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) +const options = { + args: ['--pass', 'ipfs-is-awesome-software'] +} + +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn(options, (err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.key(common) From e56e54c535be8856c9429f25182b7167ce40d928 Mon Sep 17 00:00:00 2001 From: David Dias Date: Mon, 5 Feb 2018 17:48:47 +0000 Subject: [PATCH 20/32] docs: add link to the dev calls --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4d3ccc8f52..2df3d40642 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,8 @@ You can check the development status at the [Waffle Board](https://waffle.io/ipf - DHT: https://github.com/ipfs/js-ipfs/pull/856 - Relay: https://github.com/ipfs/js-ipfs/pull/1063 +[**Weekly Dev Calls**](https://github.com/ipfs/js-ipfs/issues/1179) + ## Table of Contents - [Install](#install) From d42e5a1514a059eb120546eb6b3a090d8c80baf4 Mon Sep 17 00:00:00 2001 From: David Dias Date: Wed, 7 Feb 2018 06:50:26 +0000 Subject: [PATCH 21/32] docs: ref ipfsd-ctl --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2df3d40642..5dd8f2a3e7 100644 --- a/README.md +++ b/README.md @@ -156,9 +156,11 @@ Commands: The IPFS Daemon exposes the API defined [`http-api-spec`](https://github.com/ipfs/http-api-spec). You can use any of the IPFS HTTP-API client libraries with it, such as: [js-ipfs-api](https://github.com/ipfs/js-ipfs-api). +If you want a programmatic way to spawn a IPFS Daemon using JavaScript, check out [ipfsd-ctl module](https://github.com/ipfs/js-ipfsd-ctl) + ### IPFS Module -Use the IPFS Module as a dependency of a project to spawn in process instances of IPFS. +Use the IPFS Module as a dependency of a project to __spawn in process instances of IPFS__. #### Create a IPFS node instance From aea9344fa0f3eae831394568480ce73082b1f068 Mon Sep 17 00:00:00 2001 From: David Dias Date: Sun, 11 Feb 2018 07:52:33 +0000 Subject: [PATCH 22/32] docs: make link to Weekly Dev Calls more visual --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5dd8f2a3e7..cb3373644f 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ You can check the development status at the [Waffle Board](https://waffle.io/ipf - DHT: https://github.com/ipfs/js-ipfs/pull/856 - Relay: https://github.com/ipfs/js-ipfs/pull/1063 -[**Weekly Dev Calls**](https://github.com/ipfs/js-ipfs/issues/1179) +[**`Weekly Dev Calls`**](https://github.com/ipfs/js-ipfs/issues/1179) ## Table of Contents From 42545dc1c7dc3f67a5487d709710a0685854a4a6 Mon Sep 17 00:00:00 2001 From: Volker Mische Date: Fri, 9 Feb 2018 13:19:43 +0100 Subject: [PATCH 23/32] fix(dag): print data in a readable way if it is JSON If a dag node is JSON, print the stringified version of it, so that it shows the actual JSON and not just `[object Object]`. --- src/cli/commands/dag/get.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/commands/dag/get.js b/src/cli/commands/dag/get.js index 957185c59c..6088d2eb34 100644 --- a/src/cli/commands/dag/get.js +++ b/src/cli/commands/dag/get.js @@ -42,7 +42,7 @@ module.exports = { if (node._json) { delete node._json.multihash node._json.data = '0x' + node._json.data.toString('hex') - print(node._json) + print(JSON.stringify(node._json)) return } From 4b79066b924b8e8bf7f8a0fde0da40c3c1b84f31 Mon Sep 17 00:00:00 2001 From: David Dias Date: Thu, 15 Feb 2018 09:46:03 +0100 Subject: [PATCH 24/32] feat: latest libp2p + other deps. Fix bugs in tests along the way --- .aegir.js | 2 +- package.json | 58 +++++++++++++++++----------------- src/core/components/files.js | 10 ++++-- src/core/components/stop.js | 3 +- test/cli/bitswap.js | 3 +- test/core/bitswap.spec.js | 2 +- test/core/interface/generic.js | 6 ++-- test/core/kad-dht.node.js | 8 ++--- test/gateway/index.js | 12 +++---- 9 files changed, 56 insertions(+), 48 deletions(-) diff --git a/.aegir.js b/.aegir.js index 6a0af49287..e254dd4812 100644 --- a/.aegir.js +++ b/.aegir.js @@ -6,7 +6,7 @@ const server = createServer() module.exports = { karma: { files: [{ - pattern: 'node_modules/interface-ipfs-core/test/fixtures/**/*', + pattern: 'node_modules/interface-ipfs-core/js/test/fixtures/**/*', watched: false, served: true, included: false diff --git a/package.json b/package.json index fa3e7acf7e..9878ce947f 100644 --- a/package.json +++ b/package.json @@ -60,24 +60,24 @@ }, "homepage": "https://github.com/ipfs/js-ipfs#readme", "devDependencies": { - "aegir": "^12.3.0", + "aegir": "^13.0.0", "buffer-loader": "0.0.1", "chai": "^4.1.2", "delay": "^2.0.0", "detect-node": "^2.0.3", "dir-compare": "^1.4.0", "dirty-chai": "^2.0.1", - "eslint-plugin-react": "^7.5.1", + "eslint-plugin-react": "^7.6.1", "execa": "^0.9.0", "expose-loader": "^0.7.4", - "form-data": "^2.3.1", + "form-data": "^2.3.2", "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", - "interface-ipfs-core": "~0.42.1", - "ipfsd-ctl": "~0.27.2", + "interface-ipfs-core": "~0.50.1", + "ipfsd-ctl": "~0.28.0", "left-pad": "^1.2.0", - "lodash": "^4.17.4", - "mocha": "^4.1.0", + "lodash": "^4.17.5", + "mocha": "^5.0.1", "ncp": "^2.0.0", "nexpect": "^0.5.0", "pre-commit": "^1.2.2", @@ -97,53 +97,53 @@ "byteman": "^1.3.5", "cids": "~0.5.2", "debug": "^3.1.0", - "file-type": "^7.4.0", - "filesize": "^3.5.11", + "file-type": "^7.5.0", + "filesize": "^3.6.0", "fsm-event": "^2.1.0", "get-folder-size": "^1.0.1", "glob": "^7.1.2", "hapi": "^16.6.2", "hapi-set-header": "^1.0.2", - "hoek": "^5.0.2", - "ipfs-api": "^17.3.0", - "ipfs-bitswap": "~0.18.0", + "hoek": "^5.0.3", + "ipfs-api": "^18.0.0", + "ipfs-bitswap": "~0.19.0", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", "ipfs-multipart": "~0.1.0", - "ipfs-repo": "~0.18.5", + "ipfs-repo": "~0.18.7", "ipfs-unixfs": "~0.1.14", "ipfs-unixfs-engine": "~0.24.2", "ipld-resolver": "~0.14.1", "is-ipfs": "^0.3.2", "is-stream": "^1.1.0", - "joi": "^13.1.0", - "libp2p": "~0.15.0", + "joi": "^13.1.2", + "libp2p": "~0.16.5", "libp2p-circuit": "~0.1.4", - "libp2p-floodsub": "~0.13.1", - "libp2p-kad-dht": "~0.6.0", - "libp2p-keychain": "~0.3.0", - "libp2p-mdns": "~0.9.1", + "libp2p-floodsub": "~0.14.1", + "libp2p-kad-dht": "~0.8.0", + "libp2p-keychain": "~0.3.1", + "libp2p-mdns": "~0.9.2", "libp2p-multiplex": "~0.5.1", "libp2p-railing": "~0.7.1", - "libp2p-secio": "~0.9.0", - "libp2p-tcp": "~0.11.2", + "libp2p-secio": "~0.9.2", + "libp2p-tcp": "~0.11.5", "libp2p-webrtc-star": "~0.13.3", - "libp2p-websocket-star": "~0.7.2", + "libp2p-websocket-star": "~0.7.6", "libp2p-websockets": "~0.10.4", "lodash.flatmap": "^4.5.0", "lodash.get": "^4.4.2", "lodash.sortby": "^4.7.0", "lodash.values": "^4.3.0", - "mafmt": "^3.0.2", + "mafmt": "^4.0.0", "mime-types": "^2.1.17", "mkdirp": "~0.5.1", "multiaddr": "^3.0.2", "multihashes": "~0.4.13", "once": "^1.4.0", "path-exists": "^3.0.0", - "peer-book": "~0.5.2", - "peer-id": "~0.10.4", - "peer-info": "~0.11.4", + "peer-book": "~0.5.4", + "peer-id": "~0.10.6", + "peer-info": "~0.11.6", "progress": "^2.0.0", "promisify-es6": "^1.0.3", "pull-abortable": "^4.1.1", @@ -157,15 +157,15 @@ "pull-stream-to-stream": "^1.3.4", "pull-zip": "^2.0.1", "read-pkg-up": "^3.0.0", - "readable-stream": "2.3.3", + "readable-stream": "2.3.4", "safe-buffer": "^5.1.1", "stream-to-pull-stream": "^1.7.2", "tar-stream": "^1.5.5", "temp": "~0.8.3", "through2": "^2.0.3", "update-notifier": "^2.3.0", - "yargs": "^10.1.1", - "yargs-parser": "^8.1.0" + "yargs": "^11.0.0", + "yargs-parser": "^9.0.2" }, "optionalDependencies": { "prom-client": "^10.2.2", diff --git a/src/core/components/files.js b/src/core/components/files.js index 28b920668a..b06c396745 100644 --- a/src/core/components/files.js +++ b/src/core/components/files.js @@ -13,6 +13,7 @@ const deferred = require('pull-defer') const waterfall = require('async/waterfall') const isStream = require('is-stream') const Duplex = require('readable-stream').Duplex +const OtherBuffer = require('buffer').Buffer const CID = require('cids') const toB58String = require('multihashes').toB58String @@ -183,9 +184,12 @@ module.exports = function files (self) { callback = noop } - if (typeof data !== 'object' && - !Buffer.isBuffer(data) && - !isStream(data)) { + const ok = Buffer.isBuffer(data) || + isStream.readable(data) || + Array.isArray(data) || + OtherBuffer.isBuffer(data) + + if (!ok) { return callback(new Error('Invalid arguments, data must be an object, Buffer or readable stream')) } diff --git a/src/core/components/stop.js b/src/core/components/stop.js index 6ac0dc91a3..ad3957b546 100644 --- a/src/core/components/stop.js +++ b/src/core/components/stop.js @@ -6,10 +6,11 @@ const promisify = require('promisify-es6') module.exports = (self) => { return promisify((callback) => { callback = callback || function noop () {} + self.log('stop') if (self.state.state() === 'stopped') { - return callback() + return callback(new Error('Already stopped')) } const done = (err) => { diff --git a/test/cli/bitswap.js b/test/cli/bitswap.js index 29220f7b71..6652364f9b 100644 --- a/test/cli/bitswap.js +++ b/test/cli/bitswap.js @@ -23,7 +23,8 @@ describe('bitswap', () => runOn((thing) => { }) }) - it('stat', function () { + // TODO @hacdias fix this with https://github.com/ipfs/js-ipfs/pull/1198 + it.skip('stat', function () { this.timeout(20 * 1000) return ipfs('bitswap stat').then((out) => { diff --git a/test/core/bitswap.spec.js b/test/core/bitswap.spec.js index b06b4c41f8..029ee03072 100644 --- a/test/core/bitswap.spec.js +++ b/test/core/bitswap.spec.js @@ -70,7 +70,7 @@ let nodes = [] function addNode (inProcNode, callback) { df.spawn({ - exec: `./src/cli/bin.js`, + exec: './src/cli/bin.js', config: { Addresses: { Swarm: [`/ip4/127.0.0.1/tcp/0/ws`] diff --git a/test/core/interface/generic.js b/test/core/interface/generic.js index 9af526e58b..b1b4fcca72 100644 --- a/test/core/interface/generic.js +++ b/test/core/interface/generic.js @@ -2,7 +2,7 @@ 'use strict' const test = require('interface-ipfs-core') -const parallel = require('async/parallel') +// const parallel = require('async/parallel') const IPFS = require('../../../src') @@ -26,7 +26,9 @@ const common = { }) }, teardown: function (callback) { - parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + // Stopped by the tests themselves + // parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + callback() } } diff --git a/test/core/kad-dht.node.js b/test/core/kad-dht.node.js index db91cdc168..09989579ca 100644 --- a/test/core/kad-dht.node.js +++ b/test/core/kad-dht.node.js @@ -8,8 +8,8 @@ const expect = chai.expect chai.use(dirtyChai) const parallel = require('async/parallel') -const DaemonFactory = require('ipfsd-ctl') -const df = DaemonFactory.create({ type: 'js' }) +const IPFSFactory = require('ipfsd-ctl') +const f = IPFSFactory.create({ type: 'js' }) const config = { Addresses: { @@ -26,10 +26,10 @@ const config = { } function createNode (callback) { - df.spawn({ exec: './src/cli/bin.js', config }, callback) + f.spawn({ exec: './src/cli/bin.js', config }, callback) } -describe('verify that kad-dht is doing its thing', () => { +describe.skip('verify that kad-dht is doing its thing', () => { let nodeA let nodeB let nodeC diff --git a/test/gateway/index.js b/test/gateway/index.js index 861fa9ff87..8b9eb1c3ab 100644 --- a/test/gateway/index.js +++ b/test/gateway/index.js @@ -13,13 +13,13 @@ const path = require('path') const hat = require('hat') const fileType = require('file-type') -const bigFile = loadFixture(__dirname, '../../node_modules/interface-ipfs-core/test/fixtures/15mb.random', 'ipfs') +const bigFile = loadFixture('js/test/fixtures/15mb.random', 'interface-ipfs-core') const directoryContent = { - 'index.html': loadFixture(__dirname, './test-folder/index.html', 'ipfs'), - 'nested-folder/hello.txt': loadFixture(__dirname, './test-folder/nested-folder/hello.txt', 'ipfs'), - 'nested-folder/ipfs.txt': loadFixture(__dirname, './test-folder/nested-folder/ipfs.txt', 'ipfs'), - 'nested-folder/nested.html': loadFixture(__dirname, './test-folder/nested-folder/nested.html', 'ipfs'), - 'cat-folder/cat.jpg': loadFixture(__dirname, './test-folder/cat-folder/cat.jpg', 'ipfs') + 'index.html': loadFixture('test/gateway/test-folder/index.html'), + 'nested-folder/hello.txt': loadFixture('test/gateway/test-folder/nested-folder/hello.txt'), + 'nested-folder/ipfs.txt': loadFixture('test/gateway/test-folder/nested-folder/ipfs.txt'), + 'nested-folder/nested.html': loadFixture('test/gateway/test-folder/nested-folder/nested.html'), + 'cat-folder/cat.jpg': loadFixture('test/gateway/test-folder/cat-folder/cat.jpg') } describe('HTTP Gateway', function () { From d3a0ae10bd2d359f10e75deabe86421856664536 Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Date: Mon, 29 Jan 2018 15:47:00 -0200 Subject: [PATCH 25/32] fix: Return swarm http errors as json Closes #1176 --- src/http/api/resources/swarm.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/http/api/resources/swarm.js b/src/http/api/resources/swarm.js index fc92d76002..915a64f974 100644 --- a/src/http/api/resources/swarm.js +++ b/src/http/api/resources/swarm.js @@ -10,13 +10,22 @@ exports = module.exports // common pre request handler that parses the args and returns `addr` which is assigned to `request.pre.args` exports.parseAddrs = (request, reply) => { if (!request.query.arg) { - return reply("Argument 'addr' is required").code(400).takeover() + const err = 'Argument \'addr\' is required' + log.error(err) + return reply({ + Code: 0, + Message: err + }).code(400).takeover() } try { multiaddr(request.query.arg) } catch (err) { - return reply("Argument 'addr' is invalid").code(500).takeover() + log.error(err) + return reply({ + Code: 0, + Message: err.message + }).code(500).takeover() } return reply({ From 68e7b5a2d923490dc9416a3a80b54b6c9f531aee Mon Sep 17 00:00:00 2001 From: Paulo Rodrigues Date: Mon, 29 Jan 2018 16:05:40 -0200 Subject: [PATCH 26/32] fix: Remove scape characteres from error message. --- src/http/api/resources/swarm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/http/api/resources/swarm.js b/src/http/api/resources/swarm.js index 915a64f974..a969820c79 100644 --- a/src/http/api/resources/swarm.js +++ b/src/http/api/resources/swarm.js @@ -10,7 +10,7 @@ exports = module.exports // common pre request handler that parses the args and returns `addr` which is assigned to `request.pre.args` exports.parseAddrs = (request, reply) => { if (!request.query.arg) { - const err = 'Argument \'addr\' is required' + const err = 'Argument `addr` is required' log.error(err) return reply({ Code: 0, From 48881a343cceb2c8bf3da3762a535c1b11da0bea Mon Sep 17 00:00:00 2001 From: Bruno Zell Date: Thu, 15 Feb 2018 09:50:17 +0100 Subject: [PATCH 27/32] docs: Fixed broken link to API docs (#1214) --- examples/browser-script-tag/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/browser-script-tag/index.html b/examples/browser-script-tag/index.html index ddc474a8a4..50ef0819e3 100644 --- a/examples/browser-script-tag/index.html +++ b/examples/browser-script-tag/index.html @@ -13,7 +13,7 @@ // You can write more code here to use it. Use methods like // node.files.add, node.files.get. See the API docs here: - // https://github.com/ipfs/interface-ipfs-core/tree/master/API + // https://github.com/ipfs/interface-ipfs-core }) From 9a445d10eeaf3597e31cd7415d67aa1a58a0b2ea Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 15 Feb 2018 23:37:42 +1300 Subject: [PATCH 28/32] feat: Bootstrap API compliance (#1218) --- package.json | 2 +- src/core/components/bootstrap.js | 28 ++++++++++++++++++----- test/core/bootstrap.spec.js | 10 ++++---- test/core/interface/bootstrap.js | 33 +++++++++++++++++++++++++++ test/core/interface/interface.spec.js | 1 + test/http-api/interface/bootstrap.js | 31 +++++++++++++++++++++++++ 6 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 test/core/interface/bootstrap.js create mode 100644 test/http-api/interface/bootstrap.js diff --git a/package.json b/package.json index 9878ce947f..d07e1d9694 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "form-data": "^2.3.2", "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", - "interface-ipfs-core": "~0.50.1", + "interface-ipfs-core": "~0.51.0", "ipfsd-ctl": "~0.28.0", "left-pad": "^1.2.0", "lodash": "^4.17.5", diff --git a/src/core/components/bootstrap.js b/src/core/components/bootstrap.js index 8822c5997a..9ca1a76479 100644 --- a/src/core/components/bootstrap.js +++ b/src/core/components/bootstrap.js @@ -1,22 +1,31 @@ 'use strict' const defaultNodes = require('../runtime/config-nodejs.json').Bootstrap +const MultiAddr = require('multiaddr') +const promisify = require('promisify-es6') module.exports = function bootstrap (self) { return { - list: (callback) => { + list: promisify((callback) => { self._repo.config.get((err, config) => { if (err) { return callback(err) } callback(null, {Peers: config.Bootstrap}) }) - }, - add: (multiaddr, args, callback) => { + }), + add: promisify((multiaddr, args, callback) => { if (typeof args === 'function') { callback = args args = {default: false} } + try { + if (multiaddr) + new MultiAddr(multiaddr) + } + catch (err) { + return setImmediate(() => callback(err)) + } self._repo.config.get((err, config) => { if (err) { return callback(err) @@ -36,12 +45,19 @@ module.exports = function bootstrap (self) { }) }) }) - }, - rm: (multiaddr, args, callback) => { + }), + rm: promisify((multiaddr, args, callback) => { if (typeof args === 'function') { callback = args args = {all: false} } + try { + if (multiaddr) + new MultiAddr(multiaddr) + } + catch (err) { + return setImmediate(() => callback(err)) + } self._repo.config.get((err, config) => { if (err) { return callback(err) @@ -65,6 +81,6 @@ module.exports = function bootstrap (self) { callback(null, {Peers: res}) }) }) - } + }) } } diff --git a/test/core/bootstrap.spec.js b/test/core/bootstrap.spec.js index e18ce0e8c0..698af528b4 100644 --- a/test/core/bootstrap.spec.js +++ b/test/core/bootstrap.spec.js @@ -81,7 +81,7 @@ describe('bootstrap', () => { '/ip6/2604:a880:1:20::1d9:6001/tcp/4001/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6', - '/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT' + '/ip4/111.111.111.111/tcp/1001/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb' ] it('get bootstrap list', (done) => { @@ -93,9 +93,9 @@ describe('bootstrap', () => { }) it('add a peer to the bootstrap list', (done) => { - node.bootstrap.add('/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT', (err, res) => { + node.bootstrap.add('/ip4/111.111.111.111/tcp/1001/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb', (err, res) => { expect(err).to.not.exist() - expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT'] }) + expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb'] }) node.bootstrap.list((err, list) => { expect(err).to.not.exist() expect(list.Peers).to.deep.equal(updatedList) @@ -105,9 +105,9 @@ describe('bootstrap', () => { }) it('remove a peer from the bootstrap list', (done) => { - node.bootstrap.rm('/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT', (err, res) => { + node.bootstrap.rm('/ip4/111.111.111.111/tcp/1001/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb', (err, res) => { expect(err).to.not.exist() - expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLUVIT'] }) + expect(res).to.be.eql({ Peers: ['/ip4/111.111.111.111/tcp/1001/ipfs/QmXFX2P5ammdmXQgfqGkfswtEVFsZUJ5KeHRXQYCTdiTAb'] }) node.bootstrap.list((err, list) => { expect(err).to.not.exist() expect(list.Peers).to.deep.equal(defaultList) diff --git a/test/core/interface/bootstrap.js b/test/core/interface/bootstrap.js new file mode 100644 index 0000000000..10c95208f4 --- /dev/null +++ b/test/core/interface/bootstrap.js @@ -0,0 +1,33 @@ +/* eslint-env mocha */ +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const IPFS = require('../../../src') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ type: 'proc', exec: IPFS }) + +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.bootstrap(common) diff --git a/test/core/interface/interface.spec.js b/test/core/interface/interface.spec.js index 3d8e370981..810b7f2198 100644 --- a/test/core/interface/interface.spec.js +++ b/test/core/interface/interface.spec.js @@ -6,6 +6,7 @@ const isNode = require('detect-node') describe('interface-ipfs-core tests', () => { require('./block') + require('./bootstrap') require('./config') require('./files') require('./generic') diff --git a/test/http-api/interface/bootstrap.js b/test/http-api/interface/bootstrap.js new file mode 100644 index 0000000000..3f3df9b0d3 --- /dev/null +++ b/test/http-api/interface/bootstrap.js @@ -0,0 +1,31 @@ +/* eslint-env mocha */ +'use strict' + +const test = require('interface-ipfs-core') +const parallel = require('async/parallel') + +const DaemonFactory = require('ipfsd-ctl') +const df = DaemonFactory.create({ exec: 'src/cli/bin.js' }) + +const nodes = [] +const common = { + setup: function (callback) { + callback(null, { + spawnNode: (cb) => { + df.spawn((err, _ipfsd) => { + if (err) { + return cb(err) + } + + nodes.push(_ipfsd) + cb(null, _ipfsd.api) + }) + } + }) + }, + teardown: function (callback) { + parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) + } +} + +test.bootstrap(common) From 95365fa0634353999f96a1262d1a35d3b77314b4 Mon Sep 17 00:00:00 2001 From: Richard Schneider Date: Thu, 15 Feb 2018 23:38:13 +1300 Subject: [PATCH 29/32] feat: ipfs shutdown (#1200) * feat: route to shutdown daemon * feat: cli and http-api shutdown * chore: argggh fix the command count * chore: merge conflicts * chore: rebasing * chore: fix rebase errors * docs: add ipfs.shutdown * fix: always report state error when stopping * chore: documentation is 'stop' not 'shutdown' * fix: generic stop * fix: package.json --- README.md | 2 +- src/cli/commands/shutdown.js | 17 +++++++++++++++++ src/core/components/stop.js | 8 ++++---- src/core/index.js | 1 + src/http/api/resources/index.js | 1 + src/http/api/resources/shutdown.js | 14 ++++++++++++++ src/http/api/routes/index.js | 1 + src/http/api/routes/shutdown.js | 13 +++++++++++++ test/cli/commands.js | 2 +- test/core/interface/generic.js | 2 +- 10 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/cli/commands/shutdown.js create mode 100644 src/http/api/resources/shutdown.js create mode 100644 src/http/api/routes/shutdown.js diff --git a/README.md b/README.md index cb3373644f..e82d81d104 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.ping()` - `ipfs.init([options], callback)` - `ipfs.start([callback])` - - `ipfs.stop([callback])` + - [`ipfs.stop([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#stop) - `ipfs.isOnline()` - [config](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md) diff --git a/src/cli/commands/shutdown.js b/src/cli/commands/shutdown.js new file mode 100644 index 0000000000..99c6e8d6a7 --- /dev/null +++ b/src/cli/commands/shutdown.js @@ -0,0 +1,17 @@ +'use strict' + +module.exports = { + command: 'shutdown', + + describe: 'Shut down the ipfs daemon', + + builder: {}, + + handler (argv) { + argv.ipfs.shutdown((err) => { + if (err) { + throw err + } + }) + } +} diff --git a/src/core/components/stop.js b/src/core/components/stop.js index ad3957b546..a39900d09c 100644 --- a/src/core/components/stop.js +++ b/src/core/components/stop.js @@ -13,6 +13,10 @@ module.exports = (self) => { return callback(new Error('Already stopped')) } + if (self.state.state() !== 'running') { + return callback(new Error('Not able to stop from state: ' + self.state.state())) + } + const done = (err) => { if (err) { self.emit('error', err) @@ -23,10 +27,6 @@ module.exports = (self) => { callback() } - if (self.state.state() !== 'running') { - return done(new Error('Not able to stop from state: ' + self.state.state())) - } - self.state.stop() self._blockService.unsetExchange() self._bitswap.stop() diff --git a/src/core/index.js b/src/core/index.js index b0e5719b2f..83cc20cd37 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -77,6 +77,7 @@ class IPFS extends EventEmitter { this.preStart = components.preStart(this) this.start = components.start(this) this.stop = components.stop(this) + this.shutdown = this.stop this.isOnline = components.isOnline(this) // - interface-ipfs-core defined API this.version = components.version(this) diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index 42eec1d0b0..efc7785dbd 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -1,6 +1,7 @@ 'use strict' exports.version = require('./version') +exports.shutdown = require('./shutdown') exports.id = require('./id') exports.bootstrap = require('./bootstrap') exports.repo = require('./repo') diff --git a/src/http/api/resources/shutdown.js b/src/http/api/resources/shutdown.js new file mode 100644 index 0000000000..56f137cc91 --- /dev/null +++ b/src/http/api/resources/shutdown.js @@ -0,0 +1,14 @@ +'use strict' + +exports = module.exports + +/* + * Stop the daemon. + * + * Returns an empty response to the caller then + * on the next 'tick' emits SIGTERM. + */ +exports.do = (request, reply) => { + setImmediate(() => process.emit('SIGTERM')) + return reply() +} diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index 9e405ae6b5..aeba5f1427 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -2,6 +2,7 @@ module.exports = (server) => { require('./version')(server) + require('./shutdown')(server) require('./id')(server) require('./bootstrap')(server) require('./block')(server) diff --git a/src/http/api/routes/shutdown.js b/src/http/api/routes/shutdown.js new file mode 100644 index 0000000000..b3d8c9f8ef --- /dev/null +++ b/src/http/api/routes/shutdown.js @@ -0,0 +1,13 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/shutdown', + handler: resources.shutdown.do + }) +} diff --git a/test/cli/commands.js b/test/cli/commands.js index 1fabdc857f..50afc3240e 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,7 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 67 +const commandCount = 68 describe('commands', () => runOnAndOff((thing) => { let ipfs diff --git a/test/core/interface/generic.js b/test/core/interface/generic.js index b1b4fcca72..2393eed5f0 100644 --- a/test/core/interface/generic.js +++ b/test/core/interface/generic.js @@ -26,7 +26,7 @@ const common = { }) }, teardown: function (callback) { - // Stopped by the tests themselves + // No need to stop, because the test suite does a 'stop' test. // parallel(nodes.map((node) => (cb) => node.stop(cb)), callback) callback() } From 905bdc03edfba23d35aa6a5b8e356ab56f6f36b1 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 15 Feb 2018 11:02:22 +0000 Subject: [PATCH 30/32] feat: stats API (stats.bitswap and stats.repo) (#1198) --- README.md | 16 ++++++++---- package.json | 4 ++- src/cli/commands/bitswap/stat.js | 20 +++++++-------- src/cli/commands/repo/stat.js | 31 +++++++++++++++++++++++ src/cli/commands/repo/version.js | 3 ++- src/cli/commands/stats.js | 14 +++++++++++ src/cli/commands/stats/bitswap.js | 37 ++++++++++++++++++++++++++++ src/cli/commands/stats/repo.js | 31 +++++++++++++++++++++++ src/core/components/bitswap.js | 24 ++++++++++++++---- src/core/components/index.js | 1 + src/core/components/repo.js | 27 +++++++++++++++++--- src/core/components/start.js | 2 +- src/core/components/stats.js | 8 ++++++ src/core/index.js | 1 + src/http/api/resources/bitswap.js | 34 +++++++++++++++---------- src/http/api/resources/index.js | 1 + src/http/api/resources/repo.js | 41 +++++++++++++++++++++++++++++++ src/http/api/resources/stats.js | 7 ++++++ src/http/api/routes/index.js | 3 ++- src/http/api/routes/repo.js | 17 ++++++++++--- src/http/api/routes/stats.js | 23 +++++++++++++++++ test/cli/bitswap.js | 3 +-- test/cli/commands.js | 2 +- 23 files changed, 304 insertions(+), 46 deletions(-) create mode 100644 src/cli/commands/repo/stat.js create mode 100644 src/cli/commands/stats.js create mode 100644 src/cli/commands/stats/bitswap.js create mode 100644 src/cli/commands/stats/repo.js create mode 100644 src/core/components/stats.js create mode 100644 src/http/api/resources/stats.js create mode 100644 src/http/api/routes/stats.js diff --git a/README.md b/README.md index e82d81d104..7aa47baf01 100644 --- a/README.md +++ b/README.md @@ -256,11 +256,6 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - [`ipfs.block.put(block, cid, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md#put) - [`ipfs.block.stat(cid, [callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/BLOCK.md#stat) -- [repo](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/) - - `ipfs.repo.init` - - `ipfs.repo.version` - - `ipfs.repo.gc` (not implemented, yet!) - #### `Graph` - [dag](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/DAG.md) @@ -334,6 +329,17 @@ A complete API definition is in the works. Meanwhile, you can learn how to you u - `ipfs.start([callback])` - [`ipfs.stop([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/MISCELLANEOUS.md#stop) - `ipfs.isOnline()` + +- [repo](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/REPO.md) + - `ipfs.repo.init` + - [`ipfs.repo.stat([options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/REPO.md#stat) + - [`ipfs.repo.version([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/REPO.md#version) + - `ipfs.repo.gc([options, callback])` (not implemented, yet!) + +- [stats](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/STATS.md) + - [`ipfs.stats.bitswap([callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/STATS.md#bitswap) + - [`ipfs.stats.bw([options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/STATS.md#bw) (not implemented, yet!) + - [`ipfs.stats.repo([options, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/STATS.md#repo) - [config](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md) - [`ipfs.config.get([key, callback])`](https://github.com/ipfs/interface-ipfs-core/tree/master/SPEC/CONFIG.md#configget) diff --git a/package.json b/package.json index d07e1d9694..d927d3913d 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "form-data": "^2.3.2", "go-ipfs-dep": "^0.4.13", "hat": "0.0.3", - "interface-ipfs-core": "~0.51.0", + "interface-ipfs-core": "~0.52.0", "ipfsd-ctl": "~0.28.0", "left-pad": "^1.2.0", "lodash": "^4.17.5", @@ -90,6 +90,7 @@ }, "dependencies": { "async": "^2.6.0", + "big.js": "^5.0.3", "binary-querystring": "~0.1.2", "bl": "^1.2.1", "boom": "^7.1.1", @@ -107,6 +108,7 @@ "hoek": "^5.0.3", "ipfs-api": "^18.0.0", "ipfs-bitswap": "~0.19.0", + "human-to-milliseconds": "^1.0.0", "ipfs-block": "~0.6.1", "ipfs-block-service": "~0.13.0", "ipfs-multipart": "~0.1.0", diff --git a/src/cli/commands/bitswap/stat.js b/src/cli/commands/bitswap/stat.js index ef55ec0d1c..081dceb595 100644 --- a/src/cli/commands/bitswap/stat.js +++ b/src/cli/commands/bitswap/stat.js @@ -16,22 +16,22 @@ module.exports = { throw err } - stats.Wantlist = stats.Wantlist || [] - stats.Wantlist = stats.Wantlist.map((entry) => { + stats.wantlist = stats.wantlist || [] + stats.wantlist = stats.wantlist.map((entry) => { const buf = Buffer.from(entry.cid.hash.data) const cid = new CID(entry.cid.version, entry.cid.codec, buf) return cid.toBaseEncodedString() }) - stats.Peers = stats.Peers || [] + stats.peers = stats.peers || [] print(`bitswap status - blocks received: ${stats.BlocksReceived} - dup blocks received: ${stats.DupBlksReceived} - dup data received: ${stats.DupDataReceived}B - wantlist [${stats.Wantlist.length} keys] - ${stats.Wantlist.join('\n ')} - partners [${stats.Peers.length}] - ${stats.Peers.join('\n ')}`) + blocks received: ${stats.blocksReceived} + dup blocks received: ${stats.dupBlksReceived} + dup data received: ${stats.dupDataReceived}B + wantlist [${stats.wantlist.length} keys] + ${stats.wantlist.join('\n ')} + partners [${stats.peers.length}] + ${stats.peers.join('\n ')}`) }) } } diff --git a/src/cli/commands/repo/stat.js b/src/cli/commands/repo/stat.js new file mode 100644 index 0000000000..27f3f46ed1 --- /dev/null +++ b/src/cli/commands/repo/stat.js @@ -0,0 +1,31 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'stat', + + describe: 'Get stats for the currently used repo', + + builder: { + human: { + type: 'boolean', + default: false + } + }, + + handler (argv) { + argv.ipfs.repo.stat({human: argv.human}, (err, stats) => { + if (err) { + throw err + } + + print(`repo status + number of objects: ${stats.numObjects} + repo size: ${stats.repoSize} + repo path: ${stats.repoPath} + version: ${stats.version} + maximum storage: ${stats.storageMax}`) + }) + } +} diff --git a/src/cli/commands/repo/version.js b/src/cli/commands/repo/version.js index 462a571da2..9a0f5271a8 100644 --- a/src/cli/commands/repo/version.js +++ b/src/cli/commands/repo/version.js @@ -10,10 +10,11 @@ module.exports = { builder: {}, handler (argv) { - argv.ipfs.repo.version(function (err, version) { + argv.ipfs.repo.version((err, version) => { if (err) { throw err } + print(version) }) } diff --git a/src/cli/commands/stats.js b/src/cli/commands/stats.js new file mode 100644 index 0000000000..4eaa9adaa6 --- /dev/null +++ b/src/cli/commands/stats.js @@ -0,0 +1,14 @@ +'use strict' + +module.exports = { + command: 'stats ', + + description: 'Query IPFS statistics.', + + builder (yargs) { + return yargs.commandDir('stats') + }, + + handler (argv) { + } +} diff --git a/src/cli/commands/stats/bitswap.js b/src/cli/commands/stats/bitswap.js new file mode 100644 index 0000000000..b5c4fe48f1 --- /dev/null +++ b/src/cli/commands/stats/bitswap.js @@ -0,0 +1,37 @@ +'use strict' + +const CID = require('cids') +const print = require('../../utils').print + +module.exports = { + command: 'bitswap', + + describe: 'Show some diagnostic information on the bitswap agent.', + + builder: {}, + + handler (argv) { + argv.ipfs.stats.bitswap((err, stats) => { + if (err) { + throw err + } + + stats.wantlist = stats.wantlist || [] + stats.wantlist = stats.wantlist.map((entry) => { + const buf = Buffer.from(entry.cid.hash.data) + const cid = new CID(entry.cid.version, entry.cid.codec, buf) + return cid.toBaseEncodedString() + }) + stats.peers = stats.peers || [] + + print(`bitswap status + blocks received: ${stats.blocksReceived} + dup blocks received: ${stats.dupBlksReceived} + dup data received: ${stats.dupDataReceived}B + wantlist [${stats.wantlist.length} keys] + ${stats.wantlist.join('\n ')} + partners [${stats.peers.length}] + ${stats.peers.join('\n ')}`) + }) + } +} diff --git a/src/cli/commands/stats/repo.js b/src/cli/commands/stats/repo.js new file mode 100644 index 0000000000..366f2ae719 --- /dev/null +++ b/src/cli/commands/stats/repo.js @@ -0,0 +1,31 @@ +'use strict' + +const print = require('../../utils').print + +module.exports = { + command: 'repo', + + describe: 'Get stats for the currently used repo', + + builder: { + human: { + type: 'boolean', + default: false + } + }, + + handler (argv) { + argv.ipfs.stats.repo({human: argv.human}, (err, stats) => { + if (err) { + throw err + } + + print(`repo status + number of objects: ${stats.numObjects} + repo size: ${stats.repoSize} + repo path: ${stats.repoPath} + version: ${stats.version} + maximum storage: ${stats.storageMax}`) + }) + } +} diff --git a/src/core/components/bitswap.js b/src/core/components/bitswap.js index 6a1bffefc2..e148f8c165 100644 --- a/src/core/components/bitswap.js +++ b/src/core/components/bitswap.js @@ -1,6 +1,9 @@ 'use strict' const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR +const promisify = require('promisify-es6') +const setImmediate = require('async/setImmediate') +const Big = require('big.js') function formatWantlist (list) { return Array.from(list).map((e) => e[1]) @@ -16,16 +19,27 @@ module.exports = function bitswap (self) { const list = self._bitswap.getWantlist() return formatWantlist(list) }, - stat: () => { + + stat: promisify((callback) => { if (!self.isOnline()) { - throw new Error(OFFLINE_ERROR) + return setImmediate(() => callback(new Error(OFFLINE_ERROR))) } - return Object.assign({}, self._bitswap.stat().snapshot, { + const snapshot = self._bitswap.stat().snapshot + + callback(null, { + provideBufLen: parseInt(snapshot.providesBufferLength.toString()), + blocksReceived: new Big(snapshot.blocksReceived), wantlist: formatWantlist(self._bitswap.getWantlist()), - peers: self._bitswap.peers().map((id) => id.toB58String()) + peers: self._bitswap.peers().map((id) => id.toB58String()), + dupBlksReceived: new Big(snapshot.dupBlksReceived), + dupDataReceived: new Big(snapshot.dupDataReceived), + dataReceived: new Big(snapshot.dataReceived), + blocksSent: new Big(snapshot.blocksSent), + dataSent: new Big(snapshot.dataSent) }) - }, + }), + unwant: (key) => { if (!self.isOnline()) { throw new Error(OFFLINE_ERROR) diff --git a/src/core/components/index.js b/src/core/components/index.js index 4aea90db9e..4f4e410e43 100644 --- a/src/core/components/index.js +++ b/src/core/components/index.js @@ -22,3 +22,4 @@ exports.pubsub = require('./pubsub') exports.dht = require('./dht') exports.dns = require('./dns') exports.key = require('./key') +exports.stats = require('./stats') diff --git a/src/core/components/repo.js b/src/core/components/repo.js index eb488346a9..989e07fd9e 100644 --- a/src/core/components/repo.js +++ b/src/core/components/repo.js @@ -1,16 +1,37 @@ 'use strict' +const promisify = require('promisify-es6') + module.exports = function repo (self) { return { init: (bits, empty, callback) => { // 1. check if repo already exists }, - version: (callback) => { + version: promisify((callback) => { self._repo.version.get(callback) - }, + }), + + gc: () => {}, + + stat: promisify((options, callback) => { + if (typeof options === 'function') { + callback = options + options = {} + } + + self._repo.stat(options, (err, stats) => { + if (err) return callback(err) - gc: function () {}, + callback(null, { + numObjects: stats.numObjects, + repoSize: stats.repoSize, + repoPath: stats.repoPath, + version: stats.version.toString(), + storageMax: stats.storageMax + }) + }) + }), path: () => self._repo.path } diff --git a/src/core/components/start.js b/src/core/components/start.js index 9575c3e3c6..3004cca34d 100644 --- a/src/core/components/start.js +++ b/src/core/components/start.js @@ -45,7 +45,7 @@ module.exports = (self) => { self._bitswap = new Bitswap( self._libp2pNode, self._repo.blocks, - self._peerInfoBook + { statsEnabled: true } ) self._bitswap.start() diff --git a/src/core/components/stats.js b/src/core/components/stats.js new file mode 100644 index 0000000000..6bc7121301 --- /dev/null +++ b/src/core/components/stats.js @@ -0,0 +1,8 @@ +'use strict' + +module.exports = function stats (self) { + return { + bitswap: require('./bitswap')(self).stat, + repo: require('./repo')(self).stat + } +} diff --git a/src/core/index.js b/src/core/index.js index 83cc20cd37..2d0da3e53f 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -97,6 +97,7 @@ class IPFS extends EventEmitter { this.dht = components.dht(this) this.dns = components.dns(this) this.key = components.key(this) + this.stats = components.stats(this) if (this._options.EXPERIMENTAL.pubsub) { this.log('EXPERIMENTAL pubsub is enabled') diff --git a/src/http/api/resources/bitswap.js b/src/http/api/resources/bitswap.js index ed749ea004..da830c6415 100644 --- a/src/http/api/resources/bitswap.js +++ b/src/http/api/resources/bitswap.js @@ -21,19 +21,27 @@ exports.wantlist = (request, reply) => { } exports.stat = (request, reply) => { - let stats - try { - stats = request.server.app.ipfs.bitswap.stat() - } catch (err) { - return reply(boom.badRequest(err)) - } - - reply({ - BlocksReceived: stats.blocksReceived, - Wantlist: stats.wantlist, - Peers: stats.peers, - DupBlksReceived: stats.dupBlksReceived, - DupDataReceived: stats.dupDataReceived + const ipfs = request.server.app.ipfs + + ipfs.bitswap.stat((err, stats) => { + if (err) { + return reply({ + Message: err.toString(), + Code: 0 + }).code(500) + } + + reply({ + ProvideBufLen: stats.provideBufLen, + BlocksReceived: stats.blocksReceived, + Wantlist: stats.wantlist, + Peers: stats.peers, + DupBlksReceived: stats.dupBlksReceived, + DupDataReceived: stats.dupDataReceived, + DataReceived: stats.dataReceived, + BlocksSent: stats.blocksSent, + DataSent: stats.dataSent + }) }) } diff --git a/src/http/api/resources/index.js b/src/http/api/resources/index.js index efc7785dbd..08d8d7f2a1 100644 --- a/src/http/api/resources/index.js +++ b/src/http/api/resources/index.js @@ -15,3 +15,4 @@ exports.files = require('./files') exports.pubsub = require('./pubsub') exports.dns = require('./dns') exports.key = require('./key') +exports.stats = require('./stats') diff --git a/src/http/api/resources/repo.js b/src/http/api/resources/repo.js index ccacec309b..394fda548e 100644 --- a/src/http/api/resources/repo.js +++ b/src/http/api/resources/repo.js @@ -1 +1,42 @@ 'use strict' + +exports = module.exports + +exports.version = (request, reply) => { + const ipfs = request.server.app.ipfs + + ipfs.repo.version((err, version) => { + if (err) { + return reply({ + Message: err.toString(), + Code: 0 + }).code(500) + } + + reply({ + Version: version + }) + }) +} + +exports.stat = (request, reply) => { + const ipfs = request.server.app.ipfs + const human = request.query.human === 'true' + + ipfs.repo.stat({human: human}, (err, stat) => { + if (err) { + return reply({ + Message: err.toString(), + Code: 0 + }).code(500) + } + + reply({ + NumObjects: stat.numObjects, + RepoSize: stat.repoSize, + RepoPath: stat.repoPath, + Version: stat.version, + StorageMax: stat.storageMax + }) + }) +} diff --git a/src/http/api/resources/stats.js b/src/http/api/resources/stats.js new file mode 100644 index 0000000000..839f92a3b3 --- /dev/null +++ b/src/http/api/resources/stats.js @@ -0,0 +1,7 @@ +'use strict' + +exports = module.exports + +exports.bitswap = require('./bitswap').stat + +exports.repo = require('./repo').stat diff --git a/src/http/api/routes/index.js b/src/http/api/routes/index.js index aeba5f1427..2eeb4b137a 100644 --- a/src/http/api/routes/index.js +++ b/src/http/api/routes/index.js @@ -7,7 +7,7 @@ module.exports = (server) => { require('./bootstrap')(server) require('./block')(server) require('./object')(server) - // require('./repo')(server) + require('./repo')(server) require('./config')(server) require('./swarm')(server) require('./bitswap')(server) @@ -18,4 +18,5 @@ module.exports = (server) => { require('./webui')(server) require('./dns')(server) require('./key')(server) + require('./stats')(server) } diff --git a/src/http/api/routes/repo.js b/src/http/api/routes/repo.js index f42f03bfc1..3eb7ab2a88 100644 --- a/src/http/api/routes/repo.js +++ b/src/http/api/routes/repo.js @@ -2,13 +2,24 @@ const resources = require('./../resources') -// TODO module.exports = (server) => { const api = server.select('API') api.route({ method: '*', - path: '/api/v0/repo', - handler: resources.repo + path: '/api/v0/repo/version', + config: { + handler: resources.repo.version + } }) + + api.route({ + method: '*', + path: '/api/v0/repo/stat', + config: { + handler: resources.repo.stat + } + }) + + // TODO: implement the missing spec https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/REPO.md } diff --git a/src/http/api/routes/stats.js b/src/http/api/routes/stats.js new file mode 100644 index 0000000000..c167ec58c0 --- /dev/null +++ b/src/http/api/routes/stats.js @@ -0,0 +1,23 @@ +'use strict' + +const resources = require('./../resources') + +module.exports = (server) => { + const api = server.select('API') + + api.route({ + method: '*', + path: '/api/v0/stats/bitswap', + config: { + handler: resources.stats.bitswap + } + }) + + api.route({ + method: '*', + path: '/api/v0/stats/repo', + config: { + handler: resources.stats.repo + } + }) +} diff --git a/test/cli/bitswap.js b/test/cli/bitswap.js index 6652364f9b..29220f7b71 100644 --- a/test/cli/bitswap.js +++ b/test/cli/bitswap.js @@ -23,8 +23,7 @@ describe('bitswap', () => runOn((thing) => { }) }) - // TODO @hacdias fix this with https://github.com/ipfs/js-ipfs/pull/1198 - it.skip('stat', function () { + it('stat', function () { this.timeout(20 * 1000) return ipfs('bitswap stat').then((out) => { diff --git a/test/cli/commands.js b/test/cli/commands.js index 50afc3240e..d1d0812957 100644 --- a/test/cli/commands.js +++ b/test/cli/commands.js @@ -4,7 +4,7 @@ const expect = require('chai').expect const runOnAndOff = require('../utils/on-and-off') -const commandCount = 68 +const commandCount = 72 describe('commands', () => runOnAndOff((thing) => { let ipfs From a0fd3550e161f0afe583dc8cb0f0e19b1ec0f962 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 17 Feb 2018 09:23:02 +0000 Subject: [PATCH 31/32] fix: stats tests --- test/core/bitswap.spec.js | 41 ++++++++++++++++++++--------------- test/http-api/spec/bitswap.js | 17 ++++++++------- 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/test/core/bitswap.spec.js b/test/core/bitswap.spec.js index 029ee03072..ec46f6f3fb 100644 --- a/test/core/bitswap.spec.js +++ b/test/core/bitswap.spec.js @@ -259,8 +259,11 @@ describe('bitswap', function () { expect(() => node.bitswap.wantlist()).to.throw(/online/) }) - it('.stat throws while offline', () => { - expect(() => node.bitswap.stat()).to.throw(/online/) + it('.stat gives error while offline', () => { + node.bitswap.stat((err, stats) => { + expect(err).to.exist() + expect(stats).to.not.exist() + }) }) it('throws if offline', () => { @@ -279,22 +282,24 @@ describe('bitswap', function () { expect(node.bitswap.wantlist()).to.eql([]) }) - it('returns the stats', () => { - let stats = node.bitswap.stat() - - expect(stats).to.have.keys([ - 'blocksReceived', - 'blocksSent', - 'dataReceived', - 'dataSent', - 'wantListLength', - 'wantlist', - 'peerCount', - 'peers', - 'providesBufferLength', - 'dupDataReceived', - 'dupBlksReceived' - ]) + it('returns the stats', (done) => { + node.bitswap.stat((err, stats) => { + expect(err).to.not.exist() + expect(stats).to.have.keys([ + 'blocksReceived', + 'blocksSent', + 'dataReceived', + 'dataSent', + 'wantListLength', + 'wantlist', + 'peerCount', + 'peers', + 'providesBufferLength', + 'dupDataReceived', + 'dupBlksReceived' + ]) + done() + }) }) }) }) diff --git a/test/http-api/spec/bitswap.js b/test/http-api/spec/bitswap.js index f290dc9661..16e2c6ceef 100644 --- a/test/http-api/spec/bitswap.js +++ b/test/http-api/spec/bitswap.js @@ -28,14 +28,15 @@ module.exports = (http) => { url: '/api/v0/bitswap/stat' }, (res) => { expect(res.statusCode).to.equal(200) - - expect(res.result).to.have.keys([ - 'BlocksReceived', - 'Wantlist', - 'Peers', - 'DupBlksReceived', - 'DupDataReceived' - ]) + expect(res.result).to.have.property('ProvideBufLen') + expect(res.result).to.have.property('BlocksReceived') + expect(res.result).to.have.property('Wantlist') + expect(res.result).to.have.property('Peers') + expect(res.result).to.have.property('DupBlksReceived') + expect(res.result).to.have.property('DupDataReceived') + expect(res.result).to.have.property('DataReceived') + expect(res.result).to.have.property('BlocksSent') + expect(res.result).to.have.property('DataSent') done() }) }) From caa9556df0c95cf49cc9bb9ce483d5dcab37c23f Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Sat, 17 Feb 2018 09:24:29 +0000 Subject: [PATCH 32/32] fix one more test --- test/core/bitswap.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/core/bitswap.spec.js b/test/core/bitswap.spec.js index ec46f6f3fb..b0260ed5ff 100644 --- a/test/core/bitswap.spec.js +++ b/test/core/bitswap.spec.js @@ -290,11 +290,9 @@ describe('bitswap', function () { 'blocksSent', 'dataReceived', 'dataSent', - 'wantListLength', 'wantlist', - 'peerCount', 'peers', - 'providesBufferLength', + 'provideBufLen', 'dupDataReceived', 'dupBlksReceived' ])