From 06eb576d40f594c6def941e0948a03e4c9b3dd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kristoffer=20Str=C3=B6m?= Date: Thu, 21 May 2015 03:29:04 +0200 Subject: [PATCH] First draft --- .gitignore | 1 + index.js | 79 ++++++++++++++++++++++++++ package.json | 21 ++++++- test/test.js | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 255 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 index.js create mode 100644 test/test.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3c3629e6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/index.js b/index.js new file mode 100644 index 00000000..2ec31af5 --- /dev/null +++ b/index.js @@ -0,0 +1,79 @@ +var run = require('comandante') +var _ = require('lodash') +var Q = require('kew') +var ipfs = require('ipfs-api') +var waterfall = require('promise-waterfall') + +function configureNode (node, conf, cb) { + var delay = 0 + waterfall(_.map(conf, function (value, key) { + return function () { + var def = Q.defer() + run('ipfs', ['config', key, value]) + .on('error', function (err) { cb(err) }) + .on('end', function () { def.resolve() }) + return def.promise + } + })).then(function () { + cb(null, true) + }) +} + +var ctl = function (path) { + var env = process.env + env.IPFS_PATH = path + return { + path: path, + init: function (opts, cb) { + var t = this + if (!cb) cb = opts + var buf = '' + run('ipfs', ['init'], {env: env}) + .on('error', function (err) { cb(err) }) + .on('data', function (data) { buf += data }) + .on('end', function () { + configureNode(t, opts, function (err) { + if (err) return cb(err) + cb(null, buf) + }) + }) + }, + getConf: function (key, cb) { + var result = '' + run('ipfs', ['config', key]) + .on('error', function (err) { cb(err) }) + .on('data', function (data) { result += data }) + .on('end', function () { cb(null, result.trim()) }) + }, + daemon: function (opts, cb) { + if (!cb) cb = opts + var t = this + var running = run('ipfs', ['daemon'], {env: env}) + + running + .on('error', function (err) { cb(err) }) + .on('data', function (data) { + if ((data + '').match(/API server listening/)) { + t.getConf('Addresses.API', function (err, value) { + if (err) throw err + var split = value.split('/') + t.pid = running.pid + cb(null, ipfs('127.0.0.1', split[split.length - 1]), t.pid) + }) + } + }) + }, + stop: function (cb) { + if (this.pid) { + run('kill', [this.pid]) + .on('error', function (err) { cb(err) }) + .on('end', function () { cb(null) }) + } else { + // not started, no problem + cb(null) + } + } + } +} + +module.exports = ctl diff --git a/package.json b/package.json index a278136f..33cb77d7 100644 --- a/package.json +++ b/package.json @@ -4,19 +4,33 @@ "description": "simple controls for an ipfs node", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "mocha test", + "lint": "git diff --name-only --cached --relative | egrep .js$ | xargs --no-run-if-empty standard" }, + "pre-commit": [ + "test" + ], "keywords": [ "ipfs", "node", "daemon" ], "author": "Juan Benet (http://juan.benet.ai/)", + "contributors": [ + "Kristoffer Ström " + ], "license": "MIT", "dependencies": { + "lodash": "^3.6.0", + "promise-waterfall" : "0.1.0", + "kew": "^0.5.0", + "ipfs-api": "^1.2.1", "comandante": "0.0.1" }, - "devDependencies": {}, + "devDependencies": { + "mocha": "2.2.5", + "rimraf": "2.3.4" + }, "repository": { "type": "git", "url": "https://github.com/ipfs/node-ipfsd-ctl.git" @@ -24,5 +38,6 @@ "bugs": { "url": "https://github.com/ipfs/node-ipfsd-ctl/issues" }, - "homepage": "https://github.com/ipfs/node-ipfsd-ctl" + "homepage": "https://github.com/ipfs/node-ipfsd-ctl", + "license": "MIT" } diff --git a/test/test.js b/test/test.js new file mode 100644 index 00000000..15210ca1 --- /dev/null +++ b/test/test.js @@ -0,0 +1,157 @@ +var run = require('comandante') +var ipfsd = require('../index.js') +var assert = require('assert') +var fs = require('fs') +var rimraf = require('rimraf') + +var tempDirectories = [] +function tmpDirectory () { + var dir = '/tmp/ipfs_' + (Math.random() + '').substr(2) + tempDirectories.push(dir) + return dir +} + +function randomPort () { + // pick a really high port to make collisions unlikely enough + return Math.floor((Math.random() * (65535 - 10000))) + 10000 +} + +function cleanup (done) { + for (var i = 0; i < tempDirectories.length; i++) { + rimraf(tempDirectories[i], function () {}) + } + tempDirectories = [] + done() +} + +describe('single node', function () { + var apiPort = randomPort() + var gatewayPort = randomPort() + + var api = '/ip4/127.0.0.1/tcp/' + apiPort + var gateway = '/ip4/127.0.0.1/tcp/' + gatewayPort + + var node = ipfsd(tmpDirectory()) + + describe('init', function () { + var result + + // 10 seconds should be enough for everyone + this.timeout(10000) + + before(function (done) { + node.init({'Addresses.Gateway': gateway, + 'Addresses.API': api}, + function (err, res) { + if (err) throw err + result = res + done() + }) + }) + + it('should have setup a node', function () { + assert(result.match(/initializing ipfs node at/)) + }) + }) + + describe('check gateway conf', function () { + var testgateway = '' + + before(function (done) { + node.getConf('Addresses.Gateway', function (err, res) { + if (err) throw err + testgateway = res + done() + }) + }) + + it('should have the correct gateway addr configured', function () { + assert.equal(testgateway.trim(), gateway) + }) + }) + + describe('check api conf', function () { + var testapi = '' + + before(function (done) { + node.getConf('Addresses.API', function (err, res) { + if (err) throw err + testapi = res + done() + }) + }) + + it('should have the correct api addr configured', function () { + assert.equal(testapi.trim(), api) + }) + }) + + describe('start daemon', function () { + var ipfs + + this.timeout(10000) + + before(function (done) { + node.daemon(function (err, api) { + if (err) throw err + ipfs = api + done() + }) + }) + + it('should have started the daemon and returned an api', function () { + assert(ipfs) + assert(ipfs.add) + }) + + var store, retrieve + + before(function (done) { + var blorb = Buffer('blorb') + ipfs.block.put(blorb, function (err, res) { + if (err) throw err + store = res.Key + + ipfs.block.get(res.Key, function (err, res) { + if (err) throw err + retrieve = res + + var buf = '' + res + .on('data', function (data) { buf += data }) + .on('end', function () { + retrieve = buf + done() + }) + }) + }) + }) + + it('should be able to store objects', function () { + assert.equal(store, 'QmPv52ekjS75L4JmHpXVeuJ5uX2ecSfSZo88NSyxwA3rAQ') + }) + + it('should be able to retrieve objects', function () { + assert.equal(retrieve, 'blorb') + }) + }) + + describe('stop deamon', function () { + var killed = false + before(function (done) { + node.stop(function (err) { + if (err) throw err + killed = true + done() + }) + }) + + it('should have killed the process', function () { + assert(killed) + }) + }) + + after(function (done) { + cleanup(done) + }) +})