nuclei/internal/progress/stdcapture.go
2020-08-25 23:33:20 +02:00

103 lines
1.8 KiB
Go

package progress
/**
Inspired by the https://github.com/PumpkinSeed/cage module
*/
import (
"bufio"
"io"
"os"
"strings"
"sync"
"github.com/projectdiscovery/gologger"
)
const (
fourMegas = 4 * 1024
two = 2
)
type captureData struct {
backupStdout *os.File
writerStdout *os.File
backupStderr *os.File
writerStderr *os.File
waitFinishRead *sync.WaitGroup
}
func startCapture(writeLocker sync.Locker, stdout, stderr *strings.Builder) *captureData {
rStdout, wStdout, errStdout := os.Pipe()
if errStdout != nil {
panic(errStdout)
}
rStderr, wStderr, errStderr := os.Pipe()
if errStderr != nil {
panic(errStderr)
}
c := &captureData{
backupStdout: os.Stdout,
writerStdout: wStdout,
backupStderr: os.Stderr,
writerStderr: wStderr,
waitFinishRead: &sync.WaitGroup{},
}
os.Stdout = c.writerStdout
os.Stderr = c.writerStderr
stdCopy := func(builder *strings.Builder, reader *os.File, waitGroup *sync.WaitGroup) {
r := bufio.NewReader(reader)
buf := make([]byte, 0, fourMegas)
for {
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
waitGroup.Done()
break
}
waitGroup.Done()
gologger.Fatalf("stdcapture error: %s", err)
}
if err != nil && err != io.EOF {
waitGroup.Done()
gologger.Fatalf("stdcapture error: %s", err)
}
writeLocker.Lock()
builder.Write(buf)
writeLocker.Unlock()
}
}
c.waitFinishRead.Add(two)
go stdCopy(stdout, rStdout, c.waitFinishRead)
go stdCopy(stderr, rStderr, c.waitFinishRead)
return c
}
func stopCapture(c *captureData) {
_ = c.writerStdout.Close()
_ = c.writerStderr.Close()
c.waitFinishRead.Wait()
os.Stdout = c.backupStdout
os.Stderr = c.backupStderr
}