Is there a ssh scripting ReadUntilPrompt async method?

0 votes
asked Jan 14, 2016 by tarveaa (120 points)

I'm trying to use your ssh component in WPF to run remote changes into a unix box.

I can achieve what I want but not without locking up the user interface.

I see there is a runcommandasync. But I can't get the text returned from that. Is there a way to get the returned text?

ReadUntilPrompt works good but I get a freeze while this is running.
Is there a ssh scripting ReadUntilPrompt async method?

Here is my code:

Private Async Sub writechanges_Click(sender As Object, e As RoutedEventArgs)
    Dim ssh As Rebex.Net.Ssh = New Rebex.Net.Ssh
    Await ssh.ConnectAsync("sane.eng.com")
    ssh.Login(usr, pw)
    Dim terminal = New Rebex.TerminalEmulation.VirtualTerminal(80, 25)
    Await terminal.BindAsync(ssh)
    sshterm.Text = terminal.Screen.ToString()
    Dim scripting As Rebex.TerminalEmulation.Scripting = Await ssh.StartScriptingAsync
    scripting.SendCommand("17041") 'no async method
    scripting.ReadUntilPrompt() 'no async method freezes until done reading

End Sub

1 Answer

0 votes
answered Jan 18, 2016 by Pavel Matyska (9,680 points)

Hi,

unfortunately, there are no async method on Scripting class for sending commands and receiving theirs output. You have to write a workaround for it. Here is a sample code:

Using ssh As Rebex.Net.Ssh = New Rebex.Net.Ssh()
    Await ssh.ConnectAsync("sane.eng.com")

    Await ssh.LoginAsync(usr, pw)

    Dim terminal = New Rebex.TerminalEmulation.VirtualTerminal(80, 25)

    Await terminal.BindAsync(ssh)

    ' there Is no text on screen in this point, so this call does Not matter
    'sshterm.Text = string.Join("\n", terminal.Screen.GetRegionText(0, 0, terminal.Screen.Columns, terminal.Screen.Rows));

    ' use scripting of bound terminal
    Dim scripting As Rebex.TerminalEmulation.Scripting = terminal.Scripting

    ' workaround for synchronous api
    Await Task.Run(Function()
                        ' detect prompt first
                        scripting.DetectPrompt()

                        ' if detection of prompt does not work, set the prompt directrly
                        'scripting.Prompt = "<prompt>" ' actual prompt
                        'scripting.Prompt = "regex:[Pp]rompt" ' actual prompt described with regular expression

                        scripting.SendCommand("17041") 'no async method

                        Return scripting.ReadUntilPrompt()
                    End Function
                    )

    sshterm.Text = String.Join(Of String)(vbCrLf, terminal.Screen.GetRegionText(0, 0, terminal.Screen.Columns, terminal.Screen.Rows))
End Using

I also corrected some mistakes:

  • ssh.StartScriptingAsync creates new VirtualTerminal, so the previous one do not receive any output to its screen.
  • Also, Screen.ToString() does not convert its content to its string, you have to call Screen.GetRegionText(...) to read desired screen area.
  • Before sending a command, you have to set which prompt the server uses. You can do that by calling scripting.DetectPrompt(). It can be called for prompts like '>', 'ftp>' or 'user@workingDir$ ' and similar. At the end this method sets scripting.Prompt property, so you can set this property to whatever the prompt is. That is sufficient.
  • Since ssh is local variable, you should call ssh.Disconnect() or at least ssh.Dispose() when you are done with it, so I added that Using statement.
...