const debug = require('debug')('ipfs-pinner'); async function promiseAllInBatches(task, items, batchSize) { let position = 0; let results = []; while (position < items.length) { const itemsForBatch = items.slice(position, position + batchSize); results = [...results, ...await Promise.allSettled(itemsForBatch.map(item => task(item)))]; position += batchSize; } return results; } class IpfsPinner { constructor (kredits, ipfsApi) { this.kredits = kredits; this.ipfsApi = ipfsApi || this.kredits.ipfs; } async pinAll () { const contributorHashes = await this._pinAllFromContract(this.kredits.Contributor); const contributionHashes = await this._pinAllFromContract(this.kredits.Contribution); const reimbursementHashes = await this._pinAllFromContract(this.kredits.Reimbursement); return contributorHashes.concat(contributionHashes) .concat(reimbursementHashes); } monitor (callback) { this.kredits.Contribution.on('ContributionAdded', (id) => { this.kredits.Contribution.getData(id) .then(data => { return this.ipfsApi.pin(data); }) .then(callback); }); this.kredits.Contributor.on('ContributorAdded', (id) => { this.kredits.Contribution.getData(id) .then(data => { return this.ipfsApi.pin(data); }) .then(callback); }); this.kredits.Contributor.on('ContributorProfileUpdated', (id) => { this.kredits.Contributor.getData(id) .then(data => { return this.ipfsApi.pin(data); }) .then(callback); }); } async _pinAllFromContract (contract) { debug(`Pinning data from ${contract.constructor.name}...`); const count = await contract.count; debug('Item count:', count); const ids = [...Array(count).keys()].map(i => i+1); const cids = []; async function loadAndPin (id) { debug(`Loading ${contract.constructor.name} #${id}`); return contract.getData(id).then(data => { debug(`Pinning ${contract.constructor.name} #${id}`); return this.ipfsApi.pin(data).then(cid => cids.push(cid)); }); } await promiseAllInBatches(loadAndPin.bind(this), ids, 100); return cids; } } module.exports = IpfsPinner;