Skip to content

Commit

Permalink
feat: Add configurable $IPFS_EXEC
Browse files Browse the repository at this point in the history
  • Loading branch information
dignifiedquire committed Nov 13, 2015
1 parent 99b16d5 commit 5aa011b
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 168 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,5 @@ ipfsd.disposableApi(function (err, ipfs) {
})
})
```

If you need want to use an existing ipfs installation you can set `$IPFS_EXEC=/path/to/ipfs` to ensure it uses that.
170 changes: 3 additions & 167 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,181 +1,17 @@
'use strict'

const fs = require('fs')
const os = require('os')
const join = require('path').join
const run = require('subcomandante')
const async = require('async')
const ipfs = require('ipfs-api')
const multiaddr = require('multiaddr')
const rimraf = require('rimraf')
const shutdown = require('shutdown')

const IPFS_EXEC = require('go-ipfs')
const GRACE_PERIOD = 7500 // amount of ms to wait before sigkill

function configureNode (node, conf, done) {
if (Object.keys(conf).length > 0) {
async.forEachOfSeries(conf, (value, key, cb) => {
const env = {env: node.env}

run(IPFS_EXEC, ['config', key, '--json', JSON.stringify(value)], env)
.on('error', cb)
.on('end', cb)
}, done)
} else {
done()
}
}
const Node = require('./lib/node')

function tempDir () {
return join(os.tmpdir(), `ipfs_${(Math.random() + '').substr(2)}`)
}

// Consistent error handling
function parseConfig (path, done) {
try {
const file = fs.readFileSync(join(path, 'config'))
const parsed = JSON.parse(file)
done(null, parsed)
} catch (err) {
done(err)
}
}

function Node (path, opts, disposable) {
const env = Object.assign({}, process.env, {IPFS_PATH: path})

if (opts.env) Object.assign(env, opts.env)

return {
subprocess: null,
initialized: fs.existsSync(path),
clean: true,
path: path,
opts: opts,
env: env,
init (initOpts, done) {
if (!done) {
done = initOpts
initOpts = {}
}
let buf = ''

const keySize = initOpts.keysize || 2048

if (initOpts.directory && initOpts.directory !== path) {
path = initOpts.directory
this.env.IPFS_PATH = path
}

run(IPFS_EXEC, ['init', '-b', keySize], {env: this.env})
.on('error', done)
.on('data', data => buf += data)
.on('end', () => {
configureNode(this, this.opts, err => {
if (err) return done(err)
this.clean = false
this.initialized = true
done(null, this)
})
})

if (disposable) {
shutdown.addHandler('disposable', 1, this.shutdown.bind(this))
}
},
// cleanup tmp files
shutdown (done) {
if (!this.clean && disposable) {
rimraf(this.path, err => {
if (err) throw err
done()
})
}
},
startDaemon (done) {
parseConfig(this.path, (err, conf) => {
if (err) return done(err)

this.subprocess = run(IPFS_EXEC, ['daemon'], {env: this.env})
.on('error', err => {
if ((err + '').match('daemon is running')) {
// we're good
done(null, ipfs(conf.Addresses.API))
} else if ((err + '').match('non-zero exit code')) {
// ignore when kill -9'd
} else {
done(err)
}
})
.on('data', data => {
const match = (data + '').trim().match(/API server listening on (.*)/)
if (match) {
this.apiAddr = match[1]
const addr = multiaddr(this.apiAddr).nodeAddress()
const api = ipfs(this.apiAddr)
api.apiHost = addr.address
api.apiPort = addr.port
done(null, api)
}
})
})
},
stopDaemon (done) {
if (!done) done = () => {}
if (!this.subprocess) return done(null)

this.subprocess.kill('SIGTERM')

const timeout = setTimeout(() => {
this.subprocess.kill('SIGKILL')
done(null)
}, GRACE_PERIOD)

this.subprocess.on('close', () => {
clearTimeout(timeout)
done(null)
})

this.subprocess = null
},
daemonPid () {
return this.subprocess && this.subprocess.pid
},
getConfig (key, done) {
if (typeof key === 'function') {
done = key
key = ''
}
let result = ''
run(IPFS_EXEC, ['config', key], {env: this.env})
.on('error', done)
.on('data', data => result += data)
.on('end', () => done(null, result.trim()))
},
setConfig (key, value, done) {
run(IPFS_EXEC, ['config', key, value, '--json'], {env: this.env})
.on('error', done)
.on('data', data => {})
.on('end', () => done())
},
replaceConf (file, done) {
let result = ''
run(IPFS_EXEC, ['config', 'replace', file], {env: this.env})
.on('error', done)
.on('data', data => result += data)
.on('end', () => done(null, result.trim()))
}
}
}

module.exports = {
version (done) {
let buf = ''
run(IPFS_EXEC, ['version'])
.on('error', done)
.on('data', data => buf += data)
.on('end', () => done(null, buf))
(new Node()).version(done)
},
local (path, done) {
if (!done) {
Expand All @@ -184,7 +20,7 @@ module.exports = {
join(process.env.HOME ||
process.env.USERPROFILE, '.ipfs')
}
done(null, new Node(path, {}))
done(null, new Node(path))
},
disposableApi (opts, done) {
if (typeof opts === 'function') {
Expand Down
169 changes: 169 additions & 0 deletions lib/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
'use strict'

const fs = require('fs')
const join = require('path').join
const run = require('subcomandante')
const async = require('async')
const ipfs = require('ipfs-api')
const multiaddr = require('multiaddr')
const rimraf = require('rimraf')
const shutdown = require('shutdown')

const ipfsDefaultPath = require('go-ipfs')
const GRACE_PERIOD = 7500 // amount of ms to wait before sigkill

function configureNode (node, conf, done) {
if (Object.keys(conf).length > 0) {
async.forEachOfSeries(conf, (value, key, cb) => {
const env = {env: node.env}

run(node.exec, ['config', key, '--json', JSON.stringify(value)], env)
.on('error', cb)
.on('end', cb)
}, done)
} else {
done()
}
}

// Consistent error handling
function parseConfig (path, done) {
try {
const file = fs.readFileSync(join(path, 'config'))
const parsed = JSON.parse(file)
done(null, parsed)
} catch (err) {
done(err)
}
}

module.exports = function Node (path, opts, disposable) {
const env = Object.assign({}, process.env, {IPFS_PATH: path})
opts = opts || {}
if (opts.env) Object.assign(env, opts.env)

return {
_run (args, envArg, done) {
let result = ''
run(this.exec, args, envArg)
.on('error', done)
.on('data', data => result += data)
.on('end', () => done(null, result.trim()))
},
exec: process.env.IPFS_EXEC || ipfsDefaultPath,
subprocess: null,
initialized: fs.existsSync(path),
clean: true,
path: path,
opts: opts,
env: env,
init (initOpts, done) {
if (!done) {
done = initOpts
initOpts = {}
}
let buf = ''

const keySize = initOpts.keysize || 2048

if (initOpts.directory && initOpts.directory !== path) {
path = initOpts.directory
this.env.IPFS_PATH = path
}

run(this.exec, ['init', '-b', keySize], {env: this.env})
.on('error', done)
.on('data', data => buf += data)
.on('end', () => {
configureNode(this, this.opts, err => {
if (err) return done(err)
this.clean = false
this.initialized = true
done(null, this)
})
})

if (disposable) {
shutdown.addHandler('disposable', 1, this.shutdown.bind(this))
}
},
// cleanup tmp files
shutdown (done) {
if (!this.clean && disposable) {
rimraf(this.path, err => {
if (err) throw err
done()
})
}
},
startDaemon (done) {
parseConfig(this.path, (err, conf) => {
if (err) return done(err)

this.subprocess = run(this.exec, ['daemon'], {env: this.env})
.on('error', err => {
if ((err + '').match('daemon is running')) {
// we're good
done(null, ipfs(conf.Addresses.API))
} else if ((err + '').match('non-zero exit code')) {
// ignore when kill -9'd
} else {
done(err)
}
})
.on('data', data => {
const match = (data + '').trim().match(/API server listening on (.*)/)
if (match) {
this.apiAddr = match[1]
const addr = multiaddr(this.apiAddr).nodeAddress()
const api = ipfs(this.apiAddr)
api.apiHost = addr.address
api.apiPort = addr.port
done(null, api)
}
})
})
},
stopDaemon (done) {
if (!done) done = () => {}
if (!this.subprocess) return done(null)

this.subprocess.kill('SIGTERM')

const timeout = setTimeout(() => {
this.subprocess.kill('SIGKILL')
done(null)
}, GRACE_PERIOD)

this.subprocess.on('close', () => {
clearTimeout(timeout)
done(null)
})

this.subprocess = null
},
daemonPid () {
return this.subprocess && this.subprocess.pid
},
getConfig (key, done) {
if (typeof key === 'function') {
done = key
key = ''
}

this._run(['config', key], {env: this.env}, done)
},
setConfig (key, value, done) {
run(this.exec, ['config', key, value, '--json'], {env: this.env})
.on('error', done)
.on('data', data => {})
.on('end', () => done())
},
replaceConf (file, done) {
this._run(['config', 'replace', file], {env: this.env}, done)
},
version (done) {
this._run(['version'], {}, done)
}
}
}
Loading

0 comments on commit 5aa011b

Please sign in to comment.