R
R
Romses Panagiotis2021-01-09 12:32:37
go
Romses Panagiotis, 2021-01-09 12:32:37

How to write stdout to buffer and read from it line by line?

Given:
a third-party SDK of some Go library that launches an external process. It has the ability to write stdout, obtained from the output of this process in the form of multiline text.
SetStdout(writer io.Writer)

I need to implement a functionality that will allow me to send messages to the broker of 20 lines that were written using that writer. And, thus, send messages to the broker until all the output is over (streaming).
As far as I understand, I need to implement the interface io.Writerby writing to some kind of buffer, and in another function, in the goroutine, read from there line by line and, as the buffer of 20 lines is filled, send them to the broker.

I hope I explained it clearly enough.

Show me how to do this with a simple code example.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Mamonov, 2021-01-09
@romesses

You understand everything correctly, the goroutine can not be used.
You can do something like this

working option

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "io"
    "log"
    "os/exec"
)

type Executor struct {
    wr io.Writer
}

func (e *Executor) SetStdout(w io.Writer) {
    e.wr = w
}

func (e *Executor) Exec() error {
    cmd := exec.Command("ls", "/etc")
    cmd.Stdout = e.wr
    err := cmd.Run()
    return err
}

type BufferedBrokerWriter struct {
    buffer  bytes.Buffer
    scanner *bufio.Scanner
}

func NewBufferedBrokerWriter() *BufferedBrokerWriter {
    bw := &BufferedBrokerWriter{}
    bw.scanner = bufio.NewScanner(&bw.buffer)
    return bw
}

func (bw *BufferedBrokerWriter) Write(p []byte) (int, error) {
    return bw.buffer.Write(p)
}

func (bw *BufferedBrokerWriter) ReadLines(cnt uint) ([]string, error) {
    lines := make([]string, 0, cnt)
    linesCnt := uint(0)

    for bw.scanner.Scan() {
        line := bw.scanner.Text()
        err := bw.scanner.Err()
        if err != nil || line == `` {
            return lines, err
        }

        lines = append(lines, line)
        linesCnt++
        if linesCnt >= cnt {
            return lines, nil
        }
    }

    return nil, io.EOF
}

func main() {
    // подключаетесь к вашему брокеру сообщений,

    bw := NewBufferedBrokerWriter()

    e := &Executor{}
    e.SetStdout(bw)

    err := e.Exec()
    if err != nil {
        log.Fatal(err)
    }

    for {
        lines, err := bw.ReadLines(2)
        if err == io.EOF {
            break
        }
        fmt.Printf("Lines:\n%+v\n\n", lines)
    }
}


If you have any difficulties with the implementation - write, I will help

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question