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

Commit

Permalink
feat: implement ipfs refs
Browse files Browse the repository at this point in the history
  • Loading branch information
dirkmc committed Apr 22, 2019
1 parent 20beea2 commit aaf2d3b
Show file tree
Hide file tree
Showing 14 changed files with 449 additions and 6 deletions.
104 changes: 104 additions & 0 deletions src/cli/commands/refs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict'

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

// Default formats
const Format = {
default: '<dst>',
edges: '<src> -> <dst>'
}

module.exports = {
command: 'refs <key>',

describe: 'List links (references) from an object',

builder: {
r: {
alias: 'recursive',
desc: 'Recursively list links of child nodes.',
type: 'boolean',
default: false
},
format: {
desc: 'Output edges with given format. Available tokens: <src> <dst> <linkname>.',
type: 'string',
default: Format.default
},
e: {
alias: 'edges',
desc: 'Output edge format: `<from> -> <to>`',
type: 'boolean',
default: false
},
u: {
alias: 'unique',
desc: 'Omit duplicate refs from output.',
type: 'boolean',
default: false
},
'max-depth': {
desc: 'Only for recursive refs, limits fetch and listing to the given depth.',
type: 'number'
}
},

handler ({ getIpfs, key, recursive, format, e, u, resolve, maxDepth }) {
resolve((async () => {
if (format !== Format.default && e) {
throw new Error('Cannot set edges to true and also specify format')
}

if (maxDepth === 0) {
return
}

const ipfs = await getIpfs()
let links = await ipfs.refs(key, { recursive, maxDepth })
if (!links.length) {
return
}

const linkDAG = getLinkDAG(links)
format = e ? Format.edges : format || Format.default
printLinks(linkDAG, links[0], format, u && new Set())
})())
}
}

// Get links as a DAG Object
// { <linkName1>: [link2, link3, link4], <linkName2>: [...] }
function getLinkDAG (links) {
const linkNames = {}
for (const link of links) {
linkNames[link.name] = link
}

const linkDAG = {}
for (const link of links) {
const parentName = link.path.substring(0, link.path.lastIndexOf('/'))
linkDAG[parentName] = linkDAG[parentName] || []
linkDAG[parentName].push(link)
}
return linkDAG
}

// Print children of a link
function printLinks (linkDAG, link, format, uniques) {
const children = linkDAG[link.path] || []
for (const child of children) {
if (!uniques || !uniques.has(child.hash)) {
uniques && uniques.add(child.hash)
printLink(link, child, format)
printLinks(linkDAG, child, format, uniques)
}
}
}

// Print formatted link
function printLink (src, dst, format) {
let out = format.replace(/<src>/g, src.hash)
out = out.replace(/<dst>/g, dst.hash)
out = out.replace(/<linkname>/g, dst.name)
print(out)
}
4 changes: 3 additions & 1 deletion src/core/components/files-regular/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ module.exports = self => ({
getReadableStream: require('./get-readable-stream')(self),
ls: require('./ls')(self),
lsPullStream: require('./ls-pull-stream')(self),
lsReadableStream: require('./ls-readable-stream')(self)
lsReadableStream: require('./ls-readable-stream')(self),
refs: require('./refs')(self),
refsPullStream: require('./refs-pull-stream')(self)
})
38 changes: 38 additions & 0 deletions src/core/components/files-regular/refs-pull-stream.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict'

const exporter = require('ipfs-unixfs-exporter')
const pull = require('pull-stream')
const { normalizePath } = require('./utils')

module.exports = function (self) {
return function (ipfsPath, options = {}) {
const path = normalizePath(ipfsPath)
const pathComponents = path.split('/')

// eg QmHash/linkName => 2
const pathDepth = pathComponents.length

// The exporter returns a depth for each node, eg:
// Qmhash.../linkName/linkName/linkName/block
// 0 1 2 3 4
if (options.maxDepth === undefined) {
options.maxDepth = options.recursive ? global.Infinity : pathDepth
} else {
options.maxDepth = options.maxDepth + pathDepth - 1
}

if (options.preload !== false) {
self._preload(pathComponents[0])
}

return pull(
exporter(ipfsPath, self._ipld, options),
pull.map(node => {
node.hash = node.cid.toString()
delete node.cid
delete node.content
return node
})
)
}
}
25 changes: 25 additions & 0 deletions src/core/components/files-regular/refs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

const promisify = require('promisify-es6')
const pull = require('pull-stream')

module.exports = function (self) {
return promisify((ipfsPath, options, callback) => {
if (typeof options === 'function') {
callback = options
options = {}
}

options = options || {}

pull(
self.refsPullStream(ipfsPath, options),
pull.collect((err, values) => {
if (err) {
return callback(err)
}
callback(null, values)
})
)
})
}
Loading

0 comments on commit aaf2d3b

Please sign in to comment.