-
Notifications
You must be signed in to change notification settings - Fork 4
/
example-dag-generate.js
136 lines (115 loc) Β· 4.67 KB
/
example-dag-generate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// `npm install` to set up
//
// run with `node example-dag-generate.js` to generate an `example.car` that contains a graph(ish)
//
// run with `node example-dag-generate.js inspect` to see what `example.car` contains
//
const fs = require('fs')
const CarDatastore = require('datastore-car')
const Block = require('@ipld/block')
const CID = require('cids')
// main entry point
if (process.argv[2] === 'inspect') {
// ran with `node example-dag-generate.js inspect`
inspect().catch((err) => {
console.error(err)
process.exit(1)
})
} else {
// ran with `node example-dag-generate.js`
run().catch((err) => {
console.error(err)
process.exit(1)
})
}
// make an arbitrary graph with some weird links
async function run () {
const blocks = []
// a link to some data _elsewhere_
const externalLink = new CID('QmV88khHDJEXi7wo6o972MZWY661R9PhrZW6dvpFP6jnMn')
// two leaf nodes with raw bytes, no links
const leafRaw1 = Block.encoder(Buffer.from('π² leaf node of raw bytes π΄'), 'raw')
blocks.push(leafRaw1)
const leafRaw2 = Block.encoder(Buffer.from('π²π²π²π²π²π²π²π²π²π²π²π²π²π΄π΄π΄π΄π΄π΄π΄π΄π΄'), 'raw')
blocks.push(leafRaw2)
// a parent that bundles the two leafs into an array inside a map encoded in dag-cbor
const parent = Block.encoder({
name: 'parent of some weird children',
children: [await leafRaw1.cid(), await leafRaw2.cid()],
favouriteChild: await leafRaw2.cid()
}, 'dag-cbor')
blocks.push(parent)
// a list containing links to the 3 local blocks above, encoded in dag-json
const lister = Block.encoder([await parent.cid(), await leafRaw1.cid(), await leafRaw2.cid()], 'dag-json')
blocks.push(lister)
// a list containing 2 maps which conntain links to the two previous blocks, plus an additional bare CID
// to something external
const grandparent = Block.encoder([
{ name: 'parent', link: await parent.cid() },
{ name: 'lister', link: await lister.cid() },
externalLink
], 'dag-cbor')
blocks.push(grandparent)
// a dangling node that points to one of the leaf nodes using a map
const evergreenPointer = Block.encoder({
data: await leafRaw2.cid(),
startByte: 0,
endByte: 52
}, 'dag-cbor')
blocks.push(evergreenPointer)
// a second dangling node that points to one of the leaf nodes using a map
const palmsPointer = Block.encoder({
data: await leafRaw2.cid(),
startByte: 52,
endByte: 88
}, 'dag-cbor')
blocks.push(palmsPointer)
// write with the `grandparent` as the root of the graph, but push all blocks we
// created, this leaves the last two blocks as _not_ part of the graph that starts
// with the `grandparent` root. We could include them in the roots array if we
// wanted to be pedantic: `[await grandparent.cid(), await evergreenPointer.cid(), await palmsPointer.cid()]`
await write(blocks, [await grandparent.cid()])
}
// write the blocks to a CAR file
async function write (blocks, roots) {
const outStream = fs.createWriteStream('example.car')
const writeDs = await CarDatastore.writeStream(outStream)
await writeDs.setRoots(roots)
for (const block of blocks) {
await writeDs.put(await block.cid(), await block.encode())
}
await writeDs.close()
}
// ignore this, it's just a way of making JSON print CIDs nicely for human consumption
function jsonCIDReplacer (key, value) {
if (typeof value === 'object' &&
typeof value.codec === 'string' &&
typeof value.version === 'number' &&
Buffer.isBuffer(value.hash)) {
return `CID<${new CID(value.version, value.codec, value.hash).toString()}>`
}
return value
}
// inspect a CAR file, printing out its roots and its decoded block contents
async function inspect () {
const inStream = fs.createReadStream('example.car')
const readDs = await CarDatastore.readStreaming(inStream)
console.log('Roots:', (await readDs.getRoots()).map((cid) => cid.toString()))
let i = 1
for await (const { key, value } of readDs.query()) {
// `key` is a string form of a CID, to make it compatible with the Datastore interface
// `value` is the bytes of the block
// so we can reconstitute a `Block` from the two
const cid = new CID(key)
const block = Block.create(value, cid)
console.log(`Block #${i++}: (${block.codec}) ${cid.toString()}`)
if (block.codec === 'raw') {
// we happen to know our raw blocks are UTF8 so this is fine, otherwise `toString('hex')` would be a good idea
console.log(block.decode().toString())
} else {
// `block.decode()` gives us the object form of the block, so JSON stringify it so we can see it
console.log(`${JSON.stringify(block.decode(), jsonCIDReplacer, 2)}`)
}
console.log()
}
}