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

Commit

Permalink
fix: make recursive true defaults, tests and more
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomrdias committed May 16, 2019
1 parent d04e5c5 commit ef824d3
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 366 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"aegir": "^18.1.0",
"base64url": "^3.0.1",
"chai": "^4.2.0",
"clear-module": "^3.2.0",
"delay": "^4.1.0",
"detect-node": "^2.0.4",
"dir-compare": "^1.4.0",
Expand Down Expand Up @@ -105,6 +106,7 @@
"get-folder-size": "^2.0.0",
"glob": "^7.1.3",
"hapi-pino": "^5.4.1",
"hashlru": "^2.3.0",
"human-to-milliseconds": "^1.0.0",
"interface-datastore": "~0.6.0",
"ipfs-bitswap": "~0.23.0",
Expand Down Expand Up @@ -175,7 +177,6 @@
"pull-stream": "^3.6.9",
"pull-stream-to-stream": "^1.3.4",
"readable-stream": "^3.1.1",
"receptacle": "^1.3.2",
"stream-to-pull-stream": "^1.7.3",
"superstruct": "~0.6.0",
"tar-stream": "^2.0.0",
Expand Down
22 changes: 10 additions & 12 deletions src/cli/commands/name/publish.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const print = require('../../utils').print
const { print } = require('../../utils')

module.exports = {
command: 'publish <ipfsPath>',
Expand All @@ -11,36 +11,34 @@ module.exports = {
resolve: {
alias: 'r',
describe: 'Resolve given path before publishing. Default: true.',
default: true
default: true,
type: 'boolean'
},
lifetime: {
alias: 't',
describe: 'Time duration that the record will be valid for. Default: 24h.',
default: '24h'
default: '24h',
type: 'string'
},
key: {
alias: 'k',
describe: 'Name of the key to be used or a valid PeerID, as listed by "ipfs key list -l". Default: self.',
default: 'self'
default: 'self',
type: 'string'
},
ttl: {
describe: 'Time duration this record should be cached for (caution: experimental).',
default: ''
default: '',
type: 'string'
}
},

handler (argv) {
argv.resolve((async () => {
// yargs-promise adds resolve/reject properties to argv
// resolve should use the alias as resolve will always be overwritten to a function
let resolve = true

if (argv.r === false || argv.r === 'false') {
resolve = false
}

const opts = {
resolve,
resolve: argv.r,
lifetime: argv.lifetime,
key: argv.key,
ttl: argv.ttl
Expand Down
2 changes: 1 addition & 1 deletion src/cli/commands/name/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ module.exports = {
type: 'boolean',
alias: 'r',
describe: 'Resolve until the result is not an IPNS name. Default: false.',
default: false
default: true
}
},

Expand Down
2 changes: 1 addition & 1 deletion src/core/components/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ module.exports = function name (self) {

options = mergeOptions({
nocache: false,
recursive: false
recursive: true
}, options)

const offline = self._options.offline
Expand Down
21 changes: 14 additions & 7 deletions src/core/ipns/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const { createFromPrivKey } = require('peer-id')
const series = require('async/series')
const Receptacle = require('receptacle')

const errcode = require('err-code')
const debug = require('debug')
Expand All @@ -13,20 +12,28 @@ const IpnsPublisher = require('./publisher')
const IpnsRepublisher = require('./republisher')
const IpnsResolver = require('./resolver')
const path = require('./path')

const { normalizePath } = require('../utils')
const TLRU = require('../../utils/tlru')
const defaultRecordTtl = 60 * 1000

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

// Publish
publish (privKey, value, lifetime, callback) {
publish (privKey, value, lifetime = IpnsPublisher.defaultRecordLifetime, callback) {
try {
value = normalizePath(value)
} catch (err) {
log.error(err)
return callback(err)
}

series([
(cb) => createFromPrivKey(privKey.bytes, cb),
(cb) => this.publisher.publishWithEOL(privKey, value, lifetime, cb)
Expand All @@ -38,12 +45,12 @@ class IPNS {

log(`IPNS value ${value} was published correctly`)

// Add to cache
// // Add to cache
const id = results[0].toB58String()
const ttEol = parseFloat(lifetime)
const ttl = (ttEol < defaultRecordTtl) ? ttEol : defaultRecordTtl

this.cache.set(id, value, { ttl: ttl })
this.cache.set(id, value, ttl)

log(`IPNS value ${value} was cached correctly`)

Expand Down Expand Up @@ -96,7 +103,7 @@ class IPNS {
// Initialize keyspace
// sets the ipns record for the given key to point to an empty directory
initializeKeyspace (privKey, value, callback) {
this.publisher.publish(privKey, value, callback)
this.publish(privKey, value, IpnsPublisher.defaultRecordLifetime, callback)
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/core/ipns/publisher.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ log.error = debug('ipfs:ipns:publisher:error')

const ipns = require('ipns')

const defaultRecordTtl = 60 * 60 * 1000
const defaultRecordLifetime = 60 * 60 * 1000

// IpnsPublisher is capable of publishing and resolving names to the IPFS routing system.
class IpnsPublisher {
Expand Down Expand Up @@ -46,7 +46,7 @@ class IpnsPublisher {

// Accepts a keypair, as well as a value (ipfsPath), and publishes it out to the routing system
publish (privKey, value, callback) {
this.publishWithEOL(privKey, value, defaultRecordTtl, callback)
this.publishWithEOL(privKey, value, defaultRecordLifetime, callback)
}

_putRecordToRouting (record, peerId, callback) {
Expand Down Expand Up @@ -269,4 +269,5 @@ class IpnsPublisher {
}
}

IpnsPublisher.defaultRecordLifetime = defaultRecordLifetime
exports = module.exports = IpnsPublisher
2 changes: 1 addition & 1 deletion src/http/api/resources/name.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ exports.resolve = {
query: Joi.object().keys({
arg: Joi.string(),
nocache: Joi.boolean().default(false),
recursive: Joi.boolean().default(false)
recursive: Joi.boolean().default(true)
}).unknown()
},
async handler (request, h) {
Expand Down
83 changes: 83 additions & 0 deletions src/utils/tlru.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
'use strict'
const hashlru = require('hashlru')

/**
* Time Aware Least Recent Used Cache
* @see https://arxiv.org/pdf/1801.00390
* @todo move this to ipfs-utils or it's own package
*
* @class TLRU
*/
class TLRU {
/**
* Creates an instance of TLRU.
*
* @param {number} maxSize
* @memberof TLRU
*/
constructor (maxSize) {
this.lru = hashlru(maxSize)
}

/**
* Get the value from the a key
*
* @param {string} key
* @returns {any}
* @memberof TLRU
*/
get (key) {
const value = this.lru.get(key)
if (value) {
if ((value.expire) && (value.expire < Date.now())) {
this.lru.remove(key)
return undefined
}
}
return value.value
}

/**
* Set a key value pair
*
* @param {string} key
* @param {any} value
* @param {number} ttl - in miliseconds
* @memberof TLRU
*/
set (key, value, ttl) {
this.lru.set(key, { value, expire: Date.now() + ttl })
}

/**
* Find if the cache has the key
*
* @param {string} key
* @returns {boolean}
* @memberof TLRU
*/
has (key) {
return this.lru.has(key)
}

/**
* Remove key
*
* @param {string} key
* @memberof TLRU
*/
remove (key) {
this.lru.remove(key)
}

/**
* Clears the cache
*
* @memberof TLRU
*/
clear () {
this.lru.clear()
}
}

module.exports = TLRU
50 changes: 0 additions & 50 deletions test/cli/name-pubsub.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@ const ipfsExec = require('../utils/ipfs-exec')
const DaemonFactory = require('ipfsd-ctl')
const df = DaemonFactory.create({ type: 'js' })

const checkAll = (bits) => string => bits.every(bit => string.includes(bit))
const emptyDirCid = 'QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn'

const spawnDaemon = (callback) => {
df.spawn({
exec: `./src/cli/bin.js`,
Expand Down Expand Up @@ -165,53 +162,6 @@ describe('name-pubsub', () => {
})
})
})

describe('pubsub records', () => {
let cidAdded

before(function (done) {
this.timeout(50 * 1000)
ipfsA('add src/init-files/init-docs/readme')
.then((out) => {
cidAdded = out.split(' ')[1]
done()
})
})

it('should publish the received record to the subscriber', function () {
this.timeout(80 * 1000)

return ipfsB(`name resolve ${nodeBId.id}`)
.then((res) => {
expect(res).to.exist()
expect(res).to.satisfy(checkAll([emptyDirCid])) // Empty dir received (subscribed)

return ipfsA(`name resolve ${nodeBId.id}`)
})
.catch((err) => {
expect(err).to.exist() // Not available (subscribed now)

return ipfsB(`name publish ${cidAdded}`)
})
.then((res) => {
// published to IpfsB and published through pubsub to ipfsa
expect(res).to.exist()
expect(res).to.satisfy(checkAll([cidAdded, nodeBId.id]))

return ipfsB(`name resolve ${nodeBId.id}`)
})
.then((res) => {
expect(res).to.exist()
expect(res).to.satisfy(checkAll([cidAdded]))

return ipfsA(`name resolve ${nodeBId.id}`)
})
.then((res) => {
expect(res).to.exist()
expect(res).to.satisfy(checkAll([cidAdded])) // value propagated to node B
})
})
})
})

describe('disabled', () => {
Expand Down
Loading

0 comments on commit ef824d3

Please sign in to comment.