Skip to content

Fix bug with hasParam and getParamNames.#71

Merged
chris-smith merged 2 commits intoRethinkRobotics-opensource:kinetic-develfrom
JamesGiller:fix_hasParam
Oct 4, 2017
Merged

Fix bug with hasParam and getParamNames.#71
chris-smith merged 2 commits intoRethinkRobotics-opensource:kinetic-develfrom
JamesGiller:fix_hasParam

Conversation

@JamesGiller
Copy link
Copy Markdown
Contributor

I was trying to use hasParam in my program, but I got the following error:

[TypeError: _this4._xmlrpcClient.methodCall is not a function at /home/.../node_modules/rosnodejs/dist/lib/ParamServerApiClient.js:102:30 at Promise (<anonymous>) at ParamServerApiClient.hasParam (/home/.../node_modules/rosnodejs/dist/lib/ParamServerApiClient.js:101:14) at RosNode.hasParam (/home/.../node_modules/rosnodejs/dist/lib/RosNode.js:342:35) at NodeHandle.hasParam (/home/.../node_modules/rosnodejs/dist/lib/NodeHandle.js:334:25) at fetchParams (/home/.../scripts/test_server.js:14:34) at <anonymous> at process._tickCallback (internal/process/next_tick.js:188:7)]

I found that the bug was related to the indirection involving the XmlrpcClient wrapper in rosnodejs and the xmlrpc module that it uses:

XmlrpcClient seems to be a wrapper around xmlrpc: it has a _xmlrpcClient property, which is an object from xmlrpc, and a call() function, which is the main interface. XmlrpcClient._tryExecuteCall() actually implements the RPC by passing _xmlrpcClient to XmlrpcCall.call(), which then invokes its methodCall() function. Notice that methodCall() belongs to the _xmlrpcClient property, not to an instance of XmlrpcClient itself.

ParamServerApiClient also has a property named _xmlrpcClient, whose type is the XmlrpcClient wrapper above. The functions getParam and setParam work fine, because they end up using the call() interface; however, hasParam tries to use methodCall(), which as described above belongs to a property of ParamServerApiClient._xmlrpcClient not to ParamServerApiClient._xmlrpcClient itself. I guess because the property in the XmlrpcClient wrapper, and the property in the ParamServerApiClient class that uses the wrapper have the same name, the author forgot about the level of indirection.

This commit changes the implementatino of hasParam and getParamNames to use "call" instead of "methodCall", adding the missing layer of indirection.

The function "methodCall" was being incorrectly called on an object of
type XmlrpcClient. "methodCall" is actually defined for a property of
instances of XmlrpcClient, so this was a simple issue of missing indirection.

XmlrpcClient is a wrapper that defines a "call" function as an interface, and
delegates to an object from the xmlrpc module by calling its "methodCall".
This commit changes the implementatino of hasParam and getParamNames to
use "call" instead of "methodCall", adding the missing layer of indirection.
Copy link
Copy Markdown
Collaborator

@chris-smith chris-smith left a comment

Choose a reason for hiding this comment

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

Yikes! Not sure why I missed that... I'll file a ticket to create tests for these too so it doesn't inadvertently break again.

Comment thread src/lib/ParamServerApiClient.js Outdated
}
else {
this._call('hasParam', data, (resp) => {
if (resp[0] !== 1) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think you can ignore this bit - XmlrpcClient should check if the response code is not 1 and automatically reject the call. You should be able to just call resolve(resp[2]) in this callback

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK, please see the second commit!

I don't know where in the code the structure of the response array is decided, but would it make sense to define named constants for the indices like const ERROR_CODE = 0; or const REQUESTED_VALUE = 2; so you could write resolve(resp[REQUESTED_VALUE]); and wouldn't need the comment // resp[2] is whether it actually has param and presumably all anyone cares about?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The response array follows the ROS XMLRPC Master/Slave/Parameter API spec. Generally the first element is a status code, the second element is a status message, and the third element is the actual data.

Unfortunately, this was one of the first things I wrote and so the use of different indices is scattered across a few files. We should be able to move all of that into XmlRpcClient and have it deal with any indexing into the actual response, but it would be a bit more work than just adding constants into one file.

It's been towards the back of my "nice to do" list for a while, but you're welcome to dig into it if you want.

XmlrpcClient should check if the response code is not 1 and automatically reject the call.
@chris-smith chris-smith merged commit f1bd92e into RethinkRobotics-opensource:kinetic-devel Oct 4, 2017
@chris-smith
Copy link
Copy Markdown
Collaborator

Thanks!

@JamesGiller JamesGiller deleted the fix_hasParam branch October 17, 2017 03:36
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