-
Notifications
You must be signed in to change notification settings - Fork 300
refactor(streams): Refactor response stream handling. #465
refactor(streams): Refactor response stream handling. #465
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.
While we are at it, could you please use pump
instead of .pipe
for combining streams, as that will handle errors and cleanup streams on failure. For more details see https://github.com/mafintosh/pump
this._send = opts.send | ||
} | ||
|
||
static streamToValue (send, inputStream, 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.
is static
available in Node4?
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.
Is it? Is it not? And if so, why is that important? Provide context and solutions or guidance.
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.
Looks good: https://kangax.github.io/compat-table/es6/#test-class_static_methods
Always usable is
class MyClass {}
MyClass.mystaticmethod = function () {
}
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.
Some modifications are not clear to me
isStream.isReadable(files) || | ||
Array.isArray(files) | ||
|
||
if (!good) { | ||
callback(new Error('"files" must be a buffer, readable stream, or array of objects')) | ||
if (!ok) { |
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 change
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.
Don't you think ok
is more descriptive and intuitive than good
?
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.
fine :)
if (!good) { | ||
callback(new Error('"files" must be a buffer, readable stream, or array of objects')) | ||
if (!ok) { | ||
return callback(new Error('"files" must be a buffer, readable stream, or array of objects')) |
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
callback(null, outputStream) | ||
} | ||
|
||
_read () {} |
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 Class with a constructor and a static method? What is the goal here?
Output object format: | ||
{ | ||
path: '/path/to/file/foo.txt', | ||
hash: 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', |
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.
hash or multihash
?
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 "Output object format" is not a DAGNode Transforms a stream of objects to DAGNodes and outputs them as objects.
, what am I missing?
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.
Changed the description. Does that make sense now?
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.
Here: 1566751
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 I'm not sure about the multihash
vs. hash
. It's a breaking change again and I'd be hesitant to change it in this PR. Have we made the change elsewhere in the code already? Does anything that returns DAGNode-like information return .multihash instead of .hash? If we have, I can change it so that we're consistent, but if not, I would leave it for later.
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 https://github.com/ipld/js-ipld-dag-pb/blob/master/src/dag-node/index.js#L22-L27 has been there for a while now, that is why I proposed it to be multihash
if (typeof options !== 'object') { | ||
return callback(new Error('no options were passed')) | ||
} | ||
|
||
return requestAPI(config, options, callback) | ||
} | ||
|
||
// Wraps the 'send' function such that an asynchronous | ||
// transform may be applied to its result before | ||
// passing it on to either its callback or promise. |
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 you preserve the comment please?
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 comment doesn't make sense, and it doesn't hold true for the new implementation.
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 was trying to convey that before the response is returned, either through the callback or promise, we transform the response from go-ipfs to match interface-ipfs-core definition.
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 the description back and trying to describe as simple as I can what it does. What do you think?
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.
Here: 1566751
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.
👍
res.pipe(concat((data) => callback(null, data))) | ||
} | ||
|
||
module.exports = streamToValue |
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.
In case of error on the stream (connection dropped) this fails silently
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.
Is this why you had all the once('error') calls there previously?
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 knowing what is all the
, but yes, if you don't capture the error, you don't know it failed
cb(null, res.Strings || []) | ||
} | ||
|
||
module.exports = stringlistToArray |
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 is a string list? Is there a better name in this context? Does it has to be a separate file to do 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.
stringList is a Go type (that's what it's called in Go) that the go-ipfs API sends back for some requests. It adds an additional "Strings" field to the response that contains a list of strings, so "{ Strings: [...] }" instead of "[...]".
The correct solution here would be to fix it on go-ipfs side to return an array instead of what it does now, and this is a workaround for that: a type to another type conversion function to isolate it and make it clear that another type gets converted to another.
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.
@whyrusleeping wanna 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.
We shouldn't change this on go-ipfs side for this PR. If we do that, it's an API breaking change that we need to handle with proper care. That's why I put it in one file, so that it's wrapped and isolated and if/once we change the return values, we only need to change change it in this file and whichever command is using the current API doesn't need changes. Obviously once you do that, we don't need the stringlist-to-array.js conversion function and can get rid of the file completely, but I recommend we keep it as such now so that we isolate the data conversion to one place. Does that make sense?
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.
Understood :)
Thanks for the review @dignifiedquire and @diasdavid. Will work on this soon, mainly change it to use pump as well as address other CR pieces. |
path: obj.Name, | ||
hash: obj.Hash, | ||
size: node.size | ||
} |
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 really a dag
, it is just a json representation.
let outputStream = new TarStreamToObjects() | ||
|
||
inputStream | ||
.pipe(tar.extract()) |
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.
better to use pump
Will update this today and address the CR feedback. |
I've refactored the pipes to use pump. I wasn't sure if the pump is needed in dagnode-stream.js since streamToValue internally uses pump (so I take it would handle the errors), but I added it just in case. The tests are not running in the browser atm, but run fully on node (will look into why the browser tests are not running). I also reworked the comments for the two functions @diasdavid had a confusion about, hope they're now more descriptive. I refactored the TarStreamToObjects according to @diasdavid's question, perhaps now the intent is clearer. I couldn't get the ReadableStream to work when created directly with There's also a problem with browser version now as we're using pump because its dependency on So while this is still WIP, can you take a look and see if there's anything else to address in this one? |
@haadcode pump fix is here: mafintosh/pump#13 and the issue with cors was correct, you changed them, now they are back: b2c09b2 |
Should we wait for the PR to get merged or can we use the PR commit as our dep in the meanwhile?
Interesting. I had to change it in the first place because it wasn't working. Good that it's fixed now 👍 |
Pinged @mafintosh on irc, if it's not merged when we want to ship this lets switch to the fork. |
@@ -43,6 +42,7 @@ | |||
"peer-id": "^0.8.1", | |||
"peer-info": "^0.8.1", | |||
"promisify-es6": "^1.0.2", | |||
"pump": "^1.0.1", |
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.
lets bump this to 1.0.2
so we are sure to have the fix in
|
||
static streamToValue (send, inputStream, callback) { | ||
const outputStream = pump(inputStream, new DAGNodeStream({ send: send }), (err) => { | ||
if (err) 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.
@diasdavid will want this to be
if (err) {
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.
Other than the hash vs multihash
thing, it LGTM. I'm fine if Files API uses hash
, although I would prefer consistency.
Add dagnode-stream to transform file results to DAGNode objects. Add stream-to-value to convert a response stream to a single value. Refactor request-api so that chunked JSON objects are not buffered anymore. This touches a bunch of the files pushing the transform function down to the individual commands.
I fixed the style issues, updated pump to 1.0.2 and rebased on master.
@diasdavid would you be ok if we leave the change from |
sounds good :) |
Didn't even notice this got merged. Thank you! 😄 🎉 |
This PR will:
The general idea in this PR is to cleanup the architecture and implementation regards to how the http responses are handled. Previously some of it was done in request-api.js and some in the individual commands making request-api coupled with the commands' response type. I've moved the response transform logic down to the individual commands so that request-api is agnostic to what is returned to the consumer of the commands. I've also refactored individual types of transformations to their own files to make it clear, clean and much more reusable (we can consider moving them to their own modules, but not in this PR).