romesses
@romesses
Backend инженер

Как записывать stdout в буфер и считывать оттуда построчно?

Дано:
сторонний SDK некоторой библиотеки на Go, которая запускает внешний процесс. В ней есть возможность записывать stdout, получаемый при выводе оного процесса в виде многострочного текста.
SetStdout(writer io.Writer)

Мне необходимо реализовать функционал, который позволит отправлять в брокер сообщения по 20 строк, которые были записаны при помощи того writer. И, таким образом, отправлять сообщения в брокер, пока весь вывод не закончится (стриминг).
Насколько я понимаю, мне нужно реализовать интерфейс io.Writer, записывая в какой-то буфер, а в другой функции, в горутине, считывать оттуда построчно и по мере наполнения буфера из 20 строк, отправлять их в брокер.

Надеюсь, объяснил достаточно понятно.

Подскажите на примере простого кода как это осуществить.
  • Вопрос задан
  • 169 просмотров
Решения вопроса 1
EvgenyMamonov
@EvgenyMamonov Куратор тега Go
Senior software developer, system architect
Вы всё верно понимаете, горутину можно не использовать.

Вы можете сделать что-то типа такого
работающий вариант

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)
    }
}


если возникнут сложности с реализацией - напишите, помогу
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы