diff options
-rw-r--r-- | golib/eows/eows-out.go | 61 | ||||
-rw-r--r-- | golib/eows/eows.go | 10 |
2 files changed, 53 insertions, 18 deletions
diff --git a/golib/eows/eows-out.go b/golib/eows/eows-out.go index 6f6706c..b70e70c 100644 --- a/golib/eows/eows-out.go +++ b/golib/eows/eows-out.go @@ -4,16 +4,52 @@ import ( "bufio" "io" "strings" + "time" ) -// scanBlocks - gain character by character (or as soon as one or more characters are available) -func scanBlocks(data []byte, atEOF bool) (advance int, token []byte, err error) { +// scanChars - gain character by character (or as soon as one or more characters are available) +func scanChars(data []byte, atEOF bool) (advance int, token []byte, err error) { if atEOF && len(data) == 0 { return 0, nil, nil } return len(data), data, nil } +// _pumper is in charge to collect +func (e *ExecOverWS) _pumper(sc *bufio.Scanner, fctOut func(s string)) { + + // Select split function (default sc.ScanLines) + if e.OutSplit == SplitChar || e.OutSplit == SplitLineTime || e.OutSplit == SplitTime { + sc.Split(scanChars) + } + + // Scan method according to split type + if e.OutSplit == SplitLineTime || e.OutSplit == SplitTime { + t0 := time.Now() + buf := "" + for sc.Scan() { + buf += sc.Text() + if time.Since(t0).Nanoseconds() > e.LineTimeSpan || + (e.OutSplit == SplitLineTime && strings.Contains(buf, "\n")) { + fctOut(buf) + buf = "" + t0 = time.Now() + } + } + // Send remaining characters + if len(buf) > 0 { + e.OutputCB(e, "", buf) + } + + } else { + + for sc.Scan() { + e.OutputCB(e, sc.Text(), "") + } + } + +} + // cmdPumpStdout is in charge to forward stdout in websocket func (e *ExecOverWS) cmdPumpStdout(r io.Reader, done chan struct{}) { @@ -22,14 +58,10 @@ func (e *ExecOverWS) cmdPumpStdout(r io.Reader, done chan struct{}) { sc := bufio.NewScanner(r) - // else use default sc.ScanLines - if e.OutSplit == SplitChar { - sc.Split(scanBlocks) - } + e._pumper(sc, func(bufOut string) { + e.OutputCB(e, bufOut, "") + }) - for sc.Scan() { - e.OutputCB(e, sc.Text(), "") - } if sc.Err() != nil && !strings.Contains(sc.Err().Error(), "file already closed") { e.logError("stdout scan: %v", sc.Err()) } @@ -42,16 +74,13 @@ func (e *ExecOverWS) cmdPumpStderr(r io.Reader) { defer func() { }() + sc := bufio.NewScanner(r) - // else use default sc.ScanLines - if e.OutSplit == SplitChar { - sc.Split(scanBlocks) - } + e._pumper(sc, func(bufErr string) { + e.OutputCB(e, "", bufErr) + }) - for sc.Scan() { - e.OutputCB(e, "", sc.Text()) - } if sc.Err() != nil && !strings.Contains(sc.Err().Error(), "file already closed") { e.logError("stderr scan: %v", sc.Err()) } diff --git a/golib/eows/eows.go b/golib/eows/eows.go index a5767ed..192be3d 100644 --- a/golib/eows/eows.go +++ b/golib/eows/eows.go @@ -28,6 +28,10 @@ const ( SplitLine SplitType = iota // SplitChar Split character by character SplitChar + // SplitLineTime Split by line or until a timeout has passed + SplitLineTime + // SplitTime Split until a timeout has passed + SplitTime ) // Inspired by : @@ -51,6 +55,7 @@ type ExecOverWS struct { ExitCB EmitExitCB // exit proc callback 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) // Private fields proc *os.Process @@ -67,8 +72,9 @@ func New(cmd string, args []string, so *socketio.Socket, soID, cmdID string) *Ex SocketIO: so, Sid: soID, CmdID: cmdID, - CmdExecTimeout: -1, // default no timeout - OutSplit: SplitChar, // default split by character + CmdExecTimeout: -1, // default no timeout + OutSplit: SplitLineTime, // default split by line with time + LineTimeSpan: 500 * time.Millisecond.Nanoseconds(), } cmdIDMap[cmdID] = e |