I am trying to implement a shell terminal in a webapp using websocket in spring. I am able to send a single command to the JSch "exec" channel and send the output back to the websocket.
The problem I am having is:
I am not able to retain the state of the shell like working directory, when I send a second command. How can I retain the previous state? I have tried using the same session but it does not work.
public String sendCommand(String command) { StringBuilder outputBuffer = new StringBuilder(); try { Channel channel = sesConnection.openChannel("exec"); ((ChannelExec) channel).setCommand(command); InputStream commandOutput = channel.getInputStream(); channel.connect(); int readByte = commandOutput.read(); while (readByte != 0xffffffff) { outputBuffer.append((char) readByte); readByte = commandOutput.read(); } channel.disconnect(); } catch (IOException ioX) { logWarning(ioX.getMessage()); return null; } catch (JSchException jschX) { logWarning(jschX.getMessage()); return null; } return outputBuffer.toString(); }
To send back to the websocket, in the controller I have :
private SSHManager getSSHInstance() { String errorMessage = null; if (sshInstance == null) { sshInstance = new SSHManager(username, password, host, "", port); errorMessage = sshInstance.connect(); System.out.println("Instance created"); if (errorMessage != null) { throw new RuntimeException("Could not create an ssh connection"); } } System.out.println("Returning created instance"); return sshInstance; } @MessageMapping("/user") @SendTo("/topic/user") public UserResponse getResponse(String command) { SSHManager currInstance = getSSHInstance(); String result = currInstance.sendCommand(command); return new UserResponse(result); }
I tried using the "shell" channel instead of "exec" which worked for getting the input and output through standard input and output stream but I could not get the real-time input and output from/back to the websocket and UI. I am not sure how to proceed from here. Any direction on where/what to look would be very helpful.
Here is my code for the SSH terminal through standard input/output stream:
import com.jcraft.jsch.*; public class Terminal{ public static void main(String[] args){ try{ JSch jsch=new JSch(); String host = "127.0.0.1"; String user = "user"; String password = "pass"; Session session=jsch.getSession(user, host, 5679); session.setPassword(password); session.setConfig("StrictHostKeyChecking", "no"); session.connect(10000); Channel channel=session.openChannel("shell"); channel.setInputStream(System.in); channel.setOutputStream(System.out); channel.connect(3*1000); } catch(Exception e){ System.out.println(e.getMessage()); } } }
To send the command from the UI, I have the following:
function sendCommand() { if (stompClient != null) { stompClient.send("/app/user", {}, JSON.stringify({'command': $("#command").val()})); } }