github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/net/terminal/client/impl.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  
     8  	"golang.org/x/crypto/ssh/terminal"
     9  )
    10  
    11  type flushWriter interface {
    12  	Flush() error
    13  	io.Writer
    14  }
    15  
    16  func startTerminal(conn FlushReadWriter) error {
    17  	oldState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
    18  	if err != nil {
    19  		return err
    20  	}
    21  	defer terminal.Restore(int(os.Stdin.Fd()), oldState)
    22  	retval := make(chan error, 2)
    23  	go func(retval chan<- error) {
    24  		retval <- readFromConnection(conn)
    25  	}(retval)
    26  	go func(retval chan<- error) {
    27  		retval <- readFromStdin(conn)
    28  	}(retval)
    29  	return <-retval
    30  }
    31  
    32  func readFromConnection(conn io.Reader) error {
    33  	// Read from connection until EOF, write to stdout.
    34  	buffer := make([]byte, 256)
    35  	for {
    36  		if nRead, err := conn.Read(buffer); err != nil {
    37  			if err == io.EOF {
    38  				return nil
    39  			}
    40  			return fmt.Errorf("error reading from remote shell: %s\n", err)
    41  		} else {
    42  			os.Stderr.Write(buffer[:nRead])
    43  		}
    44  	}
    45  }
    46  
    47  func readFromStdin(conn flushWriter) error {
    48  	// Read from stdin until control-\ (File separator), write to connection.
    49  	for {
    50  		buffer := make([]byte, 256)
    51  		if nRead, err := os.Stdin.Read(buffer); err != nil {
    52  			return fmt.Errorf("error reading from stdin: %s", err)
    53  		} else {
    54  			if buffer[0] == '\x1c' { // Control-\: File separator.
    55  				return nil
    56  			}
    57  			if _, err := conn.Write(buffer[:nRead]); err != nil {
    58  				return fmt.Errorf("error writing to connection: %s", err)
    59  			}
    60  			if err := conn.Flush(); err != nil {
    61  				return fmt.Errorf("error flushing connection: %s", err)
    62  			}
    63  		}
    64  	}
    65  }