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

feat: Save new/changed behavior on the robot through SSH #21

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ if(CATKIN_ENABLE_TESTING)
find_package(rostest REQUIRED)
add_rostest(launch/test_report.test)
endif()

execute_process(COMMAND npm --prefix ${PROJECT_SOURCE_DIR} install)
Copy link
Member

Choose a reason for hiding this comment

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

This fails if npm is not installed. Do you see a way to automatically handle npm as a dependency?

14 changes: 12 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
{
"name": "FlexBE App",
"version": "2.0.10",
"name": "flexbe_app",
"version": "2.0.11",
"main": "src/main.js",
"description": "flexbe_app provides a user interface (editor + runtime control) for the FlexBE behavior engine.",
"license": "BSD-3-Clause",
"repository": {
"type": "git",
"url": "[email protected]:FlexBE/flexbe_app.git"
},
"readme": "README.md",
"window": {
"icon": "src/img/icon-128.png",
"toolbar": false,
"width": 1340,
"height": 830,
"min_width": 1340,
"min_height": 650
},
"dependencies" : {
"scp2" : "^0.5.0"
}
}
4 changes: 4 additions & 0 deletions src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ document.addEventListener('DOMContentLoaded', function() {
document.getElementById('select_default_package').addEventListener('change', UI.Settings.defaultPackageChanged);
document.getElementById('select_code_indentation').addEventListener('change', UI.Settings.codeIndentationChanged);
document.getElementById('input_editor_command').addEventListener('change', UI.Settings.editorCommandChanged);
document.getElementById('cb_save_on_robot').addEventListener('change', UI.Settings.saveOnRobotClicked);
document.getElementById('input_ssh_user_name').addEventListener('change', UI.Settings.sshUsernameChanged);
document.getElementById('input_ssh_host_name').addEventListener('change', UI.Settings.sshHostnameChanged);


document.getElementById('select_transition_mode').addEventListener('change', UI.Settings.transitionEndpointsChanged);
document.getElementById('input_gridsize').addEventListener('change', UI.Settings.gridsizeChanged);
Expand Down
104 changes: 92 additions & 12 deletions src/io/io_behaviorsaver.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,89 @@ IO.BehaviorSaver = new (function() {
}
}

String.prototype.format = function() {
var formatted = this;
for( var arg in arguments ) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};

var saveSuccessCallback = function() {
T.logInfo("Save successful!");
UI.Panels.Terminal.hide();
UI.Settings.updateBehaviorlib();
UI.Tools.notifyRosCommand('save');
}
}

var saveOnRobot = function() {
var names = Behavior.createNames();
var package_name = names.rosnode_name;
var ssh_username = UI.Settings.getRobotUsername();
var ssh_hostname = UI.Settings.getRobotHostname();
var ssh_package_path = ""

if(ssh_username === "" || ssh_hostname === "" /*|| ssh_password === ""*/) {
T.logError("SSH configurations are not well defined, fix them from Configuration Tab -> Code Generation Box");
return;
}

var ssh_password = window.prompt("Please enter {0}:{1} password: ".format(ssh_username, ssh_hostname));
if(ssh_password == null || ssh_password == "") {
return;
}

ROS.getPackagePath(package_name, (package_path) =>
{
try
{
var SSHClient = require('ssh2').Client;
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't ssh2 be an npm dependency as well? Even if included in scp2, it is referenced here directly.

conn = new SSHClient();
conn.on('ready', function() {
var ros_distro = process.env.ROS_DISTRO;
conn.exec('bash -c "source .profile && rospack find {1}"'.format(ros_distro, package_name), function(err, stream) {
if (err) {
T.logError(err);
}
stream.on('close', function(code, signal) {
conn.end();
})
.on('data', function(remote_package_path) {
ssh_package_path = String(remote_package_path).trim();
T.logInfo('Path to package on the robot: ' + ssh_package_path);
conn.end()
var scp_client = require('scp2')
var ssh_query = '{0}:{1}@{2}:{3}/'.format(
ssh_username,
ssh_password,
ssh_hostname,
ssh_package_path);
Copy link
Member

Choose a reason for hiding this comment

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

This contains the password in plain text, right? Is there a way to encrypt? I have no experience with the scp2 package, but do you know how the query string would be further used?

scp_client.scp(package_path+"/", String(ssh_query), function(err) {
var err_str = String(err);
if( err_str != 'undefined') {
T.logError("scp failed "+err);
}
});
}).stderr.on('data', function(data) {
T.logError(data+", Make sure robot's ROS environment is configured properly in \".profile\" script");
})
});
})
.on('error', function(err) {
T.logError(err);
T.logError("Please check your ssh configuration and entered password.");
})
.connect({
host: ssh_hostname,
username: ssh_username,
password: ssh_password
});
}
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if I understand the above code block correctly. To me it looks like there is an ssh connection created first and then, within this connection, another scp connection is opened to transfer the file. Do I get it wrong? Or what is the reason for this approach?

catch(ex) {
T.logError("An exception occurred: "+ex.message+", Make sure you installed the dependencies properly!")
}
})
}

this.saveStateMachine = function() {
T.clearLog();
Expand All @@ -91,15 +167,19 @@ IO.BehaviorSaver = new (function() {
return;
}

// store in file
storeBehaviorCode(generated_code, () => {
// make sure code file exists before creating the manifest
// this reduces the risk for orphan manifests
storeBehaviorManifest(generated_manifest, () => {
saveSuccessCallback();
});
});
});
}
// store in file
storeBehaviorCode(generated_code, () => {
// make sure code file exists before creating the manifest
// this reduces the risk for orphan manifests
storeBehaviorManifest(generated_manifest, () => {
if(UI.Settings.isSaveOnRobotEnabled()) {
//Save/Overwrite the behavior on the robot
saveOnRobot();
}
saveSuccessCallback();
});
});
});
}

}) ();
}) ();
48 changes: 47 additions & 1 deletion src/ui/ui_settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ UI.Settings = new (function() {
var default_package;
var code_indentation;
var editor_command;
var save_on_robot;
var ssh_hostname;
var ssh_username;

var transition_mode;
var gridsize;
Expand All @@ -42,6 +45,9 @@ UI.Settings = new (function() {
'default_package': default_package,
'code_indentation': code_indentation,
'editor_command': editor_command,
'save_on_robot': save_on_robot,
'ssh_username' : ssh_username,
'ssh_hostname' : ssh_hostname,
'transition_mode': transition_mode,
'gridsize': gridsize,
'commands_enabled': commands_enabled,
Expand Down Expand Up @@ -69,6 +75,9 @@ UI.Settings = new (function() {
'default_package': 'flexbe_behaviors',
'code_indentation': 0,
'editor_command': 'gedit --new-window $FILE +$LINE',
'save_on_robot' : false,
'ssh_username': "",
'ssh_hostname' : "",
'transition_mode': 1,
'gridsize': 50,
'commands_enabled': false,
Expand Down Expand Up @@ -101,6 +110,16 @@ UI.Settings = new (function() {
document.getElementById("select_code_indentation").selectedIndex = items.code_indentation;
editor_command = items.editor_command;
document.getElementById("input_editor_command").value = items.editor_command;
save_on_robot = items.save_on_robot;
document.getElementById("cb_save_on_robot").checked = items.save_on_robot;
ssh_username = items.ssh_username;
document.getElementById("input_ssh_user_name").value = items.ssh_username;
ssh_hostname = items.ssh_hostname;
document.getElementById("input_ssh_host_name").value = items.ssh_hostname;
document.getElementById("input_ssh_user_name").disabled = !items.save_on_robot;
document.getElementById("input_ssh_host_name").disabled = !items.save_on_robot;



transition_mode = items.transition_mode;
document.getElementById("select_transition_mode").selectedIndex = items.transition_mode;
Expand Down Expand Up @@ -443,6 +462,33 @@ UI.Settings = new (function() {
return editor_command.replace("$LINE", line_number).replace("$FILE", file_path);
}

this.isSaveOnRobotEnabled = function() { return save_on_robot; }

this.saveOnRobotClicked = function(evt) {
save_on_robot = evt.target.checked;
storeSettings();
document.getElementById("input_ssh_user_name").disabled = !save_on_robot;
document.getElementById("input_ssh_host_name").disabled = !save_on_robot;
}

this.sshUsernameChanged = function(evt) {
ssh_username = document.getElementById('input_ssh_user_name').value;
storeSettings();
}

this.sshHostnameChanged = function(evt) {
ssh_hostname = document.getElementById('input_ssh_host_name').value;
storeSettings();
}

this.getRobotHostname = function() {
return document.getElementById('input_ssh_host_name').value;
}

this.getRobotUsername = function() {
return document.getElementById('input_ssh_user_name').value;
}


// Editor
//========
Expand Down Expand Up @@ -594,4 +640,4 @@ UI.Settings = new (function() {
}
}

}) ();
}) ();
12 changes: 12 additions & 0 deletions src/window.html
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,18 @@ <h1>Code Generation</h1>
<td width="150">Editor command: </td>
<td><input id="input_editor_command" type="text" class="input_field" /></td>
</tr>
<tr title="If this option is enabled, the generated code will be uploaded on the robot using a SSH tunnel">
<td width="80">Save on the robot: </td>
<td><input id="cb_save_on_robot" type="checkbox" /></td>
</tr>
<tr title="Hostname which is required for creating a SSH connection">
<td width="100">Robot hostname: </td>
<td><input id="input_ssh_host_name" type="text" class="input_field" disabled/></td>
</tr>
<tr title="Username which is required for creating a SSH connection">
<td width="100">Robot username: </td>
<td><input id="input_ssh_user_name" type="text" class="input_field" disabled/></td>
</tr>
</table>
</div>

Expand Down