Skip to content
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

Merged
merged 27 commits into from
Jul 4, 2017
Merged

API revamp and cleansing #140

merged 27 commits into from
Jul 4, 2017

Conversation

pgte
Copy link
Contributor

@pgte pgte commented Jun 29, 2017

Fixes #139

@Kubuxu Kubuxu added the status/in-progress In progress label Jun 29, 2017
@pgte pgte changed the title API revamp and cleansing WIP: API revamp and cleansing Jun 29, 2017
@pgte pgte changed the title WIP: API revamp and cleansing API revamp and cleansing Jun 29, 2017
Copy link
Member

@daviddias daviddias left a 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`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

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.

Copy link
Member

@daviddias daviddias Jul 3, 2017

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?

Copy link
Contributor Author

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.

Copy link
Member

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..

Copy link
Contributor Author

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.
Copy link
Member

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

Copy link
Contributor Author

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())
})
},
Copy link
Member

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()))
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

},
blocks: {
sharding: true
}
Copy link
Member

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
Copy link
Member

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,
Copy link
Member

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)

Copy link
Contributor Author

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?

Copy link
Member

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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)
},
Copy link
Member

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?

Copy link
Contributor Author

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].

Copy link
Member

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

Copy link
Member

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"

Copy link
Contributor Author

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)`

Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

@daviddias daviddias left a 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
Copy link
Member

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

Copy link
Contributor Author

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

Copy link
Member

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')

Copy link
Contributor Author

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')
})
})
``
Copy link
Member

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)
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@daviddias
Copy link
Member

@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) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be .get

Copy link
Contributor Author

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
Copy link
Member

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?

Copy link
Contributor Author

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..

Copy link
Contributor

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.

Copy link
Member

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.

Copy link
Member

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

Copy link
Member

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)
Copy link
Member

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

Copy link
Contributor Author

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'))
Copy link
Member

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)
Copy link
Member

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'))

Copy link
Contributor

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.

if (err) {
callback(err)
return // early
}
Copy link
Contributor

@justinmchase justinmchase Jul 2, 2017

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)

Copy link
Member

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 ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ {}

Copy link
Member

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'
}
}
Copy link
Contributor

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')
Copy link
Contributor

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.

Copy link
Member

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

@pgte
Copy link
Contributor Author

pgte commented Jul 3, 2017

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. :)

@daviddias daviddias requested a review from dignifiedquire July 3, 2017 19:11
Copy link
Member

@daviddias daviddias left a 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`)
Copy link
Member

@daviddias daviddias Jul 3, 2017

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)`.
Copy link
Member

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)
Copy link
Member

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
Copy link
Member

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

})
})
```

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extra \n

Copy link
Contributor Author

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pgte
Copy link
Contributor Author

pgte commented Jul 4, 2017

@diasdavid listed dependents in awesome endeavour PR: ipfs/js-ipfs#887

@pgte
Copy link
Contributor Author

pgte commented Jul 4, 2017

@diasdavid 85a2810 and c5695ed test this against a repo generated by go-ipfs v0.4.10.

@daviddias daviddias merged commit 0208d60 into master Jul 4, 2017
@daviddias daviddias removed the status/in-progress In progress label Jul 4, 2017
@daviddias daviddias deleted the feat/api-cleansing branch July 4, 2017 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants