Skip to content

Commit 8732da6

Browse files
committed
feat: implement .stat function
1 parent fc4cfb3 commit 8732da6

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-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

+85
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,87 @@ 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) => cb(null, this.path),
226+
(cb) => this.config.get('Datastore.StorageMax', (err, max) => {
227+
if (err) {
228+
cb(null, new Big(noLimit))
229+
} else {
230+
cb(null, new Big(max))
231+
}
232+
}),
233+
(cb) => this.version.get(cb),
234+
(cb) => waterfall([
235+
(cb) => cb(null, {
236+
repoSize: new Big(0)
237+
}),
238+
(stats, cb) => this.blocks.query({}, (err, list) => {
239+
list = list || []
240+
stats.numObjects = new Big(list.length)
241+
242+
list.forEach(block => {
243+
stats.repoSize = stats.repoSize
244+
.plus(block.value.byteLength)
245+
.plus(block.key._buf.byteLength)
246+
})
247+
248+
cb(err, stats)
249+
}),
250+
(stats, cb) => getSize(this.datastore, (err, size) => {
251+
stats.repoSize = stats.repoSize.plus(size)
252+
cb(err, stats)
253+
}),
254+
(stats, cb) => getSize(this.keys, (err, size) => {
255+
stats.repoSize = stats.repoSize.plus(size)
256+
cb(err, stats)
257+
}),
258+
(stats, cb) => {
259+
if (options.human) {
260+
stats.repoSize = stats.repoSize.div(1048576)
261+
}
262+
263+
cb(null, stats)
264+
}
265+
], cb)
266+
], (err, results) => {
267+
if (err) return callback(err)
268+
269+
callback(null, {
270+
repoPath: results[0],
271+
storageMax: results[1],
272+
version: results[2],
273+
repoSize: results[3].repoSize,
274+
numObjects: results[3].numObjects
275+
})
276+
})
277+
}
278+
}
279+
280+
function getSize (queryFn, callback) {
281+
pull(
282+
queryFn.query({}),
283+
pull.reduce((sum, block) => {
284+
return sum
285+
.plus(block.value.byteLength)
286+
.plus(block.key._buf.byteLength)
287+
}, new Big(0), callback))
203288
}
204289

205290
module.exports = IpfsRepo

test/repo-test.js

+28
Original file line numberDiff line numberDiff line change
@@ -99,4 +99,32 @@ module.exports = (repo) => {
9999
})
100100
})
101101
})
102+
103+
describe('stat', () => {
104+
it('get stats', (done) => {
105+
repo.stat((err, stats) => {
106+
expect(err).to.not.exist()
107+
expect(stats).to.exist()
108+
expect(stats).to.have.property('numObjects')
109+
expect(stats).to.have.property('version')
110+
expect(stats).to.have.property('repoPath')
111+
expect(stats).to.have.property('repoSize')
112+
expect(stats).to.have.property('storageMax')
113+
done()
114+
})
115+
})
116+
117+
it('get human stats', (done) => {
118+
repo.stat({human: true}, (err, stats) => {
119+
expect(err).to.not.exist()
120+
expect(stats).to.exist()
121+
expect(stats).to.have.property('numObjects')
122+
expect(stats).to.have.property('version')
123+
expect(stats).to.have.property('repoPath')
124+
expect(stats).to.have.property('repoSize')
125+
expect(stats).to.have.property('storageMax')
126+
done()
127+
})
128+
})
129+
})
102130
}

0 commit comments

Comments
 (0)