diff --git a/package.json b/package.json index fae2d92..8fe417a 100644 --- a/package.json +++ b/package.json @@ -20,8 +20,9 @@ }, "dependencies": { "@polkadot/api": "^3.3.1", + "axios": "^0.21.1", "bignumber.js": "^9.0.1", - "ipfs-http-client": "^48.0.0", + "ipfs-http-client": "^48.1.3", "lodash": "^4.17.20", "node-cron": "^2.0.3", "winston": "^3.3.3" diff --git a/src/chain/index.ts b/src/chain/index.ts index ff34bc9..6311eba 100644 --- a/src/chain/index.ts +++ b/src/chain/index.ts @@ -88,6 +88,7 @@ export default class CrustApi { }); } + /// READ methods /** * Register a pubsub event, dealing with new block * @param handler handling with new block diff --git a/src/decision/index.ts b/src/decision/index.ts index 3a488d8..098a960 100644 --- a/src/decision/index.ts +++ b/src/decision/index.ts @@ -7,7 +7,8 @@ import TaskQueue, {BT} from '../queue'; import IpfsApi from '../ipfs'; import CrustApi, {DetailFileInfo, FileInfo} from '../chain'; import {logger} from '../log'; -import {hexToString} from '../util'; +import {gigaBytesToBytes, hexToString} from '../util'; +import SworkerApi from '../sworker'; // The initial probability is 5‰ const initialProbability = 0.005; @@ -22,15 +23,23 @@ interface Task extends BT { export default class DecisionEngine { private readonly crustApi: CrustApi; private readonly ipfsApi: IpfsApi; + private readonly sworkerApi: SworkerApi; private pullingQueue: TaskQueue; private sealingQueue: TaskQueue; private currentBn: number; - constructor(chainAddr: string, ipfsAddr: string, mto: number) { + constructor( + chainAddr: string, + ipfsAddr: string, + sworkerAddr: string, + ito: number, + sto: number + ) { this.crustApi = new CrustApi(chainAddr); - this.ipfsApi = new IpfsApi(ipfsAddr, mto); + this.ipfsApi = new IpfsApi(ipfsAddr, ito); + this.sworkerApi = new SworkerApi(sworkerAddr, sto); - // MaxQueueLength is 50 and Overdue is 600 blocks(1h) + // MaxQueueLength is 50 and Expired with 600 blocks(1h) this.pullingQueue = new TaskQueue(50, 600); this.sealingQueue = new TaskQueue(30, 600); @@ -73,7 +82,7 @@ export default class DecisionEngine { size: newFile.size, }; logger.info( - ` ↪ 🎁 Found new file, adding it to pulling queue ${JSON.stringify( + ` ↪ ✨ Found new file, adding it to pulling queue ${JSON.stringify( nt )}` ); @@ -107,9 +116,9 @@ export default class DecisionEngine { for (const pt of oldPts) { // 2. If join pullings and start puling in ipfs, otherwise push back to pulling tasks - if (await this.pickOrDropPulling(pt)) { + if (await this.pickUpPulling(pt)) { logger.info( - ` ↪ 🎁 Pick pulling task ${JSON.stringify(pt)}, pulling from ipfs` + ` ↪ 🗳 Pick pulling task ${JSON.stringify(pt)}, pulling from ipfs` ); // Async pulling this.ipfsApi @@ -147,24 +156,32 @@ export default class DecisionEngine { */ async subscribeSealings(): Promise { return cron.schedule('* * * * *', async () => { - const oldPts: Task[] = this.sealingQueue.tasks; - const newPts = new Array(); + const oldSts: Task[] = this.sealingQueue.tasks; + const newSts = new Array(); logger.info('⏳ Checking sealing queue...'); - logger.info(` ↪ 💌 Sealing queue length: ${oldPts.length}`); + logger.info(` ↪ 💌 Sealing queue length: ${oldSts.length}`); // 1. Loop sealing tasks - for (const pt of oldPts) { + for (const st of oldSts) { // 2. Judge if sealing successful, otherwise push back to sealing tasks - if (await this.pickOrDropSealing(pt.cid, pt.size)) { - // TODO: Call `sWorker.seal(pt.cid)` here - logger.info(` ↪ ⚙️ Send to sWorker: ${JSON.stringify(pt)}`); - } else { - newPts.push(pt); + if (await this.pickUpSealing(st)) { + logger.info( + ` ↪ 🗳 Pick sealing task ${JSON.stringify(st)}, sending to sWorker` + ); + if (await this.sworkerApi.seal(st.cid)) { + logger.info(` ↪ 💖 Seal ${st.cid} successfully`); + continue; // Continue with next sealing task + } else { + logger.error(` ↪ 💥 Seal ${st.cid} failed`); + } } + + // Otherwise, push back to sealing queue + newSts.push(st); } // 3. Push back to sealing queue - this.sealingQueue.tasks = newPts; + this.sealingQueue.tasks = newSts; }); } @@ -174,12 +191,11 @@ export default class DecisionEngine { /// 2. judge file size and free space from local ipfs repo; /** * Add or ignore to pulling queue by a given cid - * @param cid ipfs cid value - * @param f_size truly file size + * @param t Task * @returns if can pick */ // TODO: add pulling pick up strategy here, basically random with pks? - private async pickOrDropPulling(t: Task): Promise { + private async pickUpPulling(t: Task): Promise { try { // 1. Get and judge file size is match const size = await this.ipfsApi.size(t.cid); @@ -190,10 +206,8 @@ export default class DecisionEngine { } // 2. Get and judge repo can take it, make sure the free can take double file - // TODO: Remove this, cause this is no fucking use - const free = await this.ipfsApi.free(); - const bn_f_size = new BigNumber(t.size); - if (free <= bn_f_size.multipliedBy(2)) { + const free = await this.freeSpace(); + if (free <= t.size * 2) { logger.warn(` ↪ ⚠️ Free space not enought ${free} < ${size}*2`); return false; } @@ -208,31 +222,31 @@ export default class DecisionEngine { /** * Pick or drop sealing queue by a given cid - * @param cid ipfs cid value - * @param f_size truly file size + * @param t Task */ - private async pickOrDropSealing( - _cid: string, - _f_size: number - ): Promise { - // TODO: check free space or just send into sWorker? - return true; + private async pickUpSealing(t: Task): Promise { + const free = await this.freeSpace(); + + if (free <= t.size) { + logger.warn(` ↪ ⚠️ Free space not enought ${free} < ${t.size}`); + return false; + } + + return !(await this.isReplicaFull(t.cid)); } /** - * Query the given cid is already been picked plus a certain - * probability + * Judge if replica on chain is full * @param cid ipfs cid value - * @param bn task block number + * @returns boolean * @throws crustApi error */ - private async shouldPull(cid: string, bn: number): Promise { + private async isReplicaFull(cid: string): Promise { // TODO: Set flag to let user choose enable the `only take order file` const fileInfo: DetailFileInfo | null = await this.crustApi.maybeGetNewFile( cid ); - // If replicas already reach the limit if ( fileInfo && fileInfo.replicas.length > Number(fileInfo.expected_replica_count) @@ -240,9 +254,26 @@ export default class DecisionEngine { logger.warn( ` ↪ ⚠️ File replica already full with ${fileInfo.replicas.length}` ); + return true; + } + + return false; + } + + /** + * Query the given cid is already been picked plus a certain + * probability + * @param cid ipfs cid value + * @param bn task block number + * @returns should pull from ipfs + * @throws crustApi error + */ + private async shouldPull(cid: string, bn: number): Promise { + // If replicas already reach the limit + if (await this.isReplicaFull(cid)) { return false; } - // else, calculate the probability with `expired_date` + // Else, calculate the probability with `expired_date` // 1. Generate a number between 0 and 1 const randNum = Math.random(); @@ -257,4 +288,13 @@ export default class DecisionEngine { // 3. Judge if we hit the spot return randNum < probability; } + + /** + * Got free space size from sWorker + * @returns free space size + */ + private async freeSpace(): Promise { + const freeGBSize = await this.sworkerApi.free(); + return gigaBytesToBytes(freeGBSize); + } } diff --git a/src/index.ts b/src/index.ts index ecdad45..8b17a04 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,10 +5,18 @@ import {logger} from './log'; const chainAddr = argv[2] || 'ws://localhost:9944'; const ipfsAddr = argv[3] || 'http://localhost:5001'; -const maxIpfsTimeout = 20000; // 20s +const sworkerAddr = argv[4] || 'http://localhost:12222'; +const ipfsTimeout = 20000; // 20s +const sworkerTimeout = 20000; //20s try { - const de = new DecisionEngine(chainAddr, ipfsAddr, maxIpfsTimeout); + const de = new DecisionEngine( + chainAddr, + ipfsAddr, + sworkerAddr, + ipfsTimeout, + sworkerTimeout + ); // TODO: Get cancellation signal and handle errors? de.subscribeNewFiles().catch(e => diff --git a/src/ipfs/index.ts b/src/ipfs/index.ts index bfe3da0..e2abc15 100644 --- a/src/ipfs/index.ts +++ b/src/ipfs/index.ts @@ -3,7 +3,7 @@ const IpfsHttpClient = require('ipfs-http-client'); const {CID} = require('ipfs-http-client'); export default class IpfsApi { - private ipfs: any; + private readonly ipfs: any; constructor(ipfsAddr: string, mto: number) { // TODO: Check connection and ipfsAddr is legal diff --git a/src/sworker/index.ts b/src/sworker/index.ts new file mode 100644 index 0000000..642e03f --- /dev/null +++ b/src/sworker/index.ts @@ -0,0 +1,64 @@ +import axios, {AxiosInstance} from 'axios'; +import {parseObj} from '../util'; + +export default class SworkerApi { + private readonly sworker: AxiosInstance; + + constructor(sworkerAddr: string, to: number) { + this.sworker = axios.create({ + baseURL: sworkerAddr + '/api/v0', + timeout: to, + headers: {'Content-Type': 'application/json'}, + }); + } + + /// WRITE methods + /** + * Seal cid + * @param cid ipfs cid + * @returns seal success or failed + * @throws sWorker api error | timeout + */ + async seal(cid: string): Promise { + const res = await this.sworker.post( + '/storage/seal', + JSON.stringify({cid: cid}) + ); + + return res.status === 200; + } + + /** + * Delete both origin and sealed file by cid + * @param cid ipfs cid + * @returns delete success or failed + * @throws sWorker api error | timeout + */ + async delete(cid: string): Promise { + const res = await this.sworker.post( + '/storage/delete', + JSON.stringify({cid: cid}) + ); + + return res.status === 200; + } + + /// READ methods + /** + * Query local free storage size + * @returns free space size(GB) + * @throws sWorker api error | timeout + */ + async free(): Promise { + const res = await this.sworker.get('/workload'); + + if (res && res.status === 200) { + const body = parseObj(res.data); + return ( + Number(body.srd['srd_complete']) + Number(body.srd['disk_available']) + ); + } + + return 0; + } +} diff --git a/src/util/index.ts b/src/util/index.ts index 2ff2080..8bf6a3b 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -14,3 +14,14 @@ export function parseObj(o: any) { export function hexToString(hex: string): string { return Buffer.from(hex.substring(2), 'hex').toString(); } + +/** + * GB to B + * number's max value: 9007199254740991 + * so basically we don't need BigNumber at all + * @param gb GB size + * @returns B size + */ +export function gigaBytesToBytes(gb: number): number { + return gb * 1073741824; +} diff --git a/yarn.lock b/yarn.lock index dd2451c..b76252b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,13 +2,6 @@ # yarn lockfile v1 -"@achingbrain/electron-fetch@^1.7.2": - version "1.7.2" - resolved "https://registry.yarnpkg.com/@achingbrain/electron-fetch/-/electron-fetch-1.7.2.tgz#df48e7e33b217520be1abb5bef151828fef7cf73" - integrity sha512-ShX5frO+2OddzRIlUb8D0Ao2eC3uZl910CYnRIPGLLM360vQceeOqpivwNdbry41Ph3MMtLR4RpzGdaADGG8Gg== - dependencies: - encoding "^0.1.13" - "@babel/code-frame@^7.0.0": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" @@ -590,6 +583,13 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -631,12 +631,12 @@ blakejs@^1.1.0: resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= -blob-to-it@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/blob-to-it/-/blob-to-it-0.0.2.tgz#851b4db0be4acebc86dd1c14c14b77fdc473e9b0" - integrity sha512-3/NRr0mUWQTkS71MYEC1teLbT5BTs7RZ6VMPXDV6qApjw3B4TAZspQuvDkYfHuD/XzL5p/RO91x5XRPeJvcCqg== +blob-to-it@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/blob-to-it/-/blob-to-it-1.0.1.tgz#a520e21351badd50064d776589639aa197ef97e4" + integrity sha512-papO4swPtR4MtNQ2foUkaS9e7HlD8XFQEBL3HZNhT4Qp6RQ/7t4C6bo4kRKtJV6A3AIgKR05Z9sbB+na6u+QYA== dependencies: - browser-readablestream-to-it "^0.0.2" + browser-readablestream-to-it "^1.0.1" bn.js@^4.11.9, bn.js@^4.4.0: version "4.11.9" @@ -690,10 +690,10 @@ brorand@^1.0.1: resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= -browser-readablestream-to-it@0.0.2, browser-readablestream-to-it@^0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-0.0.2.tgz#4a5c2a20567623c106125ca6b640f68b081cea25" - integrity sha512-bbiTccngeAbPmpTUJcUyr6JhivADKV9xkNJVLdA91vjdzXyFBZ6fgrzElQsV3k1UNGQACRTl3p4y+cEGG9U48A== +browser-readablestream-to-it@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browser-readablestream-to-it/-/browser-readablestream-to-it-1.0.1.tgz#50ac349f38f6c0ace3c338f90699f7dc936c46ca" + integrity sha512-vLeoyPpVY8IL5R4AEMI5nICVpuK1VBwBi6OUyuD1U9NUOL7UmAgP4agfbkkkZf+cBZaYtCYrgASd6YyVbIbsjA== buffer-from@^1.0.0: version "1.1.1" @@ -708,6 +708,14 @@ buffer@^5.4.3, buffer@^5.5.0, buffer@^5.6.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.1: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + bufferutil@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.2.tgz#79f68631910f6b993d870fc77dc0a2894eb96cd5" @@ -1087,6 +1095,13 @@ duplexer3@^0.1.4: resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= +electron-fetch@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/electron-fetch/-/electron-fetch-1.7.2.tgz#7ecc63629715a5de286957a8aceb35272c5d0b02" + integrity sha512-J7D136rhxIhPwYJsnHPpKgbyd4NUCGnKM1CuXLhmVWZdc8f6+LBiJqUOTngtSacj+xvGWgaDWOAuCXnhqiMTCw== + dependencies: + encoding "^0.1.13" + elliptic@^6.5.3: version "6.5.3" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" @@ -1472,6 +1487,11 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +follow-redirects@^1.10.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.1.tgz#5f69b813376cee4fd0474a3aba835df04ab763b7" + integrity sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg== + form-data@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" @@ -1481,15 +1501,6 @@ form-data@^3.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -fs-extra@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^9.0.1: version "9.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc" @@ -1733,7 +1744,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -1818,46 +1829,48 @@ ip-regex@^4.0.0, ip-regex@^4.2.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.2.0.tgz#a03f5eb661d9a154e3973a03de8b23dd0ad6892e" integrity sha512-n5cDDeTWWRwK1EBoWwRti+8nP4NbytBBY0pldmnIkq6Z55KNFmWofh4rl9dPZpj+U/nVq7gweR3ylrvMt4YZ5A== -ipfs-core-utils@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/ipfs-core-utils/-/ipfs-core-utils-0.5.0.tgz#4721e03ca5331d3d11e309b2205da39c7193a74e" - integrity sha512-yXioQTgwX2gaJuIxofqyTd0tPBPwZbbFAebiMDPxmbERtbkLBupx3ElsTqFGoHQONw6GYBPo2yTqLRJKJofeZw== +ipfs-core-utils@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/ipfs-core-utils/-/ipfs-core-utils-0.5.4.tgz#c7fa508562086be65cebb51feb13c58abbbd3d8d" + integrity sha512-V+OHCkqf/263jHU0Fc9Rx/uDuwlz3PHxl3qu6a5ka/mNi6gucbFuI53jWsevCrOOY9giWMLB29RINGmCV5dFeQ== dependencies: - blob-to-it "0.0.2" - browser-readablestream-to-it "0.0.2" + any-signal "^2.0.0" + blob-to-it "^1.0.1" + browser-readablestream-to-it "^1.0.1" cids "^1.0.0" err-code "^2.0.3" - ipfs-utils "^4.0.0" + ipfs-utils "^5.0.0" it-all "^1.0.4" it-map "^1.0.4" - it-peekable "0.0.1" + it-peekable "^1.0.1" + multiaddr "^8.0.0" + multiaddr-to-uri "^6.0.0" + parse-duration "^0.4.4" + timeout-abort-controller "^1.1.1" uint8arrays "^1.1.0" -ipfs-http-client@^48.0.0: - version "48.0.0" - resolved "https://registry.yarnpkg.com/ipfs-http-client/-/ipfs-http-client-48.0.0.tgz#1eb8f2b72710f66862a8a2464c0604c4909e795d" - integrity sha512-Nz26Aeytc5QvikiDVOwmrE3vkLRsdGrcCTeIdN/1dxFI6n0K+jFUL/2c3H3rJWRgEcD7yMPxNU9KtLF0x0okXA== +ipfs-http-client@^48.1.3: + version "48.1.3" + resolved "https://registry.yarnpkg.com/ipfs-http-client/-/ipfs-http-client-48.1.3.tgz#d9b91b1f65d54730de92290d3be5a11ef124b400" + integrity sha512-+JV4cdMaTvYN3vd4r6+mcVxV3LkJXzc4kn2ToVbObpVpdqmG34ePf1KlvFF8A9gjcel84WpiP5xCEV/IrisPBA== dependencies: any-signal "^2.0.0" bignumber.js "^9.0.0" cids "^1.0.0" debug "^4.1.1" form-data "^3.0.0" - ipfs-core-utils "^0.5.0" - ipfs-utils "^4.0.0" - ipld-block "^0.10.1" + ipfs-core-utils "^0.5.4" + ipfs-utils "^5.0.0" + ipld-block "^0.11.0" ipld-dag-cbor "^0.17.0" ipld-dag-pb "^0.20.0" ipld-raw "^6.0.0" - iso-url "^0.4.7" it-last "^1.0.4" it-map "^1.0.4" it-tar "^1.2.2" - it-to-buffer "^1.0.2" it-to-stream "^0.1.2" merge-options "^2.0.0" multiaddr "^8.0.0" - multiaddr-to-uri "^6.0.0" multibase "^3.0.0" multicodec "^2.0.1" multihashes "^3.0.1" @@ -1867,20 +1880,21 @@ ipfs-http-client@^48.0.0: stream-to-it "^0.2.2" uint8arrays "^1.1.0" -ipfs-utils@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/ipfs-utils/-/ipfs-utils-4.0.0.tgz#f53b79294f500e43661cb6b2a9d7fa301d3fa3d3" - integrity sha512-HVeDUm4K4fYb44O1y2l4sNvDuzIB3+K6ZqYj45Bv3oqGmpBkm+ELq2Sssghpwk5b4ppsfOzSUoupMFdlg+Fk7w== +ipfs-utils@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ipfs-utils/-/ipfs-utils-5.0.1.tgz#7c0053d5e77686f45577257a73905d4523e6b4f7" + integrity sha512-28KZPgO4Uf5duT2ORLAYfboUp98iUshDD7yRAfbNxNAR8Dtidfn6o20rZfoXnkri2zKBVIPlJkuCPmPJB+6erg== dependencies: - "@achingbrain/electron-fetch" "^1.7.2" abort-controller "^3.0.0" any-signal "^2.1.0" - buffer "^5.6.0" + buffer "^6.0.1" + electron-fetch "^1.7.2" err-code "^2.0.0" fs-extra "^9.0.1" is-electron "^2.2.0" - iso-url "^0.4.7" - it-glob "0.0.8" + iso-url "^1.0.0" + it-glob "0.0.10" + it-to-stream "^0.1.2" merge-options "^2.0.0" nanoid "^3.1.3" native-abort-controller "0.0.3" @@ -1888,13 +1902,12 @@ ipfs-utils@^4.0.0: node-fetch "^2.6.0" stream-to-it "^0.2.0" -ipld-block@^0.10.1: - version "0.10.1" - resolved "https://registry.yarnpkg.com/ipld-block/-/ipld-block-0.10.1.tgz#a9de6185257cf56903cc7f71de450672f4871b65" - integrity sha512-lPMfW9tA2hVZw9hdO/YSppTxFmA0+5zxcefBOlCTOn+12RLyy+pdepKMbQw8u0KESFu3pYVmabNRWuFGcgHLLw== +ipld-block@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ipld-block/-/ipld-block-0.11.0.tgz#71b24b70f4d867b0609a738efa4872ef4df84c7a" + integrity sha512-Kk56OOPmlWAjXfBJXvx2jX5RA6R9qUrcc2JXwF7Y4IL9mlmxcxTNkgcsJYR78DbyMllQbi7yreghjGjtCTYKaw== dependencies: cids "^1.0.0" - class-is "^1.1.0" ipld-dag-cbor@^0.17.0: version "0.17.0" @@ -2082,7 +2095,12 @@ iso-constants@^0.1.2: resolved "https://registry.yarnpkg.com/iso-constants/-/iso-constants-0.1.2.tgz#3d2456ed5aeaa55d18564f285ba02a47a0d885b4" integrity sha512-OTCM5ZCQsHBCI4Wdu4tSxvDIkmDHd5EwJDps5mKqnQnWJSKlnwMs3EDZ4n3Fh1tmkWkDlyd2vCDbEYuPbyrUNQ== -iso-url@^0.4.7, iso-url@~0.4.7: +iso-url@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-1.0.0.tgz#2dd32e5915eb0ecca3a6ff419eb35a0c60eeabc8" + integrity sha512-n/MsHgKOoHcFrhsxfbM3aaSdUujoFrrZ3537p3RW80AL7axL36acCseoMwIW4tNOl0n0SnkzNyVh4bREwmHoPQ== + +iso-url@~0.4.7: version "0.4.7" resolved "https://registry.yarnpkg.com/iso-url/-/iso-url-0.4.7.tgz#de7e48120dae46921079fe78f325ac9e9217a385" integrity sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog== @@ -2099,12 +2117,12 @@ it-concat@^1.0.0: dependencies: bl "^4.0.0" -it-glob@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/it-glob/-/it-glob-0.0.8.tgz#b63d24945c18b35de8bb593a8c872fd0257c0cac" - integrity sha512-PmIAgb64aJPM6wwT1UTlNDAJnNgdGrvr0vRr3AYCngcUuq1KaAovuz0dQAmUkaXudDG3EQzc7OttuLW9DaL3YQ== +it-glob@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/it-glob/-/it-glob-0.0.10.tgz#4defd9286f693847c3ff483d2ff65f22e1359ad8" + integrity sha512-p1PR15djgPV7pxdLOW9j4WcJdla8+91rJdUU2hU2Jm68vkxpIEXK55VHBeH8Lvqh2vqLtM83t8q4BuJxue6niA== dependencies: - fs-extra "^8.1.0" + fs-extra "^9.0.1" minimatch "^3.0.4" it-last@^1.0.4: @@ -2117,10 +2135,10 @@ it-map@^1.0.4: resolved "https://registry.yarnpkg.com/it-map/-/it-map-1.0.4.tgz#d413d2b0c3d8d9703df9e8a915ad96cb74a837ac" integrity sha512-LZgYdb89XMo8cFUp6jF0cn5j3gF7wcZnKRVFS3qHHn0bPB2rpToh2vIkTBKduZLZxRRjWx1VW/udd98x+j2ulg== -it-peekable@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-0.0.1.tgz#e3f91583d172444b9cd894ed2df6e26f0c176617" - integrity sha512-fd0JzbNldseeq+FFWthbqYB991UpKNyjPG6LqFhIOmJviCxSompMyoopKIXvLPLY+fBhhv2CT5PT31O/lEnTHw== +it-peekable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/it-peekable/-/it-peekable-1.0.1.tgz#7e2c485164a37618cb546e8809ae660bb38ed84b" + integrity sha512-civpIsgG1N+nYXNhm4Qzb9S89QZOfn4M6wVpH9IIilkJ9UFcDElWQuO1qmjXkdm3M5yg5fk+blW0aSCmu4SGlA== it-reader@^2.0.0: version "2.1.0" @@ -2141,13 +2159,6 @@ it-tar@^1.2.2: it-reader "^2.0.0" p-defer "^3.0.0" -it-to-buffer@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/it-to-buffer/-/it-to-buffer-1.0.4.tgz#4fcbd34c9c503e607744c0fdbeaff30008429703" - integrity sha512-wycpGeAdQ8WH8eSBkMHN/HMNiQ0Y88XEXo6s6LGJbQZjf9K7ppVzUfCXn7OnxFfUPN0HTWZr+uhthwtrwMTTfw== - dependencies: - buffer "^5.5.0" - it-to-stream@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/it-to-stream/-/it-to-stream-0.1.2.tgz#7163151f75b60445e86b8ab1a968666acaacfe7b" @@ -2205,13 +2216,6 @@ json-text-sequence@~0.1.0: dependencies: delimit-stream "0.1.0" -jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -2981,6 +2985,11 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retimer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/retimer/-/retimer-2.0.0.tgz#e8bd68c5e5a8ec2f49ccb5c636db84c04063bbca" + integrity sha512-KLXY85WkEq2V2bKex/LOO1ViXVn2KGYe4PYysAdYdjmraYIUsVkXu8O4am+8+5UbaaGl1qho4aqAAPHNQ4GSbg== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -3300,6 +3309,14 @@ through@^2.3.6: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +timeout-abort-controller@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/timeout-abort-controller/-/timeout-abort-controller-1.1.1.tgz#2c3c3c66f13c783237987673c276cbd7a9762f29" + integrity sha512-BsF9i3NAJag6T0ZEjki9j654zoafI2X6ayuNd6Tp8+Ul6Tr5s4jo973qFeiWrRSweqvskC+AHDKUmIW4b7pdhQ== + dependencies: + abort-controller "^3.0.0" + retimer "^2.0.0" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -3449,11 +3466,6 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" -universalify@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - universalify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-1.0.0.tgz#b61a1da173e8435b2fe3c67d29b9adf8594bd16d"