UNPKG

rclnodejs

Version:
317 lines (284 loc) 9.93 kB
// Copyright (c) 2020 Wayne Parrott. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. 'use strict'; const { Parameter, PARAMETER_SEPARATOR } = require('./parameter.js'); /** * Implements the ros2 service interfaces for interacting with a node's parameters. * * The interfaces implemented are: * rcl_interfaces/srv/ListParameters * rcl_interfaces/srv/DescribeParameters * rcl_interfaces/srv/GetParameters * rcl_interfaces/srv/SetParameters * rcl_interfaces/srv/SetParametersAtomically * rcl_interfaces/srv/GetParameterTypes * * Call start() to begin receiving client request. * All service requests are forwarded to the node this service works for. * @class */ class ParameterService { /** * Create a new instance. * @constructor * @param {Node} node - The node these services will support. */ constructor(node) { this._node = node; this._isRunning = false; } /** * Get the node this * @return {Node} - The supported node. */ get node() { return this._node; } /** * Check if interface services are configured and accepting requests. * @return {boolean} - True if services are active; false otherwise. */ isStarted() { return this._isRunning; } /** * Configure parameter services and begin processing client requests. * If this service is already started the request is ignored, i.e., a nop. * * @return {undefined} */ start() { // do nothing if service is already running if (this._isRunning) return; this._isRunning = true; const nodeName = this.node.name(); // create ListParameters service const listParametersServiceName = nodeName + '/list_parameters'; this.node.createService( 'rcl_interfaces/srv/ListParameters', listParametersServiceName, (request, response) => this._handleListParameters(request, response) ); // create DescribeParameters service const describeParametersServiceName = nodeName + '/describe_parameters'; this._node.createService( 'rcl_interfaces/srv/DescribeParameters', describeParametersServiceName, (request, response) => { this._handleDescribeParameters(request, response); } ); // create GetParameters service const getParametersServiceName = nodeName + '/get_parameters'; this._node.createService( 'rcl_interfaces/srv/GetParameters', getParametersServiceName, (request, response) => { this._handleGetParameters(request, response); } ); // create SetParameters service const setParametersServiceName = nodeName + '/set_parameters'; this._node.createService( 'rcl_interfaces/srv/SetParameters', setParametersServiceName, (request, response) => { this._handleSetParameters(request, response); } ); // Create GetParameterTypes service. const getParameterTypesServiceName = nodeName + '/get_parameter_types'; this._node.createService( 'rcl_interfaces/srv/GetParameterTypes', getParameterTypesServiceName, (request, response) => { this._handleGetParameterTypes(request, response); } ); // create SetParametersAtomically service const setParametersAtomicallyServiceName = nodeName + '/set_parameters_atomically'; this._node.createService( 'rcl_interfaces/srv/SetParametersAtomically', setParametersAtomicallyServiceName, (request, response) => { this._handleSetParametersAtomically(request, response); } ); } /** * Get a list of parameter names. * * The body of the response is a rcl_interfaces.msg.ListParametersResult. * * @param {ListParameters_Request} request - The client request. * @param {ListParameters_Response} response - The service response with * a list of parameter names. * @return {undefined} - */ _handleListParameters(request, response) { const DEPTH_RECURSIVE = 0; let prefixedNames = []; const parameterNames = this._node.getParameterNames(); const msg = response.template; const result = msg.result; for (const paramName of parameterNames) { if (paramName.includes(PARAMETER_SEPARATOR)) { prefixedNames.push(paramName); continue; } else if (request.prefixes.length > 0) { for (const prefix of request.prefixes) { if (paramName.startsWith(prefix)) { result.names.push(paramName); break; } } } else { result.names.push(paramName); } } if (request.depth == 1) { response.send(msg); return; } if (request.depth != DEPTH_RECURSIVE) { prefixedNames = prefixedNames.filter( (name) => name.split(PARAMETER_SEPARATOR).length - 1 < request.depth ); } for (const paramName of prefixedNames) { if (request.prefixes.length > 0) { for (const prefix of request.prefixes) { if (paramName.startsWith(prefix + PARAMETER_SEPARATOR)) { result.names.push(paramName); // drop the last segment of paramName to reveal a prefix let fullPrefix = paramName.split(PARAMETER_SEPARATOR); fullPrefix.pop(); fullPrefix = fullPrefix.join(PARAMETER_SEPARATOR); if (!result.prefixes.includes(fullPrefix)) { result.prefixes.push(fullPrefix); } if (!request.prefixes.includes(prefix)) { result.prefixes.push(prefix); } } } } else { result.names.push(paramName); // drop the last segment of paramName to reveal a prefix let prefix = paramName.split(PARAMETER_SEPARATOR); prefix.pop(); prefix = prefix.join(PARAMETER_SEPARATOR); if (!request.prefixes.includes(prefix)) { result.prefixes.push(prefix); } } } response.send(msg); } /** * Get a list of ParameterDescriptors. * * Request.names identifies the descriptors to get. * If request.names is empty, get all descriptors. * The body of the response is a rcl_interfaces.msg.DescribeParametersResult. * * @param {DescribeParameters_Request} request - The client request * @param {DescribeParameters_Response} response - The server response with * an array of ParameterDescriptors. * @return {undefined} - */ _handleDescribeParameters(request, response) { const names = request.names; const msg = response.template; // ParameterDescriptor if (names.length > 0) { const descriptors = this._node.getParameterDescriptors(names); msg.descriptors = descriptors.map((descriptor) => descriptor.toMessage()); } response.send(msg); } /** * Get a list of ParameterValue. * * request.names identifies the parameter values to get. * If request.names is empty return the value of all parameters. * The body of the response is a rcl_interfaces.msg.ParameterValue[]. * * @param {GetParameters_Request} request - The client request. * @param {GetParameters_Response} response - The service response with * an array of ParameterValue. * @return {undefined} - */ _handleGetParameters(request, response) { const parameters = this._node.getParameters(request.names); const msg = response.template; msg.values = parameters.map((param) => param.toParameterValueMessage()); response.send(msg); } /** * Update a list of parameters. * * Process each setParameter operation in the order defined by the request. * The result is an rcl_interfaces.msg.SetParametersResult[], one result * for each parameter. * * @param {SetParameters_Request} request - The client request. * @param {SetParameters_Response} response - The service response * with a SetParametersResult[] * @return {undefined} - */ _handleSetParameters(request, response) { const parameters = request.parameters.map((paramMsg) => Parameter.fromParameterMessage(paramMsg) ); const msg = response.template; msg.results = this._node.setParameters(parameters); response.send(msg); } /** * Get a list of parameter types. * * request.names identifies the parameter types to get. * * @param {GetParameterTypes_Request} request - The client request. * @param {GetParameterTypes_Response} response - The service response with * Uint8Array. * @return {undefined} - */ _handleGetParameterTypes(request, response) { const types = this._node.getParameterTypes(request.names); const msg = response.template; msg.types = types; response.send(msg); } /** * Update a list of parameters atomically. * * The body of the response is a rcl_interfaces.msg.SetParametersResult * * @param {SetParameters_Request} request - The client request. * @param {SetParameters_Response} response - The service response * with a single SetParametersResult for the entire process. * @return {undefined} - */ _handleSetParametersAtomically(request, response) { const parameters = request.parameters.map((paramMsg) => Parameter.fromParameterMessage(paramMsg) ); const msg = response.template; msg.result = this._node.setParametersAtomically(parameters); response.send(msg); } } module.exports = ParameterService;