diff --git a/charts.go b/charts.go index bf1a0b7..41f9aeb 100644 --- a/charts.go +++ b/charts.go @@ -5,6 +5,9 @@ import ( "encoding/json" "fmt" "net" + "os" + "os/exec" + "runtime" "strings" "text/template" "time" @@ -207,5 +210,55 @@ func (c *Charts) Serve() { server := fasthttp.Server{ Handler: cors.DefaultHandler().CorsMiddleware(c.Handler), } + go openBrowser("http://" + c.ln.Addr().String()) _ = server.Serve(c.ln) } + +// openBrowser go/src/cmd/internal/browser/browser.go +func openBrowser(url string) bool { + var cmds [][]string + if exe := os.Getenv("BROWSER"); exe != "" { + cmds = append(cmds, []string{exe}) + } + switch runtime.GOOS { + case "darwin": + cmds = append(cmds, []string{"/usr/bin/open"}) + case "windows": + cmds = append(cmds, []string{"cmd", "/c", "start"}) + default: + if os.Getenv("DISPLAY") != "" { + // xdg-open is only for use in a desktop environment. + cmds = append(cmds, []string{"xdg-open"}) + } + } + cmds = append(cmds, + []string{"chrome"}, + []string{"google-chrome"}, + []string{"chromium"}, + []string{"firefox"}, + ) + for _, args := range cmds { + cmd := exec.Command(args[0], append(args[1:], url)...) + if cmd.Start() == nil && appearsSuccessful(cmd, 3*time.Second) { + return true + } + } + return false +} + +// appearsSuccessful reports whether the command appears to have run successfully. +// If the command runs longer than the timeout, it's deemed successful. +// If the command runs within the timeout, it's deemed successful if it exited cleanly. +func appearsSuccessful(cmd *exec.Cmd, timeout time.Duration) bool { + errc := make(chan error, 1) + go func() { + errc <- cmd.Wait() + }() + + select { + case <-time.After(timeout): + return true + case err := <-errc: + return err == nil + } +} diff --git a/main.go b/main.go index f22182c..a49b457 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ var ( host = kingpin.Flag("host", "Host header").String() contentType = kingpin.Flag("content", "Content-Type header").Short('T').String() - chartsListenAddr = kingpin.Flag("listen", "Listen addr to serve Web UI").Default(":18888").String() + chartsListenAddr = kingpin.Flag("listen", "Listen addr to serve Web UI").Default("0.0.0.0:18888").String() timeout = kingpin.Flag("timeout", "Timeout for each http request").PlaceHolder("DURATION").Duration() dialTimeout = kingpin.Flag("dial-timeout", "Timeout for dial addr").PlaceHolder("DURATION").Duration() reqWriteTimeout = kingpin.Flag("req-timeout", "Timeout for full request writing").PlaceHolder("DURATION").Duration() @@ -102,6 +102,11 @@ Example: desc += fmt.Sprintf(" using %d connection(s).", *concurrency) fmt.Println(desc) + if *chartsListenAddr != "" { + fmt.Printf("@ Real-time charts is listening on http://%s\n", *chartsListenAddr) + } + fmt.Printf("\n") + requester, err := NewRequester(*concurrency, *requests, *duration, &clientOpt) if err != nil { errAndExit(err.Error())