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

rexpect interact(), giving control back to the user #30

Open
chama-chomo opened this issue Oct 24, 2020 · 3 comments
Open

rexpect interact(), giving control back to the user #30

chama-chomo opened this issue Oct 24, 2020 · 3 comments

Comments

@chama-chomo
Copy link

Is there any way to return control of the terminal back to the user ? e.g. after connecting to a remote server. Thanks.
In python pexpect I use interact() method to achieve this.

@chama-chomo
Copy link
Author

chama-chomo commented Nov 1, 2020

as a Rust newbie I was able to create kind of a POC for my ssh repl, my only problem is it doesn't feel very much like a standard ssh session with command/path expansion and so. There is definitely a better way. Nevertheless, I'm going to provide my piece of code for someone like me, as inspiration (this is my specific case ofc, not too much generic)..

...
    fn connect_ssh(&self, dest: Option<&String>) -> Result<()> {
        ConnectAction::do_ssh_repl(&dest.unwrap())
            .unwrap_or_else(|e| panic!("ssh session failed with {}", e));
        Ok(())
    }

    fn do_ssh_repl(host: &String) -> Result<()> {
        let mut ssh = ConnectAction::create_ssh_session(&host)?;
        ssh.exp_regex("\r\n.*root.*:~# ")?;
        ConnectAction::interact(&mut ssh)?;
        ssh.exp_eof()?;
        Ok(())
    }

    fn create_ssh_session(host: &String) -> Result<PtyReplSession> {
        println!("Connecting to host {}", host);
        let custom_prompt = format!("root@{}'s password: ", host);
        let custom_command = format!("ssh root@{}", host);
        let mut ssh = PtyReplSession {
            echo_on: false,
            prompt: custom_prompt,
            pty_session: spawn(&*custom_command.into_boxed_str(), Some(5000))?,
            quit_command: Some("Q".to_string()),
        };
        ssh.wait_for_prompt()?;
        ssh.send_line("root")?;
        Ok(ssh)
    }

    fn interact(session: &mut PtyReplSession) -> Result<()> {
        while let Some(WaitStatus::StillAlive) = session.process.status() {
            let mut user_input = String::new();
            print!("ssh session :> ");
            io::stdout().flush().expect("couldn't flush buffer");
            io::stdin().read_line(&mut user_input).expect("error: unable to read user input");
            session.writer.write(&user_input.into_bytes()).expect("could not write");

            let re = Regex::new(r".*root@.*:~# ").unwrap();
            let (before, _) = session.reader.read_until(&rexpect::ReadUntil::Regex(re)).unwrap();

            println!("{}", before);
        };
        Ok(())
    }

@BarretRen
Copy link

@chama-chomo, your workaround looks good, but it's still not perfect.
For example, if I start gdb task with rexpect, i want a real gdb tty after calling interact. But in this way, it can't offer me that.
This issue is opened two years before, but no updates for it. I will use pexpect for my tools.
Life is short, I use python.^v^

@wolfv
Copy link

wolfv commented Aug 30, 2023

We've implemented an interact functionality in the pixi package manager (to spawn an interactive shell where we can source some scripts after the shell has started, and then give control to the user).

You can have a look at the code here: https://github.com/prefix-dev/pixi/pull/316/files

There were some changes:

  • set terminal to raw mode
  • enable ECHO for the terminal (to see what user types) - this is always deactivated in rexpect
  • be able to set the window size when the SIGWINCH signal happens
  • use select on the two filestreams (stdin of the parent and stdout of the child) to forward the input / output

We've gone through a few iterations with this code and are reasonably happy with it now. I am not sure what the appetite is for these changes in rexpect. They are a bit deeper (especially with the ECHO part), but we could potentially make a PR to contribute the feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants