This repository has been archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: return promise from dag resolve (#3152)
Makes `ipfs.dag.resolve` behave the same when calling into core and over the http api. Adds documentation and interface tests for `ipfs.dag.resolve`. Supersedes #3131 Fixes #2962 BREAKING CHANGES: - `ipfs.dag.resolve` returns `Promise<{ cid, remainderPath }` instead of `AsyncIterator<{ value, remainderPath }>` - Previously the core api returned an async iterator and the http client returned a simple promise Co-authored-by: Tarun Batra <[email protected]>
- Loading branch information
1 parent
585a142
commit f20cdf1
Showing
11 changed files
with
269 additions
and
184 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* eslint-env mocha */ | ||
'use strict' | ||
|
||
const { Buffer } = require('buffer') | ||
const dagPB = require('ipld-dag-pb') | ||
const DAGNode = dagPB.DAGNode | ||
const { getDescribe, getIt, expect } = require('../utils/mocha') | ||
const testTimeout = require('../utils/test-timeout') | ||
|
||
/** @typedef { import("ipfsd-ctl/src/factory") } Factory */ | ||
/** | ||
* @param {Factory} common | ||
* @param {Object} options | ||
*/ | ||
module.exports = (common, options) => { | ||
const describe = getDescribe(options) | ||
const it = getIt(options) | ||
|
||
describe('.dag.resolve', () => { | ||
let ipfs | ||
before(async () => { ipfs = (await common.spawn()).api }) | ||
|
||
after(() => common.clean()) | ||
|
||
it('should respect timeout option when resolving a path within a DAG node', async () => { | ||
const cid = await ipfs.dag.put({}, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
return testTimeout(() => ipfs.dag.resolve(cid, { | ||
timeout: 1 | ||
})) | ||
}) | ||
|
||
it('should resolve a path inside a cbor node', async () => { | ||
const obj = { | ||
a: 1, | ||
b: [1, 2, 3], | ||
c: { | ||
ca: [5, 6, 7], | ||
cb: 'foo' | ||
} | ||
} | ||
|
||
const cid = await ipfs.dag.put(obj, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(`${cid}/c/cb`) | ||
expect(result).to.have.deep.property('cid', cid) | ||
expect(result).to.have.property('remainderPath', 'c/cb') | ||
}) | ||
|
||
it('should resolve a path inside a cbor node by CID', async () => { | ||
const obj = { | ||
a: 1, | ||
b: [1, 2, 3], | ||
c: { | ||
ca: [5, 6, 7], | ||
cb: 'foo' | ||
} | ||
} | ||
|
||
const cid = await ipfs.dag.put(obj, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(cid, { path: '/c/cb' }) | ||
expect(result).to.have.deep.property('cid', cid) | ||
expect(result).to.have.property('remainderPath', 'c/cb') | ||
}) | ||
|
||
it('should resolve a multi-node path inside a cbor node', async () => { | ||
const obj0 = { | ||
ca: [5, 6, 7], | ||
cb: 'foo' | ||
} | ||
const cid0 = await ipfs.dag.put(obj0, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const obj1 = { | ||
a: 1, | ||
b: [1, 2, 3], | ||
c: cid0 | ||
} | ||
|
||
const cid1 = await ipfs.dag.put(obj1, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(`/ipfs/${cid1}/c/cb`) | ||
expect(result).to.have.deep.property('cid', cid0) | ||
expect(result).to.have.property('remainderPath', 'cb') | ||
}) | ||
|
||
it('should resolve a multi-node path inside a cbor node by CID', async () => { | ||
const obj0 = { | ||
ca: [5, 6, 7], | ||
cb: 'foo' | ||
} | ||
const cid0 = await ipfs.dag.put(obj0, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const obj1 = { | ||
a: 1, | ||
b: [1, 2, 3], | ||
c: cid0 | ||
} | ||
|
||
const cid1 = await ipfs.dag.put(obj1, { format: 'dag-cbor', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(cid1, { path: '/c/cb' }) | ||
expect(result).to.have.deep.property('cid', cid0) | ||
expect(result).to.have.property('remainderPath', 'cb') | ||
}) | ||
|
||
it('should resolve a raw node', async () => { | ||
const node = Buffer.from(['hello world']) | ||
const cid = await ipfs.dag.put(node, { format: 'raw', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(cid, { path: '/' }) | ||
expect(result).to.have.deep.property('cid', cid) | ||
expect(result).to.have.property('remainderPath', '') | ||
}) | ||
|
||
it('should resolve a path inside a dag-pb node linked to from another dag-pb node', async () => { | ||
const someData = Buffer.from('some other data') | ||
const childNode = new DAGNode(someData) | ||
const childCid = await ipfs.dag.put(childNode, { format: 'dag-pb', hashAlg: 'sha2-256' }) | ||
|
||
const linkToChildNode = await childNode.toDAGLink({ name: 'foo', cidVersion: 0 }) | ||
const parentNode = new DAGNode(Buffer.from('derp'), [linkToChildNode]) | ||
const parentCid = await ipfs.dag.put(parentNode, { format: 'dag-pb', hashAlg: 'sha2-256' }) | ||
|
||
const result = await ipfs.dag.resolve(parentCid, { path: '/foo' }) | ||
expect(result).to.have.deep.property('cid', childCid) | ||
expect(result).to.have.property('remainderPath', '') | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,56 @@ | ||
'use strict' | ||
|
||
const CID = require('cids') | ||
const { withTimeoutOption } = require('../../utils') | ||
const toCidAndPath = require('ipfs-core-utils/src/to-cid-and-path') | ||
|
||
module.exports = ({ ipld, preload }) => { | ||
return withTimeoutOption(async function * resolve (ipfsPath, options) { // eslint-disable-line require-await | ||
return withTimeoutOption(async function resolve (ipfsPath, options = {}) { | ||
const { | ||
cid, | ||
path | ||
} = toCidAndPath(ipfsPath) | ||
|
||
if (options.preload !== false) { | ||
preload(cid) | ||
} | ||
|
||
if (path) { | ||
options.path = path | ||
} | ||
|
||
if (options.preload !== false) { | ||
preload(cid) | ||
let lastCid = cid | ||
let lastRemainderPath = options.path || '' | ||
|
||
if (lastRemainderPath.startsWith('/')) { | ||
lastRemainderPath = lastRemainderPath.substring(1) | ||
} | ||
|
||
yield * ipld.resolve(cid, options.path, { signal: options.signal }) | ||
if (options.path) { | ||
try { | ||
for await (const { value, remainderPath } of ipld.resolve(cid, options.path, { | ||
signal: options.signal | ||
})) { | ||
if (!CID.isCID(value)) { | ||
break | ||
} | ||
|
||
lastRemainderPath = remainderPath | ||
lastCid = value | ||
} | ||
} catch (err) { | ||
// TODO: add error codes to IPLD | ||
if (err.message.startsWith('Object has no property')) { | ||
err.message = `no link named "${lastRemainderPath.split('/')[0]}" under ${lastCid}` | ||
err.code = 'ERR_NO_LINK' | ||
} | ||
throw err | ||
} | ||
} | ||
|
||
return { | ||
cid: lastCid, | ||
remainderPath: lastRemainderPath || '' | ||
} | ||
}) | ||
} |
Oops, something went wrong.