From c1dc38df4adae8c4afdf173fd1c21f40279352fa Mon Sep 17 00:00:00 2001 From: achingbrain Date: Wed, 30 May 2018 11:08:19 +0100 Subject: [PATCH] feat: read config from repo Lets us do things like `jsipfs config --bool EXPERIMENTAL.pubsub true` and have IPFS respect the flags in daemon and non-daemon mode License: MIT Signed-off-by: Alex Potsides --- README.md | 14 ++++++++ package.json | 1 + src/core/index.js | 61 ++++++++++++++++++++++++-------- test/core/options.spec.js | 74 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 test/core/options.spec.js diff --git a/README.md b/README.md index a373615839..99edfe6883 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ You can check the development status at the [Waffle Board](https://waffle.io/ipf - [IPFS CLI](#ipfs-cli) - [IPFS Daemon](#ipfs-daemon) - [IPFS Module (use IPFS as a module in Node.js or in the Browser)](#ipfs-module) + - [Experimental Features](#experimental-features) - [Tutorials and Examples](#tutorials-and-examples) - [API Docs](#api) - [Constructor](#ipfs-constructor) @@ -187,6 +188,19 @@ node.on('ready', () => { }) ``` +### Experimental Features + +To enable or disable experimental features, please use the `jsipfs config` command: + +```sh +$ jsipfs config --bool EXPERIMENTAL.pubsub true +$ jsipfs config --bool EXPERIMENTAL.pubsub false +``` + +If running the daemon you will need to restart it for this to take effect. + +See the `EXPERIMENTAL` options object passed to the IPFS constructor for which keys map to which experimental features. + ### [Tutorials and Examples](/examples) You can find some examples and tutorials in the [examples](/examples) folder, these exist to help you get started using `js-ipfs`. diff --git a/package.json b/package.json index 5273356eb6..192df1397d 100644 --- a/package.json +++ b/package.json @@ -135,6 +135,7 @@ "libp2p-webrtc-star": "~0.15.0", "libp2p-websocket-star": "~0.8.0", "libp2p-websockets": "~0.12.0", + "lodash.defaultsdeep": "^4.6.0", "lodash.flatmap": "^4.5.0", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", diff --git a/src/core/index.js b/src/core/index.js index 0b19160429..959a94c082 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -16,6 +16,9 @@ const CID = require('cids') const debug = require('debug') const extend = require('deep-extend') const EventEmitter = require('events') +const waterfall = require('async/waterfall') +const series = require('async/series') +const defaults = require('lodash.defaultsdeep') const config = require('./config') const boot = require('./boot') @@ -109,20 +112,6 @@ class IPFS extends EventEmitter { 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') - } - if (this._options.EXPERIMENTAL.sharding) { - this.log('EXPERIMENTAL sharding is enabled') - } - if (this._options.EXPERIMENTAL.dht) { - this.log('EXPERIMENTAL Kademlia DHT is enabled') - } - if (this._options.EXPERIMENTAL.relay) { - this.log('EXPERIMENTAL Relay is enabled') - } - this.state = require('./state')(this) // ipfs.ls @@ -136,7 +125,49 @@ class IPFS extends EventEmitter { isIPFS: isIPFS } - boot(this) + series([ + (cb) => { + waterfall([ + (done) => this._repo.config.get((error, config) => { + if (error) { + this.log('Could not load config', error) + } + + done(null, config || {}) + }), + (config, done) => { + this._options = defaults({}, config, this._options) + + done() + } + ], cb) + }, + (cb) => { + if (this._options.EXPERIMENTAL.pubsub) { + this.log('EXPERIMENTAL pubsub is enabled') + } + + if (this._options.EXPERIMENTAL.sharding) { + this.log('EXPERIMENTAL sharding is enabled') + } + + if (this._options.EXPERIMENTAL.dht) { + this.log('EXPERIMENTAL Kademlia DHT is enabled') + } + + if (this._options.EXPERIMENTAL.relay) { + this.log('EXPERIMENTAL Relay is enabled') + } + + cb() + } + ], (error) => { + if (error) { + return this.emit('error', error) + } + + boot(this) + }) } } diff --git a/test/core/options.spec.js b/test/core/options.spec.js new file mode 100644 index 0000000000..08d5d897f7 --- /dev/null +++ b/test/core/options.spec.js @@ -0,0 +1,74 @@ +/* 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 IPFS = require('../../src/core') +const parallel = require('async/parallel') + +// This gets replaced by `create-repo-browser.js` in the browser +const createTempRepo = require('../utils/create-repo-nodejs.js') + +describe('options', () => { + let repos = [] + let repo + + beforeEach(() => { + repo = createTempRepo() + repos.push(repo) + }) + + afterEach((done) => { + parallel( + repos.map(repo => (cb) => repo.teardown(cb)), + done + ) + }) + + it('should merge options with repo config', (done) => { + let ipfs = new IPFS({ + repo: repo, + init: true, + start: false + }) + + expect(ipfs._options.EXPERIMENTAL).to.deep.equal({}) + + ipfs.once('ready', () => { + // no experimental options have been set + expect(ipfs._options.EXPERIMENTAL).to.deep.equal({}) + + // set an experimental option + repo.config.set('EXPERIMENTAL.pubsub', true, (error) => { + if (error) { + return done(error) + } + + ipfs = new IPFS({ + repo: repo, + init: true, + start: false, + EXPERIMENTAL: { + sharding: true + } + }) + + // should only have the experimental option we passed to the constructor + expect(ipfs._options.EXPERIMENTAL).to.deep.equal({sharding: true}) + + ipfs.once('ready', () => { + // should have read experimental options from repo config and merged with constructor args + expect(ipfs._options.EXPERIMENTAL).to.deep.equal({ + sharding: true, + pubsub: true + }) + + done() + }) + }) + }) + }) +})