-
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
Conversation
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.
left some comments. Let's not forget the repo.exists
Thanks @pgte :):)
README.md
Outdated
* `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`) |
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.
- @pgte, could you add this brief description?
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
README.md
Outdated
### repo.close (callback) | ||
|
||
Unlocks the repo. | ||
|
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.
Let's break the API description into 3 sets:
- Set up - init, open, close and exists
- Repos - Explaining that there are two repos
- Utility/Convinience - apiAddr, config, version..
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.
README.md
Outdated
|
||
### 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. |
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.
Currently, the 'replace a key' is being done inside js-ipfs - https://github.com/ipfs/js-ipfs/blob/master/src/core/components/config.js#L10-L55
I like that it is being exposed here, avoids duplication of code if any other module needs to do the same. Let's make sure that once this is done we update js-ipfs to just call the methods directly
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.
src/api-addr.js
Outdated
|
||
callback(err, value && value.toString()) | ||
}) | ||
}, |
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.
since you are doing the check for value, this method can be simplified to:
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 comment
The reason will be displayed to describe this comment to others. Learn more.
done
src/default-options.js
Outdated
}, | ||
blocks: { | ||
sharding: true | ||
} |
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's missing the extension .data
src/index.js
Outdated
@@ -97,60 +75,54 @@ class IpfsRepo { | |||
*/ | |||
open (callback) { | |||
if (!this.closed) { | |||
return callback(new Error('repo is already open')) | |||
callback(new Error('repo is already open')) | |||
return // early |
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.
setImmediate the callback
src/index.js
Outdated
const blocksBaseStore = backends.create('blocks', path.join(this.path, 'blocks'), this.options) | ||
blockstore( | ||
blocksBaseStore, | ||
this.datastore, |
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.
Let's reference to this.datastore
as this.rootDatastore
(or a name that suggests that it is the root of all mount points, maybe add this as a comment)
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.
You mean change this.datastore
to this.rootDatastore
in the public API, add an alias or simply add a comment?
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.
ah, wait.
this.datastore is /datastore? If so, why does /blocks need it?
if this.datastore is just /, then it makes sense to call it rootDatastore
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.
Ah, it's legacy, it used to need it but now doesn't. Good catch, removing it.
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.
removed
{ | ||
config: (cb) => this.config.exists(cb), | ||
version: (cb) => this.version.check(repoVersion, cb) | ||
}, |
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.
Interesting, why making this an object?
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.
Just aesthetics: I prefer to refer to result.config
rather than result[0]
.
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.
nice. That I didn't know :)
README.md
Outdated
Tells whether this repo exists or not. Callsback with `(err, bool)`. | ||
|
||
### Repos | ||
|
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.
let's add a line here saying "root repo"
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
|
||
* `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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
done
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.
🎉🎉🎉🎉🎉🎉 Thank you @pgte, this module is getting so much better structured, really like the new way things are mounted.
Could you be extra rigorous with interop testing and by this I mean:
- get the latest go-ipfs
- init a clean repo
- add 3 objects
- add a couple of files
- keep all of those hashes
- bring that new repo to the test folder
- Make sure you can read all that data
- Do the same for some DHT records and or pinroot set hash (that gets stored in the datastore level)
README.md
Outdated
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this utils
? They are convenience methods but typically these are listed as utils
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
README.md
Outdated
### Convenience | ||
|
||
#### repo.config | ||
|
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.
Explain why using repo.config is better than repo.set('config')
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
README.md
Outdated
assert.equal(config.a.b.c, 'c value') | ||
}) | ||
}) | ||
`` |
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.
missing `
README.md
Outdated
|
||
Gets the API address. | ||
|
||
#### repo.apiAddr.set (value:string, 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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
done
@justinmchase I believe you are going to like the results of this PR as it will make way more obvious and testable that S3 backend you are looking for :) |
README.md
Outdated
* `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 comment
The reason will be displayed to describe this comment to others. Learn more.
Should be .get
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.
good catch, fixed
src/index.js
Outdated
} | ||
function ignoringAlreadyOpened (cb) { | ||
return (_err) => { | ||
let err = _err |
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.
Not 100% I understand this type of assignment, why not name it directly err
and just use that?
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.
The only reason is that I think that assigning to an argument is a bad practise..
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.
A couple things here, its fairly standard to have a code property on an error in addition to message for this sort of situation (e.g. fs.stats documentation).
Also, the parameter should be called error for convention purposes, standard will do some enforcement around variables of that name specifically as well.
I would probably write this as:
function ignoringAlreadyOpened (cb) {
return (err) => err && err.code === 'AOPEN' ? callback() : callback(err)
}
This would imply you are adding the code 'AOPEN'
too of course. You don't want to really assume the error message is going to be English.
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.
We currently don't have unified error handling on the datastore interfaces. These errors come directly from them which is why have to make string matching right now. I agree it would be better to have subclasses of Error
+ error codes for checking these but these need to be implemented first in all the datastores.
README.md
Outdated
Sets the API address. | ||
|
||
* `value` should be a [Multiaddr](https://github.com/multiformats/js-multiaddr) or a String representing a valid one. | ||
|
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.
seems to be missing exists
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.
* @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 comment
The reason will be displayed to describe this comment to others. Learn more.
Buffer.from
is not available in node@4 you will need to include safe-buffer
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.
fixed
src/config.js
Outdated
} 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 comment
The reason will be displayed to describe this comment to others. Learn more.
would be nice to say which key doesn't exist, i.e.Key "foo" does not exist in config
src/index.js
Outdated
if (err && err.message.startsWith('ENOENT')) { | ||
err = null | ||
} | ||
cb(err) |
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.
These to ignore calls could share some code, sth like this
const ignoreIf = (cond) => (cb) => (err) => {
cb(err && !cond(err) ? err : null)
}
const ingoreNotFound = ignoreIf((err) => err.message.startsWith('ENOENT'))
const ignoreAlreadyOpen = ignoreIf((err) => err.message === 'Already open'))
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.
Same with this, you should probably have error codes on these.
src/blockstore.js
Outdated
if (err) { | ||
callback(err) | ||
return // early | ||
} |
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.
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 comment
The 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 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.
I'm not against to if (err) { return callback(err) }
if the goal is to save a couple of lines.
sharding: true, | ||
extension: '.data' | ||
} | ||
} |
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.
👍
const levelDirectory = 'datastore' | ||
const lockers = { | ||
memory: require('./lock-memory'), | ||
fs: require('./lock') |
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.
Shouldn't the locks also be a datastore? What if you are running on an ephemeral server and it goes down and back up, would the locks need to be preserved or is it ok that they are lost when the server is replaced? For example if your server was a Docker container and you update the instance.
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.
Lock can't be a simple datastore as it uses os specific system calls on the filesystem. Though the memory lock could use something else as backend if needed. It might be good to allow passing in ones own lock module if one wants to instead of using one of the specified
I think I've addressed every concern here. Please tell me if there's anything else I need to do to make this happen, as I depend on this. :) |
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.
Only minor comments for cosmetic changes.
Have you:
- tested with a fresh repo from go-ipfs 0.4.10?
- tested all the dependents that live inside the IPFS org? If yes, could you list them in
awesome endeavour
PR
README.md
Outdated
* `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`) |
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.
- @pgte, could you add this brief description?
README.md
Outdated
|
||
#### 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 comment
The reason will be displayed to describe this comment to others. Learn more.
Missing space
README.md
Outdated
|
||
Root repo: | ||
|
||
#### repo.put (key, value:Buffer, 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.
Unnecessary spaces.
Also, can we put these between ``, helps readability on the readme.
README.md
Outdated
|
||
```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 comment
The reason will be displayed to describe this comment to others. Learn more.
please use {}
, even if they are all in the same line so that it follows our agreed codestyle
}) | ||
}) | ||
``` | ||
|
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.
extra \n
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.
fixed
README.md
Outdated
Sets the API address. | ||
|
||
* `value` should be a [Multiaddr](https://github.com/multiformats/js-multiaddr) or a String representing a valid one. | ||
|
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.
@diasdavid listed dependents in awesome endeavour PR: ipfs/js-ipfs#887 |
@diasdavid 85a2810 and c5695ed test this against a repo generated by go-ipfs v0.4.10. |
Fixes #139