Live video on the AT Protocol
at eli/deterministic-muxing 108 lines 2.5 kB view raw
1package proc 2 3import ( 4 "bufio" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "strings" 12 13 "golang.org/x/sync/errgroup" 14 "stream.place/streamplace/pkg/config" 15 "stream.place/streamplace/pkg/log" 16 "stream.place/streamplace/pkg/mist/mistconfig" 17) 18 19func RunMistServer(ctx context.Context, cli *config.CLI) error { 20 myself, err := os.Executable() 21 if err != nil { 22 return err 23 } 24 f, err := os.CreateTemp("", "mistconfig.json") 25 defer os.Remove(f.Name()) 26 if err != nil { 27 return err 28 } 29 conf, err := mistconfig.Generate(cli) 30 if err != nil { 31 return err 32 } 33 err = os.WriteFile(f.Name(), conf, 0644) 34 if err != nil { 35 return err 36 } 37 cmd := exec.CommandContext(ctx, myself, 38 "MistServer", 39 "-c", f.Name(), 40 "-i", "127.0.0.1", 41 "-p", fmt.Sprintf("%d", cli.MistAdminPort), 42 ) 43 cmd.Env = []string{ 44 "MIST_NO_PRETTY_LOGGING=true", 45 } 46 stdout, err := cmd.StdoutPipe() 47 if err != nil { 48 panic(err) 49 } 50 stderr, err := cmd.StderrPipe() 51 if err != nil { 52 panic(err) 53 } 54 group, ctx := errgroup.WithContext(ctx) 55 output := fmt.Println 56 for i, pipe := range []io.ReadCloser{stdout, stderr} { 57 func(i int, pipe io.ReadCloser) { 58 group.Go(func() error { 59 reader := bufio.NewReader(pipe) 60 61 for { 62 line, isPrefix, err := reader.ReadLine() 63 if err != nil { 64 if !errors.Is(err, io.EOF) { 65 _, _ = output(fmt.Sprintf("reader gave error, ending logging for fd=%d err=%s", i+1, err)) 66 } 67 line, _, err := reader.ReadLine() 68 if string(line) != "" { 69 _, _ = output(string(line)) 70 } 71 return err 72 } 73 if isPrefix { 74 _, _ = output("warning: preceding line exceeds 64k logging limit and was split") 75 } 76 if string(line) != "" { 77 level, procName, pid, path, streamName, msg, err := ParseMistLog(string(line)) 78 if err != nil { 79 log.Log(ctx, "badly formatted mist log", "message", string(line)) 80 } else { 81 log.Log(ctx, msg, 82 "level", level, 83 "procName", procName, 84 "pid", pid, 85 "streamName", streamName, 86 "caller", path, 87 ) 88 } 89 } 90 } 91 }) 92 }(i, pipe) 93 } 94 95 group.Go(func() error { 96 return cmd.Start() 97 }) 98 99 return group.Wait() 100} 101 102func ParseMistLog(str string) (string, string, string, string, string, string, error) { 103 parts := strings.Split(str, "|") 104 if len(parts) != 6 { 105 return "", "", "", "", "", "", fmt.Errorf("badly formatted mist string") 106 } 107 return parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], nil 108}