61 lines
1.3 KiB
Go
61 lines
1.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"github.com/qdm12/gluetun/internal/command"
|
|
)
|
|
|
|
func runCommand(ctx context.Context, cmder Cmder, logger Logger,
|
|
commandTemplate string, ports []uint16,
|
|
) (err error) {
|
|
portStrings := make([]string, len(ports))
|
|
for i, port := range ports {
|
|
portStrings[i] = fmt.Sprint(int(port))
|
|
}
|
|
portsString := strings.Join(portStrings, ",")
|
|
commandString := strings.ReplaceAll(commandTemplate, "{{PORTS}}", portsString)
|
|
commandString = strings.ReplaceAll(commandString, "{{PORT}}", portStrings[0])
|
|
args, err := command.Split(commandString)
|
|
if err != nil {
|
|
return fmt.Errorf("parsing command: %w", err)
|
|
}
|
|
|
|
cmd := exec.CommandContext(ctx, args[0], args[1:]...) // #nosec G204
|
|
stdout, stderr, waitError, err := cmder.Start(cmd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
streamCtx, streamCancel := context.WithCancel(context.Background())
|
|
streamDone := make(chan struct{})
|
|
go streamLines(streamCtx, streamDone, logger, stdout, stderr)
|
|
|
|
err = <-waitError
|
|
streamCancel()
|
|
<-streamDone
|
|
return err
|
|
}
|
|
|
|
func streamLines(ctx context.Context, done chan<- struct{},
|
|
logger Logger, stdout, stderr <-chan string,
|
|
) {
|
|
defer close(done)
|
|
|
|
var line string
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case line = <-stdout:
|
|
logger.Info(line)
|
|
case line = <-stderr:
|
|
logger.Error(line)
|
|
}
|
|
}
|
|
}
|