-
Notifications
You must be signed in to change notification settings - Fork 37
Awesome IPLD endeavour #60
Changes from all commits
edee5fa
90ff073
436f44c
00d5d46
0818945
91ecfa4
a186055
b7c2887
39db563
05d4e74
733876b
1bc5a87
4aa591c
cd6e9b1
7978fd6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,168 @@ | ||
'use strict' | ||
|
||
exports.IPLDService = require('./ipld-service') | ||
exports.resolve = require('./resolve') | ||
const Block = require('ipfs-block') | ||
const pull = require('pull-stream') | ||
const CID = require('cids') | ||
const until = require('async/until') | ||
const IPFSRepo = require('ipfs-repo') | ||
const MemoryStore = require('../node_modules/interface-pull-blob-store/lib/reference.js') | ||
const BlockService = require('ipfs-block-service') | ||
|
||
const dagPB = require('ipld-dag-pb') | ||
const dagCBOR = require('ipld-dag-cbor') | ||
|
||
class IPLDResolver { | ||
constructor (blockService) { | ||
// nicola will love this! | ||
if (!blockService) { | ||
const repo = new IPFSRepo('in-memory', { stores: MemoryStore }) | ||
blockService = new BlockService(repo) | ||
} | ||
|
||
this.bs = blockService | ||
this.resolvers = {} | ||
|
||
this.support = {} | ||
|
||
// Adds support for an IPLD format | ||
this.support.add = (multicodec, resolver, util) => { | ||
if (this.resolvers[multicodec]) { | ||
throw new Error(multicodec + 'already supported') | ||
} | ||
|
||
this.resolvers[multicodec] = { | ||
resolver: resolver, | ||
util: util | ||
} | ||
} | ||
|
||
this.support.rm = (multicodec) => { | ||
if (this.resolvers[multicodec]) { | ||
delete this.resolvers[multicodec] | ||
} | ||
} | ||
|
||
// Support by default dag-pb and dag-cbor | ||
this.support.add(dagPB.resolver.multicodec, dagPB.resolver, dagPB.util) | ||
this.support.add(dagCBOR.resolver.multicodec, dagCBOR.resolver, dagCBOR.util) | ||
} | ||
|
||
resolve (cid, path, callback) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why are There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nicola note that CID is a instance of class CID that has several utility methods https://github.com/ipfs/js-cid/tree/feat/complete What you are proposing is to use cids always as strings, which would assume that we have to be constantly parsing and mounting them again to get their props. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see, perfect then. There must be up in the levels of abstraction a sort of resolver that takes a path and resolve that (by using this, I guess) |
||
if (path === '/') { | ||
return this.get(cid, callback) | ||
} | ||
|
||
let value | ||
|
||
until( | ||
() => { | ||
if (!path || path === '' || path === '/') { | ||
return true | ||
} else { | ||
// continue traversing | ||
if (value) { | ||
cid = new CID(value['/']) | ||
} | ||
return false | ||
} | ||
}, | ||
(cb) => { | ||
// get block | ||
// use local resolver | ||
// update path value | ||
this.bs.get(cid, (err, block) => { | ||
if (err) { | ||
return cb(err) | ||
} | ||
const r = this.resolvers[cid.codec] | ||
r.resolver.resolve(block, path, (err, result) => { | ||
if (err) { | ||
return cb(err) | ||
} | ||
value = result.value | ||
path = result.remainderPath | ||
cb() | ||
}) | ||
}) | ||
}, | ||
(err, results) => { | ||
if (err) { | ||
return callback(err) | ||
} | ||
return callback(null, value) | ||
} | ||
) | ||
} | ||
|
||
// Node operations (get and retrieve nodes, not values) | ||
|
||
put (nodeAndCID, callback) { | ||
callback = callback || noop | ||
pull( | ||
pull.values([nodeAndCID]), | ||
this.putStream(callback) | ||
) | ||
} | ||
|
||
putStream (callback) { | ||
callback = callback || noop | ||
|
||
return pull( | ||
pull.asyncMap((nodeAndCID, cb) => { | ||
const cid = nodeAndCID.cid | ||
const r = this.resolvers[cid.codec] | ||
|
||
r.util.serialize(nodeAndCID.node, (err, serialized) => { | ||
if (err) { | ||
return cb(err) | ||
} | ||
cb(null, { | ||
block: new Block(serialized), | ||
cid: cid | ||
}) | ||
}) | ||
}), | ||
this.bs.putStream(), | ||
pull.onEnd(callback) | ||
) | ||
} | ||
|
||
get (cid, callback) { | ||
pull( | ||
this.getStream(cid), | ||
pull.collect((err, res) => { | ||
if (err) { | ||
return callback(err) | ||
} | ||
callback(null, res[0]) | ||
}) | ||
) | ||
} | ||
|
||
getStream (cid) { | ||
return pull( | ||
this.bs.getStream(cid), | ||
pull.asyncMap((block, cb) => { | ||
const r = this.resolvers[cid.codec] | ||
if (r) { | ||
r.util.deserialize(block.data, (err, deserialized) => { | ||
if (err) { | ||
return cb(err) | ||
} | ||
cb(null, deserialized) | ||
}) | ||
} else { // multicodec unknown, send back raw data | ||
cb(null, block.data) | ||
} | ||
}) | ||
) | ||
} | ||
|
||
remove (cids, callback) { | ||
this.bs.delete(cids, callback) | ||
} | ||
} | ||
|
||
function noop () {} | ||
|
||
module.exports = IPLDResolver |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can do
require('interface-pull-blob-store/lib/reference.js')
instead, no need for the full pathThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right! (I do remember fighting with this one and this was how I got it to reference to the right one, not sure what was the error without node_modules though).
Could you also check ipfs-inactive/interface-pull-blob-store#6, this way we don't even have to point to a path inside.