const debug = require('debug')('ipfs-pinner'); const cliProgress = require('cli-progress'); class IpfsPinner { constructor (kredits, options={}) { this.kredits = kredits; this.ipfsApi = this.kredits.ipfs; this.progressBars = !!options.progress && !process.env.DEBUG; if (this.progressBars) { this.multibar = new cliProgress.MultiBar({ stopOnComplete: true, clearOnComplete: false, hideCursor: false, etaBuffer: 30, format: '{entity} [{bar}] {percentage}% | ETA: {eta_formatted} | {value}/{total}' }, cliProgress.Presets.shades_grey); } } async pinAll () { console.log('Pinning IPFS documents for all known items...\n') const cids = []; const promises = []; const contracts = [ this.kredits.Contributor, this.kredits.Contribution, // TODO uncomment once we have data here // this.kredits.Reimbursement ] for (const contract of contracts) { debug(`Pinning data from ${contract.constructor.name}...`); const itemCount = await contract.count; debug('Item count:', itemCount); let bar; if (this.progressBars) { bar = this.multibar.create(itemCount, 0); bar.update(0, {entity: `${contract.constructor.name}s`.padEnd(14)}); } promises.push(this._pinAllFromContract(contract, itemCount, bar) .then(res => { cids.push(...res); })); } await Promise.all(promises); return cids; } watch (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, itemCount, progressBar) { const ids = [...Array(itemCount).keys()].map(i => i+1); const cids = []; const batchSize = 20; let position = 0; while (position < itemCount) { const batchIds = ids.slice(position, position + batchSize); await Promise.all(batchIds.map(async id => { const data = await contract.getData(id); debug(`Loaded ${contract.constructor.name} #${id}`); const cid = await this.ipfsApi.pin(data); debug(`Pinned ${contract.constructor.name} #${id} at ${cid}`); cids.push(cid); if (this.progressBars) { progressBar.increment(); } })); position += batchSize; } return cids; } } module.exports = IpfsPinner;