Как транслировать выходные данные команды с каналом? - PullRequest
0 голосов
/ 29 апреля 2020

Я пытаюсь перехватить вывод команды в том виде, в каком она происходит, чтобы я мог передать sh это как буферизованные данные HTTP-клиенту, но я не правильно использую каналы и не знаю, как это исправить.

По сути, это то, как я это реализую. Выходной канал никогда не принимается, и я не получаю вывод команды. Это должно быть что-то довольно очевидное, но я этого не вижу.

package main

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

func main() {
    output := make(chan []byte, 1024)
    done := make(chan struct{})

    cmd := exec.Command("echo", "hello")

    go execute(cmd, output, done)

    for {
        select {
        case data := <-output:
            fmt.Println("Got data")
            fmt.Println(string(data))
            //Flush to http.ResponseWriter
        case <-done:
            fmt.Println("Done")
            return
        }
    }
}

func execute(cmd *exec.Cmd, output chan []byte, done chan struct{}) {
    defer func() {
        done <- struct{}{}
    }()

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error getting stdout pipe: %v", err))
        return
    }
    stderr, err := cmd.StderrPipe()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error getting stderr pipe: %v", err))
        return
    }

    scanner := bufio.NewScanner(io.MultiReader(stdout, stderr))

    err = cmd.Start()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error executing: %v", err))
        return
    }

    go func() {
        for scanner.Scan() {
            fmt.Println(string(scanner.Bytes()))
            output <- scanner.Bytes()
            fmt.Println("Sent data")
        }
    }()

    err = cmd.Wait()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error waiting for the script to complete: %v", err))
        return
    }
}

РЕДАКТИРОВАТЬ:

После некоторых размышлений, вот обновленный код. Это работает, как я ожидаю, но все еще не уверен, правильно ли я делаю. Я удалил готовый канал и диапазон по выходному каналу. Он получает все данные из вывода, отправленные через сканер при выполнении, и не блокируется, так как вывод закрыт после завершения команды. Это не печатает «привет» на Go Playground, но я получаю ожидаемое поведение в моем проекте.

Буду признателен за отзыв.

package main

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

func main() {
    output := make(chan []byte)

    cmd := exec.Command("echo", "hello")

    go execute(cmd, output)

    for data := range output {
        fmt.Println(string(data))
    }
}

func execute(cmd *exec.Cmd, output chan []byte) {
    defer close(output)

    stdout, err := cmd.StdoutPipe()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error getting stdout pipe: %v", err))
        return
    }
    cmd.Stderr = cmd.Stdout

    scanner := bufio.NewScanner(stdout)

    done := make(chan struct{})

    err = cmd.Start()
    if err != nil {
        output <- []byte(fmt.Sprintf("Error executing: %v", err))
        return
    }

    go func() {
        for scanner.Scan() {
            output <- scanner.Bytes()
        }
        done <- struct{}{}
    }()

    <-done

    err = cmd.Wait()
    if err != nil {
        fmt.Println(err)
        output <- []byte(fmt.Sprintf("Error waiting for the script to complete: %v", err))
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...