package main import ( "context" "fmt" "io" "log" "net" "net/http" "os" "os/exec" "os/signal" "runtime" "strings" "syscall" "time" ) // language=html const injectScript = ` ` func main() { if err := run(); err != nil { log.Fatal(err) } } func newHandler(html string, onShutdown func()) *http.ServeMux { handler := http.NewServeMux() handler.HandleFunc("POST /shutdown", func(w http.ResponseWriter, r *http.Request) { onShutdown() }) handler.HandleFunc("GET /", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.Write([]byte(html)) }) return handler } func run() error { html, err := io.ReadAll(os.Stdin) if err != nil { return fmt.Errorf("failed to read HTML from stdin: %w", err) } htmlStr := string(html) if strings.Contains(htmlStr, "") { htmlStr = strings.ReplaceAll(string(html), "", injectScript+"") } else { htmlStr += injectScript } listener, err := net.Listen("tcp", ":0") if err != nil { return fmt.Errorf("failed to create listener: %w", err) } ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer cancel() port := listener.Addr().(*net.TCPAddr).Port server := &http.Server{Addr: listener.Addr().String()} server.Handler = newHandler(htmlStr, func() { cancel() }) servedURL := fmt.Sprintf("http://localhost:%d", port) go func() { log.Printf("serving at %s", servedURL) if err := server.Serve(listener); err != nil && err != http.ErrServerClosed { log.Fatalf("failed to serve: %v", err) } }() go func() { // wait for server to start time.Sleep(250 * time.Millisecond) if err := openBrowser(servedURL); err != nil { log.Fatalf("failed to open browser: %v", err) } }() <-ctx.Done() log.Printf("shutting down server") if err := server.Shutdown(ctx); err != nil { return fmt.Errorf("failed to shutdown server: %w", err) } return nil } func openBrowser(url string) error { var cmd *exec.Cmd switch runtime.GOOS { case "darwin": cmd = exec.Command("open", url) case "linux": cmd = exec.Command("xdg-open", url) case "windows": cmd = exec.Command("cmd", "/c", "start", url) default: return fmt.Errorf("invalid URL: %s", url) } return cmd.Run() }