From 1a408f59428134e6a7c755c8aa7cb0c0dda0fb61 Mon Sep 17 00:00:00 2001 From: Kevin Siegler Date: Mon, 13 Jan 2020 08:42:24 -0600 Subject: [PATCH] feat(helpers): add IPFS helper function --- package.json | 1 + src/helpers/index.js | 7 ++++-- src/helpers/parseIpfs.js | 52 +++++++++++++++++++++++++++++++++++++++ test/examples/examples.js | 34 +++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/helpers/parseIpfs.js diff --git a/package.json b/package.json index d54cde3..02b8850 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ }, "dependencies": { "@babel/runtime": "^7.1.2", + "axios": "^0.19.0", "bn.js": "^4.11.8", "date-fns": "2.0.0-alpha.22", "web3-eth": "^1.2.1", diff --git a/src/helpers/index.js b/src/helpers/index.js index c2c3575..6096a2a 100644 --- a/src/helpers/index.js +++ b/src/helpers/index.js @@ -6,6 +6,7 @@ import formatPct from './formatPct' import tokenAmount from './tokenAmount' import transformTime from './transformTime' import radspec from './radspec' +import parseIpfs from './parseIpfs' const defaultHelpers = { formatDate, @@ -14,7 +15,8 @@ const defaultHelpers = { formatPct, fromHex, radspec, - echo + echo, + parseIpfs } export { @@ -27,5 +29,6 @@ export { fromHex, radspec, transformTime, - tokenAmount + tokenAmount, + parseIpfs } diff --git a/src/helpers/parseIpfs.js b/src/helpers/parseIpfs.js new file mode 100644 index 0000000..64b14ab --- /dev/null +++ b/src/helpers/parseIpfs.js @@ -0,0 +1,52 @@ +import axios from 'axios' +import Web3Utils from 'web3-utils' + +// default endpoints to be queried +const ipfsEndpoints = ['https://ipfs.autark.xyz:5001/api/v0'] + +export default () => + async (cid, node = '', ...keys) => { + node && ipfsEndpoints.push(node) + let rejectedPromises = 0 + const results = await Promise.all( + ipfsEndpoints.map(async ipfsEndpoint => { + const ipfsQuery = `${ipfsEndpoint}/cat?arg=${cid}` + try { + const { data } = await axios.get(ipfsQuery) + return getValue(data, keys, ipfsQuery) + } catch (err) { + return ++rejectedPromises < ipfsEndpoints.length + ? null : { + type: 'string', + value: `failed getting data from IPFS: ${err}` + } + } + }) + ) + return results.reduce((finalResult, candidate) => candidate || finalResult) + } + +const getValue = (data, keys = [], ipfsQuery) => { + const key = keys.shift() + if (!key) { + switch (typeof data) { + case 'string': + return Web3Utils.isAddress(data) + ? { + type: 'address', + value: Web3Utils.toChecksumAddress(data) + } + : { + type: 'string', + value: data + } + default: + return { + type: 'string', + value: ipfsQuery + } + } + } + + return data[key] ? getValue(data[key], keys, ipfsQuery) : { value: `failed to find value for key: ${key}`, type: 'string' } +} diff --git a/test/examples/examples.js b/test/examples/examples.js index 363caf3..26327be 100644 --- a/test/examples/examples.js +++ b/test/examples/examples.js @@ -359,6 +359,40 @@ const cases = [ source: "`_bool ? 'h' + _var + 'o' : 'bye'`", bindings: { _bool: bool(true), _var: string('ell') } }, 'hello'], + [{ + source: 'parse this ipfs hash: `@parseIpfs(test)`', + bindings: { test: string('Qmc3zqKcwzbbvw3MQm3hXdg8BQoFjGdZiGdAfXAyAGGdLi') } + }, 'parse this ipfs hash: Don\'t we all.'], + [{ + source: 'get registry address: `@parseIpfs(test,"", "env", "registry")`', + bindings: { + test: string('QmWP9roMebu5LyV6Q4RNooAw6yj18zKUqXqAc5Lxy1YVFh'), + } + }, 'get registry address: 0x5f6F7E8cc7346a11ca2dEf8f827b7a0b612c56a1'], + [{ + source: 'works with invalid custom node: `@parseIpfs(test,"http://invalidaddress", "env", "registry")`', + bindings: { + test: string('QmWP9roMebu5LyV6Q4RNooAw6yj18zKUqXqAc5Lxy1YVFh'), + } + }, 'works with invalid custom node: 0x5f6F7E8cc7346a11ca2dEf8f827b7a0b612c56a1'], + [{ + source: 'fails to get networkId: `@parseIpfs(test,"", "env", "networkId")` (undefined key)', + bindings: { + test: string('QmWP9roMebu5LyV6Q4RNooAw6yj18zKUqXqAc5Lxy1YVFh'), + } + }, 'fails to get networkId: failed to find value for key: networkId (undefined key)'], + [{ + source: 'fails to get registry address: `@parseIpfs(test,"", "env", "registry")` (invalid CID)', + bindings: { + test: string('Qm'), + } + }, 'fails to get registry address: failed getting data from IPFS: Error: Request failed with status code 500 (invalid CID)'], + [{ + source: 'returns links for non-string values: `@parseIpfs(test,"", "env")`', + bindings: { + test: string('QmWP9roMebu5LyV6Q4RNooAw6yj18zKUqXqAc5Lxy1YVFh'), + } + }, 'returns links for non-string values: https://ipfs.autark.xyz:5001/api/v0/cat?arg=QmWP9roMebu5LyV6Q4RNooAw6yj18zKUqXqAc5Lxy1YVFh'], // External calls with multiple return values [{