UNPKG

webgme-rosmod

Version:

This repository contains ROSMOD developed for WebGME. ROSMOD is a web-based, collaborative, modeling and execution environment for distributed embedded applications built using ROS http://rosmod.rcps.isis.vanderbilt.edu

335 lines (291 loc) 12.9 kB
/*globals define, WebGMEGlobal*/ /** * Example of custom plugin configuration. Typically a dialog would show up here. * @author pmeijer / https://github.com/pmeijer */ define([ 'q', 'js/Dialogs/PluginConfig/PluginConfigDialog' ], function ( Q, PluginConfigDialog) { 'use strict'; function ConfigWidget(params) { this._client = params.client; this._logger = params.logger.fork('ConfigWidget'); } /** * Called by the InterpreterManager if pointed to by metadata.configWidget. * You can reuse the default config by including it from 'js/Dialogs/PluginConfig/PluginConfigDialog'. * * @param {object[]} globalConfigStructure - Array of global options descriptions (e.g. runOnServer, namespace) * @param {object} pluginMetadata - The metadata.json of the the plugin. * @param {object} prevPluginConfig - The config at the previous (could be stored) execution of the plugin. * @param {function} callback * @param {object|boolean} callback.globalConfig - Set to true to abort execution otherwise resolved global-config. * @param {object} callback.pluginConfig - Resolved plugin-config. * @param {boolean} callback.storeInUser - If true the pluginConfig will be stored in the user for upcoming execs. * */ ConfigWidget.prototype.show = function (globalConfigStructure, pluginMetadata, prevPluginConfig, callback) { var pluginConfig = JSON.parse(JSON.stringify(prevPluginConfig)), // Make a copy of the prev config globalConfig = {}, activeNodeId = WebGMEGlobal.State.getActiveObject(), activeNode; var self = this; self.activeNode = self._client.getNode(activeNodeId); self._client.getCoreInstance(null, function(err, result) { self.core = result.core; self.root = result.rootNode; var systemPointer = self.activeNode.getPointer('System').to; var systemNode = self._client.getNode( systemPointer ); var deploymentPointer = self.activeNode.getPointer('Deployment').to; var deploymentNode = self._client.getNode( deploymentPointer ); // get hosts in the system from pointer var hosts, users, containers; self.getChildrenByType( systemNode, 'Host' ) .then(function(_hosts) { hosts = _hosts; return self.getChildrenByType( systemNode, 'User' ); }) .then(function(_users) { users = _users; return self.getChildrenByType( deploymentNode, 'Container' ); }) .then(function(_containers) { containers = _containers; return self.makeContainerNodeMap( containers ); }) .then(function(_containerNodeMap) { var containerNodeMap = _containerNodeMap; // how do we want to do debugging? var debugConfig = self.makeDebugConfig( containerNodeMap ); pluginMetadata.configStructure = debugConfig.concat(pluginMetadata.configStructure); // for each container create sortable selection of nodes for ordering their starting var containerConfig = self.makeContainerConfig( containerNodeMap ); pluginMetadata.configStructure = [containerConfig].concat(pluginMetadata.configStructure); // figure out their users var hostUserMap = self.makeHostUserMap( hosts, users ); // for each host create selection in meta with options // containing users (defauling to first user) and "Disabled" var hostConfig = self.makeHostConfig( hostUserMap ); pluginMetadata.configStructure = [hostConfig].concat(pluginMetadata.configStructure); // do we want to spawn rosbridge? var rosBridgeConfig = self.makeRosBridgeConfig( ); pluginMetadata.configStructure = [rosBridgeConfig].concat(pluginMetadata.configStructure); // where do we want to spawn roscore? var rosCoreConfig = self.makeRosCoreConfig( hosts ); pluginMetadata.configStructure = [rosCoreConfig].concat(pluginMetadata.configStructure); var pluginDialog = new PluginConfigDialog({client: self._client}); pluginDialog.show(globalConfigStructure, pluginMetadata, prevPluginConfig, callback); }) }); }; ConfigWidget.prototype.getChildrenByType = function(node, childType) { var self = this; var childIds = node.getChildrenIds(); var nodes = childIds.map(function(cid) { return self.core.loadByPath(self.root, cid); }); return Q.all(nodes) .then(function(nodes) { var filtered = nodes.filter(function(c) { var base = self.core.getMetaType(c); return childType == self.core.getAttribute(base, 'name'); }); return Q.all(filtered); }); }; ConfigWidget.prototype.makeHostUserMap = function(hosts, users) { var self = this, core = self.core, hostUserMap = {}; hosts.map(function(h) { var hostPath = self.core.getPath(h); var hostName = self.core.getAttribute(h,'name'); var validUserPaths = self.core.getMemberPaths(h, 'Users'); var validUsers = users.filter(function(u) { var path = self.core.getPath(u); return validUserPaths.indexOf(path) > -1; }).map(function(u) { return self.core.getAttribute(u, 'name'); }); hostUserMap[ hostPath ] = { name: hostName, users: validUsers }; }); return hostUserMap; }; ConfigWidget.prototype.makeContainerNodeMap = function( containers ) { var self = this, core = self.core, containerNodeMap = {}; var validTypes = ["Node", "External Node", "Script Node"]; var tasks = containers.map(function (container) { var containerPath = core.getPath(container); var containerName = core.getAttribute(container, 'name'); containerNodeMap[ containerPath ] = { nodes: [], name: containerName }; return core.loadChildren(container).then((children) => { children.map((child) => { var nodeName = core.getAttribute(child, 'name'); var base = core.getMetaType(child); var metaType = core.getAttribute(base, 'name'); if (validTypes.indexOf(metaType) > -1) { containerNodeMap[ containerPath ].nodes.push(nodeName); } }); }); }); return Q.all(tasks).then(() => { return containerNodeMap; }); }; ConfigWidget.prototype.makeDebugConfig = function( containerNodeMap ) { var self = this, config = []; var tmpl = { "name": "debugging", "displayName": "Debugging Configuration", "description": "Select if and how you would like to debug.", "value": "None", "valueType": "string", "valueItems": [ "None", "Valgrind on all ROSMOD Nodes", ] }; Object.keys(containerNodeMap).map(function(containerPath) { var nodeDebugging = containerNodeMap[ containerPath ].nodes.map(function(node) { return `gdb+${node}`; }); tmpl.valueItems = tmpl.valueItems.concat(nodeDebugging); }); config.push(tmpl); return config; }; ConfigWidget.prototype.makeContainerConfig = function( containerNodeMap ) { var self = this; return Object.keys(containerNodeMap).reduce(function(o, containerPath) { var tmpl = { "name": containerPath, "displayName": containerNodeMap[ containerPath ].name, "description": "Sort the nodes in the order you wish to start them, top to bottom.", "value": "", "valueType": "sortable", "valueItems": containerNodeMap[ containerPath ].nodes }; o.configStructure.push(tmpl); return o; }, { "name": "containerConfig", "displayName": "Container Configuration", "valueType": "header", "configStructure": [] }); }; ConfigWidget.prototype.makeHostConfig = function( hostUserMap ) { var self = this, disabledMessage = 'Excluded from Experiment'; return Object.keys(hostUserMap).reduce(function(o, hostPath) { var map = hostUserMap[hostPath]; var users = map.users; var hostName = map.name; var tmpl = { "name": hostPath, "displayName": hostName, "description": "Select User for Host deployment or Disabled to exclude host.", "value": users[0] || disabledMessage, "valueType": "string", "valueItems": users.concat(disabledMessage) }; o.configStructure.push(tmpl); return o; }, { "name": "hostConfig", "displayName": "Host Configuration", "valueType": "header", "configStructure": [] }); }; ConfigWidget.prototype.makeRosBridgeConfig = function () { return { "name": "rosbridge", "displayName": "ROS Bridge Config", "valueType": "header", "configStructure": [ { "name": "spawn", "displayName": "Spawn ROSBridge server.", "description": "If true, it will spawn a ROS Bridge server on the ROSMOD server that connects to the system", "value": false, "valueType": "boolean", "readOnly": false }, { "name": "port", "displayName": " ROSBridge server port.", "description": "What port number should we give ROSBridge server? Leave blank for a randomly assigned port", "value": 0, "minValue": 0, "maxValue": 65535, "valueType": "integer", "readOnly": false }, { "name": "IP", "displayName": " ROSBridge server IP.", "description": "What is the ROS_IP of the rosbridge server - this is the IP that the nodes in the system will use to connect to the rosbridge server.", "value": "127.0.0.1", "valueType": "string", "readOnly": false } ] }; }; ConfigWidget.prototype.makeRosCoreConfig = function( hosts ) { var self = this; var hostNames = [ 'Any' ]; hostNames = hostNames.concat( hosts.map(function(h) { return self.core.getAttribute(h,'name'); }) ); hostNames.push('None'); return { "name": "rosCoreConfig", "displayName": "ROS Core Config", "valueType": "header", "configStructure": [ { "name": "rosCoreHost", "displayName": "ROS Core Host", "description": "Select Host / Any / None to select where and whether to spawn ROS Core / ROS Master.", "value": hostNames[0], "valueType": "string", "valueItems": hostNames }, { "name": "rosMasterURI", "displayName": "ROS Master URI.", "description": "Connect to provided ROS MASTER URI if ROS Core Host is set to 'None'. Has the form of 'http://<IP Address>:<Port Number>'", "value": "", "valueType": "string", "readOnly": false }, { "name": "rosNamespace", "displayName": "ROS Namespace.", "description": "Sets the ROS_NAMESPACE for the experiment.", "value": "", "valueType": "string", "readOnly": false }, ] }; }; return ConfigWidget; });