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

fix: http server reporting circular structure #513

Merged

Conversation

danielpeintner
Copy link
Member

Note: this PR is not meant to be merged as is.

I just run the counter sample and with the current code I get

[binding-http] HttpServer on port 8080 got internal error on read '/counter/properties/count': Converting circular structure to JSON
    --> starting at object with constructor 'ReadableStream'
    |     property '_readableStreamController' -> object with constructor 'ReadableStreamDefaultController'
    --- property '_controlledReadableStream' closes the circle

I tried to fix it but I am not sure whether this is the right way...

@danielpeintner danielpeintner marked this pull request as draft September 17, 2021 11:26
Copy link
Member

@relu91 relu91 left a comment

Choose a reason for hiding this comment

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

I think we should find a more general approach to solve this issue. One starter is to define an internal content type (e.g., "application/internal" or similar) for values that are passed from the old consumed thing methods in ExposedThing. Later on, we should evaluate a refactoring where the ExposedThing class does not have ConsumedThing methods anymore.

packages/binding-http/src/http-server.ts Outdated Show resolved Hide resolved
packages/core/src/interaction-output.ts Outdated Show resolved Hide resolved
@danielpeintner danielpeintner marked this pull request as ready for review September 21, 2021 06:54
@@ -111,16 +110,16 @@ class HttpServerTest {
console.log("Testing", uri);

body = await (await fetch(uri + "properties/test")).text();
expect(body).to.equal('"off"');
expect(body).to.equal("off");
Copy link
Member Author

@danielpeintner danielpeintner Sep 21, 2021

Choose a reason for hiding this comment

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

I am a bit unsure why there was '"off"' before?

Comment on lines +694 to +709
.then(async (propMap: WoT.PropertyReadMap) => {
// Note we create one object to return, TODO piping response
let recordReponse: Record<string, any> = {};
for (let key of propMap.keys()) {
let value: WoT.InteractionOutput = propMap.get(key);
value.form = { f: "all" }; // to avoid missing form error
let content = ContentSerdes.get().valueToContent(
value.data && !value.dataUsed ? value.data : await value.value(),
undefined,
"application/json"
);
// TODO ProtocolHelpers.readStreamFully() does not work for counter example for SVG countAsImage
const data = await ProtocolHelpers.readStreamFully(content.body);
recordReponse[key] = data.toString(); // contentType handling?
}
res.setHeader("Content-Type", "application/json"); // contentType handling?
Copy link
Member Author

Choose a reason for hiding this comment

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

read all properties is very messy... piping does not work for me.

Moreover, ProtocolHelpers.readStreamFully() does not worj for all properties, e.g. SVG image in counter

Copy link
Member

Choose a reason for hiding this comment

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

I agree it is messy, but I think this is something from the spec itself. In all the aggregated operations we are failing to describe how the payload will look like... I remembered that we decided to go with the fact that each property value should be transmitted inside a JSON object similar to what you're doing. However, don't you think is better to just call the value function on each key in propMap and If it fails read the stream? Why are you using valueToContent ?

@danielpeintner
Copy link
Member Author

danielpeintner commented Sep 21, 2021

Note: I would like to merge this PR soon so that we continue the work (e.g., #522) and do some more fixes later.

Hence I propose to post-pone:

Copy link
Member

@relu91 relu91 left a comment

Choose a reason for hiding this comment

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

PR looks good! there are some minor comments to be fixed. I have also another concern but we can fix it in a follow-up PR: I think that the protocol bindings server should not care about content types as much as possible (maybe write/readall is an exception). But in principle, they should just receive the InteractionOuput (already encoded) from the upper level and pipe it to the output stream

Comment on lines +694 to +709
.then(async (propMap: WoT.PropertyReadMap) => {
// Note we create one object to return, TODO piping response
let recordReponse: Record<string, any> = {};
for (let key of propMap.keys()) {
let value: WoT.InteractionOutput = propMap.get(key);
value.form = { f: "all" }; // to avoid missing form error
let content = ContentSerdes.get().valueToContent(
value.data && !value.dataUsed ? value.data : await value.value(),
undefined,
"application/json"
);
// TODO ProtocolHelpers.readStreamFully() does not work for counter example for SVG countAsImage
const data = await ProtocolHelpers.readStreamFully(content.body);
recordReponse[key] = data.toString(); // contentType handling?
}
res.setHeader("Content-Type", "application/json"); // contentType handling?
Copy link
Member

Choose a reason for hiding this comment

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

I agree it is messy, but I think this is something from the spec itself. In all the aggregated operations we are failing to describe how the payload will look like... I remembered that we decided to go with the fact that each property value should be transmitted inside a JSON object similar to what you're doing. However, don't you think is better to just call the value function on each key in propMap and If it fails read the stream? Why are you using valueToContent ?

packages/binding-http/src/http-server.ts Outdated Show resolved Hide resolved
packages/core/src/interaction-output.ts Show resolved Hide resolved
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.

2 participants