package eows import ( "bufio" "io" "strings" "time" ) // 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, fctCB 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")) { fctCB(buf) buf = "" t0 = time.Now() } if e.procExited { break } } // Send remaining characters if len(buf) > 0 { fctCB(buf) } } else { for sc.Scan() { fctCB(sc.Text()) if e.procExited { break } } } } // 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) { if e.OutputCB != nil { e.OutputCB(e, []byte(b), []byte{}) } }) e.logDebug("STDOUT pump exit") if sc.Err() != nil && !strings.Contains(sc.Err().Error(), "file already closed") { e.logError("stdout scan: %v", sc.Err()) } close(done) } // 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) { if e.OutputCB != nil { e.OutputCB(e, []byte{}, []byte(b)) } }) e.logDebug("STDERR pump exit") if sc.Err() != nil && !strings.Contains(sc.Err().Error(), "file already closed") { 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") }