Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

Commit

Permalink
refactor: ipns routing logic moved to instantiation (#1701)
Browse files Browse the repository at this point in the history
  • Loading branch information
vasco-santos authored and Alan Shaw committed Nov 19, 2018
1 parent eacd580 commit a0642ed
Show file tree
Hide file tree
Showing 15 changed files with 551 additions and 200 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"ncp": "^2.0.0",
"qs": "^6.5.2",
"rimraf": "^2.6.2",
"sinon": "^7.1.1",
"stream-to-promise": "^2.2.0"
},
"dependencies": {
Expand All @@ -87,6 +88,7 @@
"byteman": "^1.3.5",
"cid-tool": "~0.1.0",
"cids": "~0.5.5",
"datastore-core": "~0.6.0",
"debug": "^4.1.0",
"deep-extend": "~0.6.0",
"err-code": "^1.1.2",
Expand Down
11 changes: 11 additions & 0 deletions src/core/components/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const defaultsDeep = require('@nodeutils/defaults-deep')
const defaultConfig = require('../runtime/config-nodejs.js')
const Keychain = require('libp2p-keychain')

const IPNS = require('../ipns')
const OfflineDatastore = require('../ipns/routing/offline-datastore')

const addDefaultAssets = require('./init-assets')

module.exports = function init (self) {
Expand Down Expand Up @@ -105,6 +108,14 @@ module.exports = function init (self) {
cb(null, true)
}
},
// Setup the offline routing for IPNS.
// This is primarily used for offline ipns modifications, such as the initializeKeyspace feature.
(_, cb) => {
const offlineDatastore = new OfflineDatastore(self._repo)

self._ipns = new IPNS(offlineDatastore, self._repo, self._peerInfo, self._keychain, self._options)
cb(null, true)
},
// add empty unixfs dir object (go-ipfs assumes this exists)
(_, cb) => {
if (opts.emptyRepo) {
Expand Down
7 changes: 3 additions & 4 deletions src/core/components/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ module.exports = function name (self) {
const nocache = options.nocache && options.nocache.toString() === 'true'
const recursive = options.recursive && options.recursive.toString() === 'true'

const local = true // TODO ROUTING - use self._options.local
const local = self._options.local

if (!self.isOnline() && !local) {
const errMsg = utils.OFFLINE_ERROR
Expand Down Expand Up @@ -157,11 +157,10 @@ module.exports = function name (self) {

const resolveOptions = {
nocache,
recursive,
local
recursive
}

self._ipns.resolve(name, self._peerInfo.id, resolveOptions, callback)
self._ipns.resolve(name, resolveOptions, callback)
})
}
}
18 changes: 18 additions & 0 deletions src/core/components/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const series = require('async/series')
const Bitswap = require('ipfs-bitswap')
const setImmediate = require('async/setImmediate')
const promisify = require('promisify-es6')
const { TieredDatastore } = require('datastore-core')

const IPNS = require('../ipns')
const OfflineDatastore = require('../ipns/routing/offline-datastore')

module.exports = (self) => {
return promisify((callback) => {
Expand Down Expand Up @@ -34,6 +38,20 @@ module.exports = (self) => {
},
(cb) => self.libp2p.start(cb),
(cb) => {
// Setup online routing for IPNS with a tiered routing composed by a DHT and a Pubsub router (if properly enabled)
const ipnsStores = []

// TODO Add IPNS pubsub if enabled

// NOTE: IPNS routing is being replaced by the local repo datastore while the IPNS over DHT is not ready
// When DHT is added, if local option enabled, should receive offlineDatastore as well
const offlineDatastore = new OfflineDatastore(self._repo)
ipnsStores.push(offlineDatastore)

// Create ipns routing with a set of datastores
const routing = new TieredDatastore(ipnsStores)
self._ipns = new IPNS(routing, self._repo, self._peerInfo, self._keychain, self._options)

self._bitswap = new Bitswap(
self._libp2pNode,
self._repo.blocks,
Expand Down
4 changes: 2 additions & 2 deletions src/core/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const EventEmitter = require('events')
const config = require('./config')
const boot = require('./boot')
const components = require('./components')
const IPNS = require('./ipns')

// replaced by repo-browser when running in the browser
const defaultRepo = require('./runtime/repo-nodejs')
const preload = require('./preload')
Expand Down Expand Up @@ -126,7 +126,7 @@ class IPFS extends EventEmitter {
})
this._preload = preload(this)
this._mfsPreload = mfsPreload(this)
this._ipns = new IPNS(null, this)
this._ipns = undefined

// IPFS Core exposed components
// - for booting up a node
Expand Down
28 changes: 22 additions & 6 deletions src/core/ipns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { createFromPrivKey } = require('peer-id')
const series = require('async/series')
const Receptacle = require('receptacle')

const errcode = require('err-code')
const debug = require('debug')
const log = debug('jsipfs:ipns')
log.error = debug('jsipfs:ipns:error')
Expand All @@ -16,11 +17,12 @@ const path = require('./path')
const defaultRecordTtl = 60 * 1000

class IPNS {
constructor (routing, ipfs) {
this.publisher = new IpnsPublisher(routing, ipfs._repo)
this.republisher = new IpnsRepublisher(this.publisher, ipfs)
this.resolver = new IpnsResolver(routing, ipfs._repo)
constructor (routing, repo, peerInfo, keychain, options) {
this.publisher = new IpnsPublisher(routing, repo)
this.republisher = new IpnsRepublisher(this.publisher, repo, peerInfo, keychain, options)
this.resolver = new IpnsResolver(routing)
this.cache = new Receptacle({ max: 1000 }) // Create an LRU cache with max 1000 items
this.routing = routing
}

// Publish
Expand Down Expand Up @@ -53,7 +55,21 @@ class IPNS {
}

// Resolve
resolve (name, peerId, options, callback) {
resolve (name, options, callback) {
if (typeof name !== 'string') {
const errMsg = `name received is not valid`

log.error(errMsg)
return callback(errcode(new Error(errMsg), 'ERR_INVALID_NAME'))
}

if (typeof options === 'function') {
callback = options
options = {}
}

options = options || {}

// If recursive, we should not try to get the cached value
if (!options.nocache && !options.recursive) {
// Try to get the record from cache
Expand All @@ -67,7 +83,7 @@ class IPNS {
}
}

this.resolver.resolve(name, peerId, options, (err, result) => {
this.resolver.resolve(name, options, (err, result) => {
if (err) {
log.error(err)
return callback(err)
Expand Down
8 changes: 1 addition & 7 deletions src/core/ipns/path.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@ const resolvePath = (ipfsNode, name, callback) => {
if (isIPFS.ipnsPath(name)) {
log(`resolve ipns path ${name}`)

const local = true // TODO ROUTING - use self._options.local

const options = {
local: local
}

return ipfsNode._ipns.resolve(name, ipfsNode._peerInfo.id, options, callback)
return ipfsNode._ipns.resolve(name, callback)
}

// ipfs path
Expand Down
20 changes: 10 additions & 10 deletions src/core/ipns/publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class IpnsPublisher {

PeerId.createFromPrivKey(privKey.bytes, (err, peerId) => {
if (err) {
callback(err)
return callback(err)
}

this._updateOrCreateRecord(privKey, value, lifetime, peerId, (err, record) => {
Expand Down Expand Up @@ -67,17 +67,17 @@ class IpnsPublisher {

let keys
try {
keys = ipns.getIdKeys(peerId.id)
keys = ipns.getIdKeys(peerId.toBytes())
} catch (err) {
log.error(err)
return callback(err)
}

series([
(cb) => this._publishEntry(keys.ipnsKey, embedPublicKeyRecord || record, peerId, cb),
(cb) => this._publishEntry(keys.routingKey, embedPublicKeyRecord || record, peerId, cb),
// Publish the public key if a public key cannot be extracted from the ID
// We will be able to deprecate this part in the future, since the public keys will be only in the peerId
(cb) => embedPublicKeyRecord ? this._publishPublicKey(keys.pkKey, publicKey, peerId, cb) : cb()
(cb) => embedPublicKeyRecord ? this._publishPublicKey(keys.routingPubKey, publicKey, peerId, cb) : cb()
], (err) => {
if (err) {
log.error(err)
Expand Down Expand Up @@ -108,13 +108,13 @@ class IpnsPublisher {
return callback(err)
}

// TODO Routing - this should be replaced by a put to the DHT
this._repo.datastore.put(key, rec.serialize(), (err, res) => {
// Add record to routing (buffer key)
this._routing.put(key.toBuffer(), rec.serialize(), (err, res) => {
if (err) {
const errMsg = `ipns record for ${key.toString()} could not be stored in the routing`

log.error(errMsg)
return callback(errcode(new Error(errMsg), 'ERR_STORING_IN_DATASTORE'))
return callback(errcode(new Error(errMsg), 'ERR_PUTTING_TO_ROUTING'))
}

log(`ipns record for ${key.toString()} was stored in the routing`)
Expand Down Expand Up @@ -146,13 +146,13 @@ class IpnsPublisher {
return callback(err)
}

// TODO Routing - this should be replaced by a put to the DHT
this._repo.datastore.put(key, rec.serialize(), (err, res) => {
// Add public key to routing (buffer key)
this._routing.put(key.toBuffer(), rec.serialize(), (err, res) => {
if (err) {
const errMsg = `public key for ${key.toString()} could not be stored in the routing`

log.error(errMsg)
return callback(errcode(new Error(errMsg), 'ERR_STORING_IN_DATASTORE'))
return callback(errcode(new Error(errMsg), 'ERR_PUTTING_TO_ROUTING'))
}

log(`public key for ${key.toString()} was stored in the routing`)
Expand Down
18 changes: 10 additions & 8 deletions src/core/ipns/republisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ const defaultBroadcastInterval = 4 * hour
const defaultRecordLifetime = 24 * hour

class IpnsRepublisher {
constructor (publisher, ipfs) {
constructor (publisher, repo, peerInfo, keychain, options) {
this._publisher = publisher
this._ipfs = ipfs
this._repo = ipfs._repo
this._repo = repo
this._peerInfo = peerInfo
this._keychain = keychain
this._options = options
this._republishHandle = null
}

Expand Down Expand Up @@ -62,8 +64,8 @@ class IpnsRepublisher {
}
}

const { privKey } = this._ipfs._peerInfo.id
const { pass } = this._ipfs._options
const { privKey } = this._peerInfo.id
const { pass } = this._options

republishHandle.runPeriodically((done) => {
this._republishEntries(privKey, pass, () => done(defaultBroadcastInterval))
Expand Down Expand Up @@ -98,16 +100,16 @@ class IpnsRepublisher {
}

// keychain needs pass to get the cryptographic keys
if (this._ipfs._keychain && Boolean(pass)) {
this._ipfs._keychain.listKeys((err, list) => {
if (pass) {
this._keychain.listKeys((err, list) => {
if (err) {
log.error(err)
return
}

each(list, (key, cb) => {
waterfall([
(cb) => this._ipfs._keychain.exportKey(key.name, pass, cb),
(cb) => this._keychain.exportKey(key.name, pass, cb),
(pem, cb) => crypto.keys.import(pem, pass, cb)
], (err, privKey) => {
if (err) {
Expand Down
Loading

0 comments on commit a0642ed

Please sign in to comment.