aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2018-03-09 15:57:36 +0100
committerSebastien Douheret <sebastien.douheret@iot.bzh>2018-03-09 16:08:53 +0100
commitf1e97cdbcc13318cb3de39d9e67bc0241614dfcc (patch)
tree04188e8d91e6b1b6a77d21614237f96f2bbbed1f
parentabbf89a5589f2c92f786bb45c5cd613a318a9e24 (diff)
Improved PtyMode (eows lib).
- renamed PtsMode to PtyMode - used byte array instead of string - allowed terminal echo on/off (PtyMode only) - fixed support escaped and control characters (PtyMode only) Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
-rw-r--r--golib/eows/eows-in.go10
-rw-r--r--golib/eows/eows-out.go49
-rw-r--r--golib/eows/eows.go36
3 files changed, 62 insertions, 33 deletions
diff --git a/golib/eows/eows-in.go b/golib/eows/eows-in.go
index 89ca891..5e74c76 100644
--- a/golib/eows/eows-in.go
+++ b/golib/eows/eows-in.go
@@ -13,21 +13,21 @@ type DoneChan struct {
err error
}
-// cmdPumpStdin is in charge of receive characters and send them to stdin
-func (e *ExecOverWS) cmdPumpStdin(inw *os.File) {
+// pumpStdin is in charge of receive characters and send them to stdin
+func (e *ExecOverWS) pumpStdin(inw *os.File) {
done := make(chan DoneChan, 1)
if e.InputEvent != "" && e.InputCB != nil {
- err := (*e.SocketIO).On(e.InputEvent, func(stdin string) {
- in, err := e.InputCB(e, string(stdin))
+ err := (*e.SocketIO).On(e.InputEvent, func(stdin []byte) {
+ in, err := e.InputCB(e, stdin)
if err != nil {
e.logDebug("Error stdin: %s", err.Error())
inw.Close()
return
}
- if _, err := inw.Write([]byte(in)); err != nil {
+ if _, err := inw.Write(in); err != nil {
e.logError("Error while writing to stdin: %s", err.Error())
}
})
diff --git a/golib/eows/eows-out.go b/golib/eows/eows-out.go
index 2d9bdb0..3163b2f 100644
--- a/golib/eows/eows-out.go
+++ b/golib/eows/eows-out.go
@@ -56,16 +56,15 @@ func (e *ExecOverWS) _pumper(sc *bufio.Scanner, fctCB func(s string)) {
}
-// cmdPumpStdout is in charge to forward stdout in websocket
-func (e *ExecOverWS) cmdPumpStdout(r io.Reader, done chan struct{}) {
-
- defer func() {
- }()
+// pipePumpStdout is in charge to forward stdout in websocket
+func (e *ExecOverWS) pipePumpStdout(r io.Reader, done chan struct{}) {
sc := bufio.NewScanner(r)
e._pumper(sc, func(b string) {
- e.OutputCB(e, b, "")
+ if e.OutputCB != nil {
+ e.OutputCB(e, []byte(b), []byte{})
+ }
})
e.logDebug("STDOUT pump exit")
@@ -77,16 +76,15 @@ func (e *ExecOverWS) cmdPumpStdout(r io.Reader, done chan struct{}) {
close(done)
}
-// cmdPumpStderr is in charge to forward stderr in websocket
-func (e *ExecOverWS) cmdPumpStderr(r io.Reader) {
-
- defer func() {
- }()
+// pipePumpStderr is in charge to forward stderr in websocket
+func (e *ExecOverWS) pipePumpStderr(r io.Reader) {
sc := bufio.NewScanner(r)
e._pumper(sc, func(b string) {
- e.OutputCB(e, "", b)
+ if e.OutputCB != nil {
+ e.OutputCB(e, []byte{}, []byte(b))
+ }
})
e.logDebug("STDERR pump exit")
@@ -95,3 +93,30 @@ func (e *ExecOverWS) cmdPumpStderr(r io.Reader) {
e.logError("stderr scan: %v", sc.Err())
}
}
+
+// ptsPumpStdout is in charge to forward stdout in websocket
+// (only used when PtyMode is set)
+func (e *ExecOverWS) ptsPumpStdout(r io.Reader, done chan struct{}) {
+
+ buffer := make([]byte, 1024)
+ for {
+ n, err := r.Read(buffer)
+ if err != nil {
+ if err != io.EOF &&
+ !strings.Contains(err.Error(), "file already closed") {
+ e.logError("Error stdout read: %v", err)
+ }
+ break
+ }
+ if n == 0 {
+ continue
+ }
+ if e.OutputCB != nil {
+ e.OutputCB(e, buffer[:n], []byte{})
+ }
+ }
+
+ close(done)
+
+ e.logDebug("Eows stdout pump exited")
+}
diff --git a/golib/eows/eows.go b/golib/eows/eows.go
index 283d673..9d0b520 100644
--- a/golib/eows/eows.go
+++ b/golib/eows/eows.go
@@ -16,10 +16,10 @@ import (
)
// OnInputCB is the function callback used to receive data
-type OnInputCB func(e *ExecOverWS, stdin string) (string, error)
+type OnInputCB func(e *ExecOverWS, stdin []byte) ([]byte, error)
// EmitOutputCB is the function callback used to emit data
-type EmitOutputCB func(e *ExecOverWS, stdout, stderr string)
+type EmitOutputCB func(e *ExecOverWS, stdout, stderr []byte)
// EmitExitCB is the function callback used to emit exit proc code
type EmitExitCB func(e *ExecOverWS, code int, err error)
@@ -60,7 +60,8 @@ type ExecOverWS struct {
UserData *map[string]interface{} // user data passed to callbacks
OutSplit SplitType // split method to tokenize stdout/stderr
LineTimeSpan int64 // time span (only used with SplitTime or SplitLineTime)
- PtsMode bool // Allocate a pseudo-terminal (allow to execute screen-based program)
+ PtyMode bool // Allocate a pseudo-terminal (allow to execute screen-based program)
+ PtyTermEcho bool // Turn on/off terminal echo
// Private fields
@@ -84,7 +85,8 @@ func New(cmd string, args []string, so *socketio.Socket, soID, cmdID string) *Ex
CmdExecTimeout: -1, // default no timeout
OutSplit: SplitLineTime, // default split by line with time
LineTimeSpan: 500 * time.Millisecond.Nanoseconds(),
- PtsMode: false,
+ PtyMode: false,
+ PtyTermEcho: true,
}
cmdIDMap[cmdID] = e
@@ -114,7 +116,7 @@ func (e *ExecOverWS) Start() error {
e.procExited = false
- if e.PtsMode {
+ if e.PtyMode {
e.command = exec.Command(bashArgs[0], bashArgs[1:]...)
e.command.Env = append(os.Environ(), e.Env...)
@@ -126,7 +128,9 @@ func (e *ExecOverWS) Start() error {
e.proc = e.command.Process
// Turn off terminal echo
- e.terminalEcho(e.ptmx, false)
+ if !e.PtyTermEcho {
+ e.terminalEcho(e.ptmx, false)
+ }
} else {
@@ -162,15 +166,15 @@ func (e *ExecOverWS) Start() error {
go func() {
stdoutDone := make(chan struct{})
- if e.PtsMode {
+ if e.PtyMode {
// Make sure to close the pty at the end.
defer e.ptmx.Close()
// Handle both stdout mixed with stderr
- go e.cmdPumpStdout(e.ptmx, stdoutDone)
+ go e.ptsPumpStdout(e.ptmx, stdoutDone)
// Blocking function that poll input or wait for end of process
- e.cmdPumpStdin(e.ptmx)
+ e.pumpStdin(e.ptmx)
} else {
// Make sure to close all pipes
@@ -182,11 +186,11 @@ func (e *ExecOverWS) Start() error {
defer inw.Close()
// Handle stdout + stderr
- go e.cmdPumpStdout(outr, stdoutDone)
- go e.cmdPumpStderr(errr)
+ go e.pipePumpStdout(outr, stdoutDone)
+ go e.pipePumpStderr(errr)
// Blocking function that poll input or wait for end of process
- e.cmdPumpStdin(inw)
+ e.pumpStdin(inw)
}
if status, err := e.proc.Wait(); err == nil {
@@ -222,8 +226,8 @@ exitErr:
// TerminalSetSize Set terminal size
func (e *ExecOverWS) TerminalSetSize(rows, cols uint16) error {
- if !e.PtsMode || e.ptmx == nil {
- return fmt.Errorf("PtsMode not set")
+ if !e.PtyMode || e.ptmx == nil {
+ return fmt.Errorf("PtyMode not set")
}
w, err := pty.GetsizeFull(e.ptmx)
if err != nil {
@@ -234,8 +238,8 @@ func (e *ExecOverWS) TerminalSetSize(rows, cols uint16) error {
// TerminalSetSizePos Set terminal size and position
func (e *ExecOverWS) TerminalSetSizePos(rows, cols, x, y uint16) error {
- if !e.PtsMode || e.ptmx == nil {
- return fmt.Errorf("PtsMode not set")
+ if !e.PtyMode || e.ptmx == nil {
+ return fmt.Errorf("PtyMode not set")
}
winSz := pty.Winsize{Rows: rows, Cols: cols, X: x, Y: y}
return pty.Setsize(e.ptmx, &winSz)