I'm trying to copy from a file in go using io.Copy
, which waits for an EOF before actually copying the bytes out of its internal buffer, correct? In my use case (PTY/SSH session) the EOF only comes when the session completes, which means I am flying blind the whole time until the session decides that its over.
I've tried to use CopyN with 1 byte at a time which does work, but if I try to wait for a certain bit of text to come up and I copy one past what has been pushed to the file the code will hang and I lose the session. Is there a function to just "read whats there" and then stop, or a different marker (like EOF) that can tell copy to stop for now?
I have also tried to read the contents of the file that ptyI.pty points to but it always returns 0 bytes so I cant check for updates there
Here is the code that handles it as of right now:
type PtyInterface struct {
pty *os.File
buf *bytes.Buffer
}
func (ptyI *PtyInterface) PrivCmd(cmdStr string) (string, error) {
// Copy the command provided into the STDIN of the bash shell we opened with
// the earlier PtyInterface
_, _ = io.Copy(ptyI.pty, strings.NewReader(string("somecommand")))
// Assuming everything has gone well, we wait for the prompt to appear
// We do this by running through individual bytes until the prompt is
// fully printed (otherwise we might try to send in the answer at the wrong time)
for !strings.HasSuffix(ptyI.buf.String(), "Prompt question? ") {
_, _ = io.CopyN(ptyI.buf, ptyI.pty, 1)
}
// Once we hit the prompt we throw the answer into STDIN along with a newline
// and the bash shell should accept this and begin executing the command.
_, _ = io.Copy(ptyI.pty, strings.NewReader(string("answer
")))
// If we dont throw an exit in there then the PTY will never receive an EOF marker and we'll
// hang on the next copy
_, _ = io.Copy(ptyI.pty, strings.NewReader(string("exit
")))
// Now this copy will wait for an EOF
_, _ = io.Copy(ptyI.buf, ptyI.pty)
//Debug info to be printed after
fmt.Println("
Bytes written to buffer (newone):
" + ptyI.buf.String())
return ptyI.buf.String(), nil
}