-
Notifications
You must be signed in to change notification settings - Fork 124
feat(breaking change): stats.bwReadableStream and stats.bwPullStream #211
Conversation
Needed for ipfs/js-ipfs#1198 /cc @diasdavid 😄 |
@hacdias this should be a argument to the function that changes if it just returns the values once or if you get a stream back, rather than just having one of them. The different signatures would be something like this:
or
|
Sure! Makes sense. Will change that @victorbjelkholm |
c9aedbf
to
17aebbf
Compare
@victorbjelkholm done 😄 |
SPEC/STATS.md
Outdated
`callback` must follow `function (err, stats) {}` signature, where `err` is an error if the operation was not successful. `stats` is an Object containing the following keys: | ||
If `poll` is `true`, then `callback` must follow `function (err, stream) {}` signature, where `err` is an error if the operation was not successful and `stream` is a Readable Stream where you can listen to the event `data` with a listener that must follow `function (stat) {}` signature. | ||
|
||
Otherwise, `callback` must follow `function (err, stat) {}` signature, where `err` is an error and `stat` is an Object containing the following keys: |
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 should define what the values are as well, I think the values are defined in bytes, but unsure.
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 stat
thing on the stream?
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.
If so, it is an object like the other one. That's why I left them with the same name and explained in the end.
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.
Yeah, that stat
object. We say which keys are on the object, but not what the values are.
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.
Problem is not understanding that stat
is used in both cases, but what the values are. Are they bytes? Are they kilobytes?
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'll add that!
js/src/stats.js
Outdated
expect(err).to.not.exist() | ||
expect(res).to.exist() | ||
|
||
res.once('data', (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.
We should have a way of closing the stream as well, for when you're done polling for stats
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.
@victorbjelkholm probably stream.destroy()
is our best shot
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.
Added res.destroy()
in the end.
js/src/stats.js
Outdated
expect(res).to.exist() | ||
|
||
res.once('data', (data) => { | ||
expect(data).to.have.a.property('totalIn') |
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 expectation only checks that the property exists, which I don't think is good enough. These test cases would still pass even if totalIn
is set to for example false
, undefined
or even null
, which is not correct.
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.
Noticed that the two test cases are the same as well. One should test with {poll: true}
and the other one without passing any extra args.
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 have 4 test cases: 2 for callbacks and two for promises. One of those two has {poll: true}
and the other has no args.
Right now, those values are strings. Should I convert them to something like big.js
?
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.
Added a try catch
to check if they are numbers using big.js.
js/src/stats.js
Outdated
done() | ||
}) | ||
}).catch(err => { | ||
expect(err).to.not.exist() |
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.
can just do .catch(done)
instead as done
with a error set will fail the test case
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 using Promises, you can remove the done
and just make sure that you return the promise. The way it is now you don't get any benefit from using the Promise syntax over Callbacks
js/src/stats.js
Outdated
done() | ||
}) | ||
}).catch(err => { | ||
expect(err).to.not.exist() |
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 using Promises, you can remove the done
and just make sure that you return the promise. The way it is now you don't get any benefit from using the Promise syntax over Callbacks
SPEC/STATS.md
Outdated
@@ -25,7 +25,11 @@ Where: | |||
- `poll` is used to print bandwidth at an interval. | |||
- `interval` is the time interval to wait between updating output, if `poll` is true. | |||
|
|||
`callback` must follow `function (err, stats) {}` signature, where `err` is an error if the operation was not successful. `stats` is an Object containing the following keys: | |||
If `poll` is `true`, then `callback` must follow `function (err, stream) {}` signature, where `err` is an error if the operation was not successful and `stream` is a Readable Stream where you can listen to the event `data` with a listener that must follow `function (stat) {}` signature. |
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.
Why ReadableStream and not pull-stream?
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 can use a pull-stream, but I didn't find a way to do this with that package...
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 Also, js-ipfs-api
doesn't seem to be using pull streams. at least the package isn't a dependency.
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.
And how can we close a pull-stream? Their docs say nothing about it. The Readable Stream seems to be more straightforward and easy to use. You just have to do .on('data', fn)
.
@victorbjelkholm I made some updates so this also fixes #212 |
@diasdavid, @victorbjelkholm and I discussed about using Readable Stream or Pull Stream and he pointed me to ipfs/js-ipfs#557 (comment). Then we noticed that it doesn't make much sense to have three different functions for this API since it is really simple. Right now, I have made the implementation to use Readable Stream here. Do you think we should use |
@hacdias there are some more bits that are important for you to get familiar with. Glad that you found ipfs/js-ipfs#557, make sure to also:
I feel that the argument that you are trying to make is that "this is not a very used function and so a simple thing will though", which can be fair, however, it is important to understand the future implications and make decisions that will enable users to migrate without having to follow a changing interface. Two cery good threads for you to read: https://unix.stackexchange.com/questions/235335/the-linux-kernel-breaking-user-space & https://felipec.wordpress.com/2013/10/07/the-linux-way/ Let's follow up once you went through all of these materials :) |
js/src/repo.js
Outdated
expect(isNumber(res.repoSize)).to.eql(true) | ||
expect(isNumber(res.storageMax)).to.eql(true) | ||
expect(res.repoPath).to.be.a('string') | ||
expect(res.version).to.be.a('string') |
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 is still not valid as expect('').to.be.a('string')
would pass the tests.
js/src/stats.js
Outdated
|
||
expect(isNumber(res.provideBufLen)).to.eql(true) | ||
expect(res.wantlist).to.be.an('array') | ||
expect(res.peers).to.be.an('array') |
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 we consider this test to be correct if res.peers
was a empty array?
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.
Yes and it might be empty in some cases.
js/src/repo.js
Outdated
chai.use(dirtyChai) | ||
|
||
const isNumber = (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.
This is actually checking if n
is a BigInt, not Number
, which is a built-in type in JavaScript
js/src/repo.js
Outdated
expect(stat).to.have.property('repoPath') | ||
expect(stat).to.have.property('version') | ||
expect(stat).to.have.property('storageMax') | ||
expect(res).to.exist() |
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 assertions are repeated all over the tests. We should extract the assertions into a function and pass in res
instead.
const expectIsStat = (stat) => {
// Make all the assertions once here
}
SPEC/STATS.md
Outdated
|
||
`stat` is, in both cases, an Object containing the following keys: | ||
|
||
- `totalIn` - is a string containing a uint64 in bytes. |
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 are now Big
values rather than strings.
SPEC/STATS.md
Outdated
@@ -25,12 +25,16 @@ Where: | |||
- `poll` is used to print bandwidth at an interval. | |||
- `interval` is the time interval to wait between updating output, if `poll` is true. | |||
|
|||
`callback` must follow `function (err, stats) {}` signature, where `err` is an error if the operation was not successful. `stats` is an Object containing the following keys: | |||
If `poll` is `true`, then `callback` must follow `function (err, stream) {}` signature, where `err` is an error if the operation was not successful and `stream` is a Pull Stream where you can listen to the event `data` with a listener that must follow `function (stat) {}` signature. |
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.
@hacdias this wasn't necessarily what I was hoping for here. Follow the example of https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/FILES.md#files-api and create two api calls.
ipfs.stats.bw
- single requestsipfs.stats.bwPoll
- return a stream
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.
bwPoll
returns which kind of stream?
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.
ipfs.stats.bwPollPullStream
ipfs.stats.bwPollReadableStream
🙂
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'd just suggest to take the 'Poll' out of the equation and use this three functions:
stats.bw
stats.bwPullStream
stats.bwReadableStream
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.
What do you think @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.
I suggest to structure the SPEC like that instead of creating different entries for each function and add examples for each of them. In FILES spec, we have:
Which is not accurate: we have one API endpoint which is cat
. The other functions should be called variants or something like that and not separated in the SPEC. Why? Duplicated information (on the parameters for example) and then we have that GO - WIP
thing which may make users think there will be catPullStream
or [insert your command here]ReadableStream
on Go. That's something I'd like to work on after finishing this Pull Request and make this interface documentation a little better. What do you think @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.
@hacdias let's avoid painting the 🚲🏡 in this PR. tl;dr; they are top level functions, they should be listed in the table of contents and have urls to it.
4432dc9
to
c76eab4
Compare
@diasdavid @victorbjelkholm could you please take a look at the SPEC I wrote? If you approve it, I can start implementing it on |
@hacdias go for it :) |
I think this is ready @diasdavid :) |
More details on ipfs-inactive/js-ipfs-http-client#686
This also closes #212