Skip to content

Commit 753dfa7

Browse files
committed
feat: implement .stat function
1 parent fc4cfb3 commit 753dfa7

File tree

6 files changed

+158
-2
lines changed

6 files changed

+158
-2
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,20 @@ Sets the API address.
282282

283283
* `value` should be a [Multiaddr](https://github.com/multiformats/js-multiaddr) or a String representing a valid one.
284284

285+
### `repo.stat ([options], callback)`
286+
287+
Gets the repo status.
288+
289+
`options` is an object which might contain the key `human`, which is a boolean indicating whether or not the `repoSize` should be displayed in MiB or not.
290+
291+
`callback` is a function with the signature `function (err, stats)`, where `stats` is an Object with the following keys:
292+
293+
- `numObjects`
294+
- `repoPath`
295+
- `repoSize`
296+
- `version`
297+
- `storageMax`
298+
285299
## Notes
286300

287301
- [Explanation of how repo is structured](https://github.com/ipfs/js-ipfs-repo/pull/111#issuecomment-279948247)

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,22 @@
5656
"dependencies": {
5757
"async": "^2.6.0",
5858
"base32.js": "~0.1.0",
59+
"big.js": "^5.0.3",
5960
"cids": "~0.5.2",
60-
"interface-datastore": "~0.4.2",
6161
"datastore-core": "~0.4.0",
6262
"datastore-fs": "~0.4.2",
6363
"datastore-level": "~0.7.0",
6464
"debug": "^3.1.0",
65+
"interface-datastore": "~0.4.2",
6566
"ipfs-block": "~0.6.1",
6667
"level-js": "timkuijsten/level.js#idbunwrapper",
6768
"leveldown": "^1.7.2",
6869
"lock-me": "^1.0.3",
6970
"lodash.get": "^4.4.2",
7071
"lodash.has": "^4.5.2",
7172
"lodash.set": "^4.3.2",
72-
"multiaddr": "^3.0.1"
73+
"multiaddr": "^3.0.1",
74+
"pull-stream": "^3.6.1"
7375
},
7476
"license": "MIT",
7577
"contributors": [

src/blockstore.js

+14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const Block = require('ipfs-block')
88
const setImmediate = require('async/setImmediate')
99
const reject = require('async/reject')
1010
const CID = require('cids')
11+
const pull = require('pull-stream')
1112

1213
/**
1314
* Transform a raw buffer to a base32 encoded key.
@@ -49,6 +50,19 @@ function maybeWithSharding (filestore, options, callback) {
4950

5051
function createBaseStore (store) {
5152
return {
53+
/**
54+
* Query the store.
55+
*
56+
* @param {object} query
57+
* @param {function(Error, Array)} callback
58+
* @return {void}
59+
*/
60+
query (query, callback) {
61+
pull(
62+
store.query(query),
63+
pull.collect(callback)
64+
)
65+
},
5266
/**
5367
* Get a single block by CID.
5468
*

src/index.js

+79
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ const each = require('async/each')
77
const assert = require('assert')
88
const path = require('path')
99
const debug = require('debug')
10+
const Big = require('big.js')
11+
const pull = require('pull-stream')
1012

1113
const backends = require('./backends')
1214
const version = require('./version')
@@ -17,6 +19,8 @@ const defaultOptions = require('./default-options')
1719

1820
const log = debug('repo')
1921

22+
const noLimit = Number.MAX_SAFE_INTEGER
23+
2024
const lockers = {
2125
memory: require('./lock-memory'),
2226
fs: require('./lock')
@@ -200,6 +204,81 @@ class IpfsRepo {
200204
exists (callback) {
201205
this.version.exists(callback)
202206
}
207+
208+
/**
209+
* Get repo status.
210+
*
211+
* @param {Object} options
212+
* @param {Boolean} options.human
213+
* @param {function(Error, Object)} callback
214+
* @return {void}
215+
*/
216+
stat (options, callback) {
217+
if (typeof options === 'function') {
218+
callback = options
219+
options = {}
220+
}
221+
222+
options = Object.assign({}, {human: false}, options)
223+
224+
parallel([
225+
(cb) => this.config.get('Datastore.StorageMax', (err, max) => {
226+
if (err) {
227+
cb(null, new Big(noLimit))
228+
} else {
229+
cb(null, new Big(max))
230+
}
231+
}),
232+
(cb) => this.version.get(cb),
233+
(cb) => this.blocks.query({}, (err, list) => {
234+
list = list || []
235+
236+
const count = new Big(list.length)
237+
let size = new Big(0)
238+
239+
list.forEach(block => {
240+
size = size
241+
.plus(block.value.byteLength)
242+
.plus(block.key._buf.byteLength)
243+
})
244+
245+
cb(err, {
246+
count: count,
247+
size: size
248+
})
249+
}),
250+
(cb) => getSize(this.datastore, cb),
251+
(cb) => getSize(this.keys, cb)
252+
], (err, results) => {
253+
if (err) return callback(err)
254+
255+
let size = results[2].size
256+
.plus(results[3])
257+
.plus(results[4])
258+
259+
if (options.human) {
260+
size = size.div(1048576)
261+
}
262+
263+
callback(null, {
264+
repoPath: this.path,
265+
storageMax: results[0],
266+
version: results[1],
267+
numObjects: results[2].count,
268+
repoSize: size
269+
})
270+
})
271+
}
272+
}
273+
274+
function getSize (queryFn, callback) {
275+
pull(
276+
queryFn.query({}),
277+
pull.reduce((sum, block) => {
278+
return sum
279+
.plus(block.value.byteLength)
280+
.plus(block.key._buf.byteLength)
281+
}, new Big(0), callback))
203282
}
204283

205284
module.exports = IpfsRepo

test/node.js

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ describe('IPFS Repo Tests onNode.js', () => {
6161
require('./blockstore-test')(repo)
6262
require('./datastore-test')(repo)
6363
require('./keystore-test')(repo)
64+
require('./stat-test')(repo)
6465
if (!r.init) {
6566
require('./interop-test')(repo)
6667
}

test/stat-test.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/* eslint-env mocha */
2+
'use strict'
3+
4+
const chai = require('chai')
5+
chai.use(require('dirty-chai'))
6+
const expect = chai.expect
7+
8+
module.exports = (repo) => {
9+
describe('stat', () => {
10+
it('get stats', (done) => {
11+
repo.stat((err, stats) => {
12+
expect(err).to.not.exist()
13+
expect(stats).to.exist()
14+
expect(stats).to.have.property('numObjects')
15+
expect(stats).to.have.property('version')
16+
expect(stats).to.have.property('repoPath')
17+
expect(stats).to.have.property('repoSize')
18+
expect(stats).to.have.property('storageMax')
19+
20+
expect(stats.numObjects > '0').to.eql(true)
21+
expect(stats.version > '0').to.eql(true)
22+
expect(stats.repoSize > '0').to.eql(true)
23+
expect(stats.storageMax > '0').to.eql(true)
24+
done()
25+
})
26+
})
27+
28+
it('get human stats', (done) => {
29+
repo.stat({human: true}, (err, stats) => {
30+
expect(err).to.not.exist()
31+
expect(stats).to.exist()
32+
expect(stats).to.have.property('numObjects')
33+
expect(stats).to.have.property('version')
34+
expect(stats).to.have.property('repoPath')
35+
expect(stats).to.have.property('repoSize')
36+
expect(stats).to.have.property('storageMax')
37+
38+
expect(stats.numObjects > '0').to.eql(true)
39+
expect(stats.version > '0').to.eql(true)
40+
expect(stats.repoSize > '0').to.eql(true)
41+
expect(stats.storageMax > '0').to.eql(true)
42+
done()
43+
})
44+
})
45+
})
46+
}

0 commit comments

Comments
 (0)