Skip to content

Commit

Permalink
Add waitForService to Client class
Browse files Browse the repository at this point in the history
This patch adds waitForService interface to wait for a specific service if it's not available yet. Also, isServiceServerAvailable is added to inquiry the current availability of a service.

Fix #512

* add pollForService method to service client

* use Nan::New instead of v8::Boolean::New

* jsdoc

* rename pollForService to waitForService

* add to contributors
  • Loading branch information
koonpeng authored and Minggang Wang committed Sep 14, 2019
1 parent e40a663 commit 4c6b4a7
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ project. The next step is to send a pull request (PR) for review. The PR will be
Special thanks to the people who contribute.

* [martins-mozeiko](https://github.com/martins-mozeiko)
* [Teo Koon Peng](https://github.com/koonpeng)

## License

Expand Down
15 changes: 11 additions & 4 deletions example/client-example.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,17 @@ rclnodejs.init().then(() => {
b: Math.floor(Math.random() * 100),
};

console.log(`Sending: ${typeof request}`, request);
client.sendRequest(request, (response) => {
console.log(`Result: ${typeof response}`, response);
rclnodejs.shutdown();
client.waitForService(1000).then(result => {
if (!result) {
console.log('Error: service not available');
rclnodejs.shutdown();
return;
}
console.log(`Sending: ${typeof request}`, request);
client.sendRequest(request, (response) => {
console.log(`Result: ${typeof response}`, response);
rclnodejs.shutdown();
});
});

rclnodejs.spin(node);
Expand Down
40 changes: 38 additions & 2 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const debug = require('debug')('rclnodejs:client');
*/

class Client extends Entity {
constructor(handle, serviceName, typeClass, options) {
constructor(handle, nodeHandle, serviceName, typeClass, options) {
super(handle, typeClass, options);
this._nodeHandle = nodeHandle;
this._serviceName = serviceName;
this._sequenceNumber = 0;
}
Expand Down Expand Up @@ -72,10 +73,45 @@ class Client extends Entity {
this._callback(this._response.toPlainObject(this.typedArrayEnabled));
}

/**
* Checks if the service is available.
* @return {boolean} true if the service is available.
*/
isServiceServerAvailable() {
return rclnodejs.serviceServerIsAvailable(this._nodeHandle, this.handle);
}

/**
* Wait until the service server is available or a timeout is reached. This
* function polls for the service state so it may not return as soon as the
* service is available.
* @param {number} timeout The maximum amount of time to wait for, if timeout
* is `undefined` or `< 0`, this will wait indefinitely.
* @return {Promise<boolean>} true if the service is available.
*/
async waitForService(timeout = undefined) {
let deadline = Infinity;
if (timeout !== undefined && timeout >= 0) {
deadline = Date.now() + timeout;
}
let waitMs = 5;
let serviceAvailable = this.isServiceServerAvailable();
while (!serviceAvailable && Date.now() < deadline) {
waitMs *= 2;
waitMs = Math.min(waitMs, 1000);
if (timeout !== undefined && timeout >= -1) {
waitMs = Math.min(waitMs, deadline - Date.now());
}
await new Promise(resolve => setTimeout(resolve, waitMs));
serviceAvailable = this.isServiceServerAvailable();
}
return serviceAvailable;
}

static createClient(nodeHandle, serviceName, typeClass, options) {
let type = typeClass.type();
let handle = rclnodejs.createClient(nodeHandle, serviceName, type.interfaceName, type.pkgName, options.qos);
return new Client(handle, serviceName, typeClass, options);
return new Client(handle, nodeHandle, serviceName, typeClass, options);
}

/**
Expand Down
17 changes: 17 additions & 0 deletions src/rcl_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,22 @@ NAN_METHOD(GetServiceNamesAndTypes) {
info.GetReturnValue().Set(result_list);
}

NAN_METHOD(ServiceServerIsAvailable) {
RclHandle* node_handle = RclHandle::Unwrap<RclHandle>(info[0]->ToObject());
rcl_node_t* node = reinterpret_cast<rcl_node_t*>(node_handle->ptr());
RclHandle* client_handle = RclHandle::Unwrap<RclHandle>(info[1]->ToObject());
rcl_client_t* client = reinterpret_cast<rcl_client_t*>(client_handle->ptr());

bool is_available;
THROW_ERROR_IF_NOT_EQUAL(RCL_RET_OK,
rcl_service_server_is_available(
node, client, &is_available),
"Failed to get service state.");

v8::Local<v8::Boolean> result = Nan::New<v8::Boolean>(is_available);
info.GetReturnValue().Set(result);
}

uint32_t GetBindingMethodsCount(BindingMethod* methods) {
uint32_t count = 0;
while (methods[count].function) {
Expand Down Expand Up @@ -1284,6 +1300,7 @@ BindingMethod binding_methods[] = {
{"getServiceNamesAndTypesByNode", GetServiceNamesAndTypesByNode},
{"getTopicNamesAndTypes", GetTopicNamesAndTypes},
{"getServiceNamesAndTypes", GetServiceNamesAndTypes},
{"serviceServerIsAvailable", ServiceServerIsAvailable},
{"", nullptr}};

} // namespace rclnodejs
2 changes: 1 addition & 1 deletion test/client_setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ rclnodejs.init().then(function() {
b: 2,
};
var publisher = node.createPublisher(Int8, 'back_add_two_ints');
var timer = node.createTimer(100, () => {
client.waitForService().then(() => {
client.sendRequest(request, (response) => {
publisher.publish(response.sum);
});
Expand Down

0 comments on commit 4c6b4a7

Please sign in to comment.