-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: getPath with carScope #8
Changes from 4 commits
6235baf
b7898ee
3b75841
2efdcf9
59c666b
3acbe11
cdd530d
2769c69
e942e82
4aed254
26f019a
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 |
---|---|---|
|
@@ -66,14 +66,14 @@ export class Dagula { | |
} | ||
|
||
/** | ||
* @param {import('multiformats').CID|string} cid | ||
* @param {CID[]|CID|string} cid | ||
* @param {{ signal?: AbortSignal }} [options] | ||
*/ | ||
async * get (cid, options = {}) { | ||
cid = typeof cid === 'string' ? CID.parse(cid) : cid | ||
log('getting DAG %s', cid) | ||
let cids = [cid] | ||
while (true) { | ||
let cids = Array.isArray(cid) ? cid : [cid] | ||
while (cids.length > 0) { | ||
olizilla marked this conversation as resolved.
Show resolved
Hide resolved
|
||
log('fetching %d CIDs', cids.length) | ||
const fetchBlocks = transform(cids.length, async cid => { | ||
return this.getBlock(cid, { signal: options.signal }) | ||
|
@@ -98,6 +98,43 @@ export class Dagula { | |
} | ||
} | ||
|
||
/** | ||
* @param {string} cidPath | ||
* @param {object} [options] | ||
* @param {AbortSignal} [options.signal] | ||
* @param {'all'|'file'|'block'} [options.carScope] control how many layers of the dag are returned | ||
* 'all': return the entire dag starting at path. (default) | ||
* 'block': return the block identified by the path. | ||
* 'file': Mimic gateway semantics: Return All blocks for a multi-block file or just enough blocks to enumerate a dir/map but not the dir contents. | ||
* e.g. Where path points to a single block file, all three selectors would return the same thing. | ||
* e.g. where path points to a sharded hamt: 'file' returns the blocks of the hamt so the dir can be listed. 'block' returns the root block of the hamt. | ||
*/ | ||
async * getPath (cidPath, options = {}) { | ||
const carScope = options.carScope ?? 'all' | ||
/** @type {import('ipfs-unixfs-exporter').UnixFSEntry} */ | ||
let base | ||
for await (const item of this.walkUnixfsPath(cidPath, { signal: options.signal })) { | ||
base = item | ||
yield item | ||
} | ||
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. This should emit blocks not unixfs entries... where an entry is for a hamt we will only emit one thing, but we want to emit all the blocks that we traverse through the hamt. Also we don't want to emit a mix of unixfs entries and blocks. 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. Apologies I should have caught that in the review! |
||
if (carScope === 'all' || (carScope === 'file' && base.type !== 'directory')) { | ||
// fetch the entire dag rooted at the end of the provided path | ||
const links = base.node.Links?.map(l => l.Hash) || [] | ||
if (links.length) { | ||
yield * this.get(links, { signal: options.signal }) | ||
} | ||
} | ||
// non-files, like directories, and IPLD Maps only return blocks necessary for their enumeration | ||
if (carScope === 'file' && base.type === 'directory') { | ||
// the single block for the root has already been yielded. | ||
// For a hamt we must fetch all the blocks of the (current) hamt. | ||
if (base.unixfs.type === 'hamt-sharded-directory') { | ||
// TODO: how to determine the boundary of a hamt | ||
throw new Error('hamt-sharded-directory is unsupported') | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @param {import('multiformats').CID|string} cid | ||
* @param {{ signal?: AbortSignal }} [options] | ||
|
@@ -133,11 +170,11 @@ export class Dagula { | |
} | ||
|
||
/** | ||
* @param {string|import('multiformats').CID} path | ||
* @param {string} cidPath | ||
* @param {{ signal?: AbortSignal }} [options] | ||
*/ | ||
async * walkUnixfsPath (path, options = {}) { | ||
log('walking unixfs %s', path) | ||
async * walkUnixfsPath (cidPath, options = {}) { | ||
log('walking unixfs %s', cidPath) | ||
const blockstore = { | ||
/** | ||
* @param {CID} cid | ||
|
@@ -148,7 +185,10 @@ export class Dagula { | |
return block.bytes | ||
} | ||
} | ||
|
||
yield * walkPath(path, blockstore, { signal: options.signal }) | ||
for await (const entry of walkPath(cidPath, blockstore, { signal: options.signal })) { | ||
/** @type {Uint8Array} */ | ||
const bytes = entry.node.Links ? dagPb.encode(entry.node) : entry.node | ||
yield { ...entry, bytes } | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,8 +49,7 @@ | |
"blockstore-core": "^1.0.5", | ||
"ipfs-unixfs": "^11.0.0", | ||
"miniswap": "^2.0.0", | ||
"standard": "^17.0.0", | ||
"uint8arrays": "^3.0.0" | ||
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. turns out the swiss-army-knife has |
||
"standard": "^17.0.0" | ||
}, | ||
"types": "./index.d.ts", | ||
"repository": { | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { createLibp2p } from 'libp2p' | ||
import { webSockets } from '@libp2p/websockets' | ||
import { noise } from '@chainsafe/libp2p-noise' | ||
import { mplex } from '@libp2p/mplex' | ||
import { MemoryBlockstore } from 'blockstore-core/memory' | ||
import { Miniswap, BITSWAP_PROTOCOL } from 'miniswap' | ||
|
||
/** | ||
* @param {import('..').Block[]} | ||
*/ | ||
export async function startBitswapPeer (blocks = []) { | ||
const libp2p = await createLibp2p({ | ||
addresses: { listen: ['/ip4/127.0.0.1/tcp/0/ws'] }, | ||
transports: [webSockets()], | ||
streamMuxers: [mplex()], | ||
connectionEncryption: [noise()] | ||
}) | ||
|
||
const bs = new MemoryBlockstore() | ||
for (const { cid, bytes } of blocks) { | ||
bs.put(cid, bytes) | ||
} | ||
|
||
const miniswap = new Miniswap(bs) | ||
libp2p.handle(BITSWAP_PROTOCOL, miniswap.handler) | ||
|
||
await libp2p.start() | ||
|
||
return { | ||
libp2p, | ||
bs | ||
} | ||
} |
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.
Is
UnixFSEntry
not already aBlock
?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.
No, it lacks the all important
bytes