-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
API revamp and cleansing #140
Changes from 12 commits
872284b
929695b
5bf8ad4
6029487
85380a5
1c877fa
13499cd
210e494
8904d7a
7c59443
87a40b1
41b021e
424d0d8
77d1e43
bb6dccd
90ae830
25bab69
1cf93ab
bf82528
174fff0
8e8055d
40791c5
a156241
a9293e2
85a2810
c5695ed
bda0e7f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -137,7 +137,142 @@ This now has created the following structure, either on disk or as an in memory | |
|
||
## API | ||
|
||
See https://ipfs.github.io/js-ipfs-repo | ||
### Setup | ||
|
||
#### new Repo(path[, options]) | ||
|
||
Creates an IPFS Repo. | ||
|
||
Arguments: | ||
|
||
* `path` (string, mandatory): the path for this repo | ||
* `options` (object, optional): may contain the following values | ||
* `lock` (string, defaults to `"fs"` in Node.js, `"memory"` in the browser): what type of lock to use. Lock has to be acquired when opening. | ||
* `storageBackends` (object, optional): may contain the following values, which should each be a class implementing the [datastore interface](https://github.com/ipfs/interface-datastore#readme): | ||
* `root` (defaults to [`datastore-fs`](https://github.com/ipfs/js-datastore-fs#readme) in Node.js and [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme) in the browser) | ||
* `blocks` (defaults to [`datastore-fs`](https://github.com/ipfs/js-datastore-fs#readme) in Node.js and [`datastore-level`](https://github.com/ipfs/js-datastore-level#readme) in the browser) | ||
* `datastore` (defaults to `datastore-level`) | ||
|
||
```js | ||
const repo = new Repo('path/to/repo') | ||
``` | ||
|
||
#### repo.init (callback) | ||
|
||
Creates the necesary folder structure inside the repo. | ||
|
||
#### repo.open (callback) | ||
|
||
Locks the repo. | ||
|
||
#### repo.close (callback) | ||
|
||
Unlocks the repo. | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's break the API description into 3 sets:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
#### repo.exists (callback) | ||
|
||
Tells whether this repo exists or not. Callsback with `(err, bool)`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing space |
||
|
||
### Repos | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's add a line here saying "root repo" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
#### repo.put (key, value:Buffer, callback) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unnecessary spaces. Also, can we put these between ``, helps readability on the readme. |
||
|
||
Put a value at the root of the repo. | ||
|
||
* `key` can be a buffer, a string or a [Key](https://github.com/ipfs/interface-datastore#keys). | ||
|
||
#### repo.get (key, callback) | ||
|
||
Get a value at the root of the repo. | ||
|
||
* `key` can be a buffer, a string or a [Key](https://github.com/ipfs/interface-datastore#keys). | ||
* `callback` is a callback function `function (err, result:Buffer)` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's add a line here saying "blocks/blockstore" and link it to the ipfs-block class There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
#### repo.blocks.put (block:Block, callback) | ||
|
||
* `block` should be of type [Block](https://github.com/ipfs/js-ipfs-block#readme). | ||
|
||
#### repo.blocks.putMany (blocks, callback) | ||
|
||
Put many blocks block. | ||
|
||
* `block` should be an array of type [Block](https://github.com/ipfs/js-ipfs-block#readme). | ||
|
||
#### repo.blocks.get (cid, callback) | ||
|
||
Get block. | ||
|
||
* `cid` is the content id of [type CID](https://github.com/ipld/js-cid#readme). | ||
* `callback` is a callback function `function (err, result:Buffer)` | ||
|
||
#### repo.datastore | ||
|
||
This is contains a full implementation of [the `interface-datastore` API](https://github.com/ipfs/interface-datastore#api). | ||
|
||
|
||
### Convenience | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
#### repo.config | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explain why using repo.config is better than repo.set('config') There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
##### repo.config.set(key:string, value, callback) | ||
|
||
Set a config value. `value` can be any object that is serializable to JSON. | ||
|
||
* `key` is a string specifying the object path. Example: | ||
|
||
```js | ||
repo.config.set('a.b.c', 'c value', (err) => { | ||
if (err) throw err | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please use |
||
repo.config.get((err, config) => { | ||
if (err) throw err | ||
assert.equal(config.a.b.c, 'c value') | ||
}) | ||
}) | ||
`` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing ` |
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extra There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
|
||
##### repo.config.set(value, callback) | ||
|
||
Set the whole config value. `value` can be any object that is serializable to JSON. | ||
|
||
##### repo.config.get(key:string, callback) | ||
|
||
Get a config value. `callback` is a function with the signature: `function (err, value)`, wehre the ` | ||
value` is of the same type that was set before. | ||
|
||
* `key` is a string specifying the object path. Example: | ||
|
||
```js | ||
repo.config.set('a.b.c', (err, value) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good catch, fixed |
||
if (err) throw err | ||
console.log('config.a.b.c = ', value) | ||
}) | ||
``` | ||
|
||
##### repo.config.get(callback) | ||
|
||
Get the entire config value. `callback` is a function with the signature: `function (err, configValue:Object)`. | ||
|
||
#### repo.version | ||
|
||
##### repo.version.get (callback) | ||
|
||
Gets the repo version. | ||
|
||
##### repo.version.set (version:number, callback) | ||
|
||
Sets the repo version | ||
|
||
#### repo.apiAddr | ||
|
||
#### repo.apiAddr.get (callback) | ||
|
||
Gets the API address. | ||
|
||
#### repo.apiAddr.set (value:string, callback) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should take a String or multiaddr, but should always be a valid multiaddr There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
|
||
Sets the API address. | ||
|
||
|
||
## Notes | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,9 @@ | |
"level-js": "timkuijsten/level.js#idbunwrapper", | ||
"leveldown": "^1.7.2", | ||
"lock-me": "^1.0.2", | ||
"lodash.get": "^4.4.2", | ||
"lodash.has": "^4.5.2", | ||
"lodash.set": "^4.3.2", | ||
"multiaddr": "^2.3.0", | ||
"safe-buffer": "^5.1.1" | ||
}, | ||
|
@@ -85,4 +88,4 @@ | |
"nginnever <[email protected]>", | ||
"npmcdn-to-unpkg-bot <[email protected]>" | ||
] | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
'use strict' | ||
|
||
const Key = require('interface-datastore').Key | ||
|
||
const apiFile = new Key('api') | ||
|
||
module.exports = (store) => { | ||
return { | ||
/** | ||
* Get the current configuration from the repo. | ||
* | ||
* @param {function(Error, Object)} callback | ||
* @returns {void} | ||
*/ | ||
get (callback) { | ||
store.get(apiFile, (err, value) => callback(err, value && value.toString())) | ||
}, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since you are doing the check for value, this method can be simplified to:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
/** | ||
* Set the current configuration for this repo. | ||
* | ||
* @param {Object} value - the api address to be written | ||
* @param {function(Error)} callback | ||
* @returns {void} | ||
*/ | ||
set (value, callback) { | ||
store.put(apiFile, Buffer.from(value.toString()), callback) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fixed |
||
}, | ||
/** | ||
* Deletes api file | ||
* | ||
* @param {function(Error, bool)} callback | ||
* @returns {void} | ||
*/ | ||
delete (callback) { | ||
store.delete(apiFile, callback) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict' | ||
|
||
exports.create = function createBackend (name, path, options) { | ||
const Ctor = options.storageBackends[name] | ||
const backendOptions = Object.assign({}, options.storageBackendOptions[name] || {}) | ||
return new Ctor(path, backendOptions) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,14 @@ | ||
'use strict' | ||
|
||
const NamespaceStore = require('datastore-core').NamespaceDatastore | ||
const core = require('datastore-core') | ||
const ShardingStore = core.ShardingDatastore | ||
const Key = require('interface-datastore').Key | ||
const base32 = require('base32.js') | ||
const Block = require('ipfs-block') | ||
const setImmediate = require('async/setImmediate') | ||
const reject = require('async/reject') | ||
const CID = require('cids') | ||
|
||
const blockPrefix = new Key('blocks') | ||
|
||
/** | ||
* Transform a raw buffer to a base32 encoded key. | ||
* | ||
|
@@ -31,8 +30,27 @@ const cidToDsKey = (cid) => { | |
return keyFromBuffer(cid.buffer) | ||
} | ||
|
||
module.exports = (repo) => { | ||
const store = new NamespaceStore(repo.store, blockPrefix) | ||
module.exports = (filestore, options, callback) => { | ||
maybeWithSharding(filestore, options, (err, store) => { | ||
if (err) { | ||
callback(err) | ||
return // early | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section can be a single line, which standard will allow: if (err) return callback(err) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but our linting rules do not, right @diasdavid ;) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❤️ {} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not against to |
||
|
||
callback(null, createBaseStore(store)) | ||
}) | ||
} | ||
|
||
function maybeWithSharding (filestore, options, callback) { | ||
if (options.sharding) { | ||
const shard = new core.shard.NextToLast(2) | ||
ShardingStore.createOrOpen(filestore, shard, callback) | ||
} else { | ||
setImmediate(() => callback(null, filestore)) | ||
} | ||
} | ||
|
||
function createBaseStore (store) { | ||
return { | ||
/** | ||
* Get a single block by CID. | ||
|
@@ -134,6 +152,10 @@ module.exports = (repo) => { | |
} | ||
|
||
store.delete(cidToDsKey(cid), callback) | ||
}, | ||
|
||
close (callback) { | ||
store.close(callback) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,44 +1,69 @@ | ||
'use strict' | ||
|
||
const Key = require('interface-datastore').Key | ||
const queue = require('async/queue') | ||
const waterfall = require('async/waterfall') | ||
const _get = require('lodash.get') | ||
const _set = require('lodash.set') | ||
const _has = require('lodash.has') | ||
|
||
const configKey = new Key('config') | ||
|
||
module.exports = (store) => { | ||
return { | ||
const setQueue = queue(_doSet, 1) | ||
|
||
const configStore = { | ||
/** | ||
* Get the current configuration from the repo. | ||
* | ||
* @param {String} key - the config key to get | ||
* @param {function(Error, Object)} callback | ||
* @returns {void} | ||
*/ | ||
get (callback) { | ||
store.get(configKey, (err, value) => { | ||
get (key, callback) { | ||
if (typeof key === 'function') { | ||
callback = key | ||
key = undefined | ||
} | ||
store.get(configKey, (err, encodedValue) => { | ||
if (err) { | ||
return callback(err) | ||
} | ||
|
||
let config | ||
try { | ||
config = JSON.parse(value.toString()) | ||
config = JSON.parse(encodedValue.toString()) | ||
} catch (err) { | ||
return callback(err) | ||
} | ||
callback(null, config) | ||
if (key !== undefined && !_has(config, key)) { | ||
callback(new Error('Key does not exist in config')) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be nice to say which key doesn't exist, i.e. |
||
return // early | ||
} | ||
let value = key !== undefined ? _get(config, key) : config | ||
callback(null, value) | ||
}) | ||
}, | ||
/** | ||
* Set the current configuration for this repo. | ||
* | ||
* @param {Object} config - the config object to be written | ||
* @param {String} key - the config key to be written | ||
* @param {Object} value - the config value to be written | ||
* @param {function(Error)} callback | ||
* @returns {void} | ||
*/ | ||
set (config, callback) { | ||
const buf = new Buffer(JSON.stringify(config, null, 2)) | ||
|
||
store.put(configKey, buf, callback) | ||
set (key, value, callback) { | ||
if (typeof value === 'function') { | ||
callback = value | ||
value = key | ||
key = undefined | ||
} | ||
setQueue.push({ | ||
key: key, | ||
value: value | ||
}, callback) | ||
}, | ||
|
||
/** | ||
* Check if a config file exists. | ||
* | ||
|
@@ -49,4 +74,27 @@ module.exports = (store) => { | |
store.has(configKey, callback) | ||
} | ||
} | ||
|
||
return configStore | ||
|
||
function _doSet (m, callback) { | ||
const key = m.key | ||
const value = m.value | ||
if (key) { | ||
waterfall( | ||
[ | ||
(cb) => configStore.get(cb), | ||
(config, cb) => cb(null, _set(config, key, value)), | ||
_saveAll | ||
], | ||
callback) | ||
} else { | ||
_saveAll(value, callback) | ||
} | ||
} | ||
|
||
function _saveAll (config, callback) { | ||
const buf = new Buffer(JSON.stringify(config, null, 2)) | ||
store.put(configKey, buf, callback) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have a brief description of what the role of each of these datastores are at a high level.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done