diff --git a/package.json b/package.json index 18a7f1be85..883982a605 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "ipfs-bitswap": "^0.26.0", "ipfs-block": "~0.8.1", "ipfs-block-service": "~0.16.0", - "ipfs-http-client": "^39.0.2", + "ipfs-http-client": "github:ipfs/js-ipfs-http-client#feat/human-option-bitswap-stat", "ipfs-http-response": "~0.4.0", "ipfs-mfs": "^0.13.0", "ipfs-multipart": "^0.2.0", @@ -164,6 +164,7 @@ "peer-book": "^0.9.1", "peer-id": "^0.12.2", "peer-info": "~0.15.1", + "pretty-bytes": "^5.3.0", "progress": "^2.0.1", "promise-nodeify": "^3.0.1", "promisify-es6": "^1.0.3", @@ -204,7 +205,7 @@ "execa": "^3.0.0", "form-data": "^3.0.0", "hat": "0.0.3", - "interface-ipfs-core": "^0.119.0", + "interface-ipfs-core": "github:ipfs/interface-js-ipfs-core#test/add-human-option-test-bitswap-stat", "ipfs-interop": "^0.1.1", "ipfsd-ctl": "^0.47.2", "libp2p-websocket-star": "~0.10.2", diff --git a/src/cli/commands/bitswap/stat.js b/src/cli/commands/bitswap/stat.js index bcc5356117..46c51f28a8 100644 --- a/src/cli/commands/bitswap/stat.js +++ b/src/cli/commands/bitswap/stat.js @@ -13,24 +13,35 @@ module.exports = { describe: 'Number base to display CIDs in. Note: specifying a CID base for v0 CIDs will have no effect.', type: 'string', choices: multibase.names + }, + human: { + type: 'boolean', + default: false } }, - handler ({ getIpfs, print, cidBase, resolve }) { + handler ({ getIpfs, print, cidBase, resolve, human }) { resolve((async () => { const ipfs = await getIpfs() - const stats = await ipfs.bitswap.stat() - stats.wantlist = stats.wantlist.map(k => cidToString(k['/'], { base: cidBase, upgrade: false })) - stats.peers = stats.peers || [] + const stats = await ipfs.bitswap.stat({ human }) + + if (!human) { + const wantlist = stats.wantlist.map((elem) => cidToString(elem['/'], { base: cidBase, upgrade: false })) + stats.wantlist = `[${wantlist.length} keys] + ${wantlist.join('\n ')}` + stats.peers = `[${stats.peers.length}]` + } print(`bitswap status - blocks received: ${stats.blocksReceived} - dup blocks received: ${stats.dupBlksReceived} - dup data received: ${stats.dupDataReceived}B - wantlist [${stats.wantlist.length} keys] - ${stats.wantlist.join('\n ')} - partners [${stats.peers.length}] - ${stats.peers.join('\n ')}`) + provides buffer: ${stats.provideBufLen} + blocks received: ${stats.blocksReceived} + blocks sent: ${stats.blocksSent} + data received: ${stats.dataReceived} + data sent: ${stats.dataSent} + dup blocks received: ${stats.dupBlksReceived} + dup data received: ${stats.dupDataReceived} + wantlist ${stats.wantlist} + partners ${stats.peers}`) })()) } } diff --git a/src/core/components/bitswap.js b/src/core/components/bitswap.js index 654f9f045b..2a9db3b1a2 100644 --- a/src/core/components/bitswap.js +++ b/src/core/components/bitswap.js @@ -1,8 +1,8 @@ 'use strict' const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR +const prettyBytes = require('pretty-bytes') const callbackify = require('callbackify') -const Big = require('bignumber.js') const CID = require('cids') const PeerId = require('peer-id') const errCode = require('err-code') @@ -31,23 +31,50 @@ module.exports = function bitswap (self) { return { Keys: formatWantlist(list) } }), - stat: callbackify(async () => { // eslint-disable-line require-await + stat: callbackify(async (options = {}) => { // eslint-disable-line require-await if (!self.isOnline()) { throw new Error(OFFLINE_ERROR) } - const snapshot = self._bitswap.stat().snapshot + const { human } = options + const { + providesBufferLength, + blocksReceived, + dupBlksReceived, + dupDataReceived, + dataReceived, + blocksSent, + dataSent + } = self._bitswap.stat().snapshot return { - provideBufLen: parseInt(snapshot.providesBufferLength.toString()), - blocksReceived: new Big(snapshot.blocksReceived), - wantlist: formatWantlist(self._bitswap.getWantlist()), - peers: self._bitswap.peers().map((id) => id.toB58String()), - dupBlksReceived: new Big(snapshot.dupBlksReceived), - dupDataReceived: new Big(snapshot.dupDataReceived), - dataReceived: new Big(snapshot.dataReceived), - blocksSent: new Big(snapshot.blocksSent), - dataSent: new Big(snapshot.dataSent) + provideBufLen: human + ? providesBufferLength.toNumber() + : providesBufferLength, + blocksReceived: human + ? blocksReceived.toNumber() + : blocksReceived, + wantlist: human + ? `[${Array.from(self._bitswap.getWantlist()).length} keys]` + : formatWantlist(self._bitswap.getWantlist()), + peers: human + ? `[${self._bitswap.peers().length}]` + : self._bitswap.peers().map((id) => id.toB58String()), + dupBlksReceived: human + ? dupBlksReceived.toNumber() + : dupBlksReceived, + dupDataReceived: human + ? prettyBytes(dupDataReceived.toNumber()).toUpperCase() + : dupDataReceived, + dataReceived: human + ? prettyBytes(dataReceived.toNumber()).toUpperCase() + : dataReceived, + blocksSent: human + ? blocksSent.toNumber() + : blocksSent, + dataSent: human + ? prettyBytes(dataSent.toNumber()).toUpperCase() + : dataSent } }), diff --git a/src/http/api/resources/bitswap.js b/src/http/api/resources/bitswap.js index 0a8d9debf1..b294cb0632 100644 --- a/src/http/api/resources/bitswap.js +++ b/src/http/api/resources/bitswap.js @@ -30,19 +30,23 @@ exports.wantlist = { exports.stat = { validate: { query: Joi.object().keys({ - 'cid-base': Joi.string().valid(...multibase.names) + 'cid-base': Joi.string().valid(...multibase.names), + human: Joi.boolean().default(false) }).unknown() }, async handler (request, h) { const { ipfs } = request.server.app const cidBase = request.query['cid-base'] + const human = request.query.human - const stats = await ipfs.bitswap.stat() + const stats = await ipfs.bitswap.stat({ human }) - stats.wantlist = stats.wantlist.map(k => ({ - '/': cidToString(k['/'], { base: cidBase, upgrade: false }) - })) + if (!human) { + stats.wantlist = stats.wantlist.map(k => ({ + '/': cidToString(k['/'], { base: cidBase, upgrade: false }) + })) + } return h.response({ ProvideBufLen: stats.provideBufLen, diff --git a/test/cli/bitswap.js b/test/cli/bitswap.js index c22cefe81c..4df65d5ea7 100644 --- a/test/cli/bitswap.js +++ b/test/cli/bitswap.js @@ -67,17 +67,36 @@ describe('bitswap', () => runOn((thing) => { this.timeout(20 * 1000) const out = await ipfs('bitswap stat') - expect(out).to.include([ - 'bitswap status', - ' blocks received: 0', - ' dup blocks received: 0', - ' dup data received: 0B', - // We sometimes pick up partners while the tests run and the order of - // wanted keys is not defined so our assertion ends here. - ' wantlist [2 keys]' - ].join('\n')) + + expect(out).to.include('bitswap status') + expect(out).to.match(/provides buffer:\s\d+$/gm) + expect(out).to.match(/blocks received:\s\d+$/gm) + expect(out).to.match(/blocks sent:\s\d+$/gm) + expect(out).to.match(/data received:\s\d+$/gm) + expect(out).to.match(/data sent:\s\d+$/gm) + expect(out).to.match(/dup blocks received:\s\d+$/gm) + expect(out).to.match(/dup data received:\s\d+$/gm) + expect(out).to.match(/wantlist\s\[\d+\skeys\]$/gm) expect(out).to.include(key0) expect(out).to.include(key1) + expect(out).to.match(/partners\s\[\d+\]$/gm) + }) + + it('human readable stats', async () => { + const out = await ipfs('bitswap stat --human') + + expect(out).to.include('bitswap status') + expect(out).to.match(/provides buffer:\s\d+$/gm) + expect(out).to.match(/blocks received:\s\d+$/gm) + expect(out).to.match(/blocks sent:\s\d+$/gm) + expect(out).to.match(/data received:\s+[\d.]+\s[PTGMK]?B$/gm) + expect(out).to.match(/data sent:\s+[\d.]+\s[PTGMK]?B$/gm) + expect(out).to.match(/dup blocks received:\s\d+$/gm) + expect(out).to.match(/dup data received:\s+[\d.]+\s[PTGMK]?B$/gm) + expect(out).to.match(/wantlist\s\[\d+\skeys\]$/gm) + expect(out).to.not.include(key0) + expect(out).to.not.include(key1) + expect(out).to.match(/partners\s\[\d+\]$/gm) }) it('should get stats with wantlist CIDs encoded in specified base', async function () {