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

Commit aaf2d3b

Browse files
committed
feat: implement ipfs refs
1 parent 20beea2 commit aaf2d3b

File tree

14 files changed

+449
-6
lines changed

14 files changed

+449
-6
lines changed

src/cli/commands/refs.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
'use strict'
2+
3+
const { print } = require('../utils')
4+
5+
// Default formats
6+
const Format = {
7+
default: '<dst>',
8+
edges: '<src> -> <dst>'
9+
}
10+
11+
module.exports = {
12+
command: 'refs <key>',
13+
14+
describe: 'List links (references) from an object',
15+
16+
builder: {
17+
r: {
18+
alias: 'recursive',
19+
desc: 'Recursively list links of child nodes.',
20+
type: 'boolean',
21+
default: false
22+
},
23+
format: {
24+
desc: 'Output edges with given format. Available tokens: <src> <dst> <linkname>.',
25+
type: 'string',
26+
default: Format.default
27+
},
28+
e: {
29+
alias: 'edges',
30+
desc: 'Output edge format: `<from> -> <to>`',
31+
type: 'boolean',
32+
default: false
33+
},
34+
u: {
35+
alias: 'unique',
36+
desc: 'Omit duplicate refs from output.',
37+
type: 'boolean',
38+
default: false
39+
},
40+
'max-depth': {
41+
desc: 'Only for recursive refs, limits fetch and listing to the given depth.',
42+
type: 'number'
43+
}
44+
},
45+
46+
handler ({ getIpfs, key, recursive, format, e, u, resolve, maxDepth }) {
47+
resolve((async () => {
48+
if (format !== Format.default && e) {
49+
throw new Error('Cannot set edges to true and also specify format')
50+
}
51+
52+
if (maxDepth === 0) {
53+
return
54+
}
55+
56+
const ipfs = await getIpfs()
57+
let links = await ipfs.refs(key, { recursive, maxDepth })
58+
if (!links.length) {
59+
return
60+
}
61+
62+
const linkDAG = getLinkDAG(links)
63+
format = e ? Format.edges : format || Format.default
64+
printLinks(linkDAG, links[0], format, u && new Set())
65+
})())
66+
}
67+
}
68+
69+
// Get links as a DAG Object
70+
// { <linkName1>: [link2, link3, link4], <linkName2>: [...] }
71+
function getLinkDAG (links) {
72+
const linkNames = {}
73+
for (const link of links) {
74+
linkNames[link.name] = link
75+
}
76+
77+
const linkDAG = {}
78+
for (const link of links) {
79+
const parentName = link.path.substring(0, link.path.lastIndexOf('/'))
80+
linkDAG[parentName] = linkDAG[parentName] || []
81+
linkDAG[parentName].push(link)
82+
}
83+
return linkDAG
84+
}
85+
86+
// Print children of a link
87+
function printLinks (linkDAG, link, format, uniques) {
88+
const children = linkDAG[link.path] || []
89+
for (const child of children) {
90+
if (!uniques || !uniques.has(child.hash)) {
91+
uniques && uniques.add(child.hash)
92+
printLink(link, child, format)
93+
printLinks(linkDAG, child, format, uniques)
94+
}
95+
}
96+
}
97+
98+
// Print formatted link
99+
function printLink (src, dst, format) {
100+
let out = format.replace(/<src>/g, src.hash)
101+
out = out.replace(/<dst>/g, dst.hash)
102+
out = out.replace(/<linkname>/g, dst.name)
103+
print(out)
104+
}

src/core/components/files-regular/index.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,7 @@ module.exports = self => ({
1515
getReadableStream: require('./get-readable-stream')(self),
1616
ls: require('./ls')(self),
1717
lsPullStream: require('./ls-pull-stream')(self),
18-
lsReadableStream: require('./ls-readable-stream')(self)
18+
lsReadableStream: require('./ls-readable-stream')(self),
19+
refs: require('./refs')(self),
20+
refsPullStream: require('./refs-pull-stream')(self)
1921
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict'
2+
3+
const exporter = require('ipfs-unixfs-exporter')
4+
const pull = require('pull-stream')
5+
const { normalizePath } = require('./utils')
6+
7+
module.exports = function (self) {
8+
return function (ipfsPath, options = {}) {
9+
const path = normalizePath(ipfsPath)
10+
const pathComponents = path.split('/')
11+
12+
// eg QmHash/linkName => 2
13+
const pathDepth = pathComponents.length
14+
15+
// The exporter returns a depth for each node, eg:
16+
// Qmhash.../linkName/linkName/linkName/block
17+
// 0 1 2 3 4
18+
if (options.maxDepth === undefined) {
19+
options.maxDepth = options.recursive ? global.Infinity : pathDepth
20+
} else {
21+
options.maxDepth = options.maxDepth + pathDepth - 1
22+
}
23+
24+
if (options.preload !== false) {
25+
self._preload(pathComponents[0])
26+
}
27+
28+
return pull(
29+
exporter(ipfsPath, self._ipld, options),
30+
pull.map(node => {
31+
node.hash = node.cid.toString()
32+
delete node.cid
33+
delete node.content
34+
return node
35+
})
36+
)
37+
}
38+
}
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict'
2+
3+
const promisify = require('promisify-es6')
4+
const pull = require('pull-stream')
5+
6+
module.exports = function (self) {
7+
return promisify((ipfsPath, options, callback) => {
8+
if (typeof options === 'function') {
9+
callback = options
10+
options = {}
11+
}
12+
13+
options = options || {}
14+
15+
pull(
16+
self.refsPullStream(ipfsPath, options),
17+
pull.collect((err, values) => {
18+
if (err) {
19+
return callback(err)
20+
}
21+
callback(null, values)
22+
})
23+
)
24+
})
25+
}

0 commit comments

Comments
 (0)