Reopen the already-running setup wizard instead of failing on a busy port
This commit is contained in:
@@ -10,11 +10,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -166,6 +168,16 @@ func runSetup(args []string) int {
|
|||||||
})
|
})
|
||||||
listener, err := server.Listen()
|
listener, err := server.Listen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// A wizard may already be running on this port (left open, or a
|
||||||
|
// second terminal). If it is ours, opening the browser is the
|
||||||
|
// friendlier outcome than failing the command.
|
||||||
|
if existing := wizardAlreadyRunning(*port); existing != "" {
|
||||||
|
logger.Info("the setup wizard is already running", "url", existing)
|
||||||
|
if !*noOpen {
|
||||||
|
openBrowser(existing)
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
logger.Error("setup wizard could not bind the loopback port", "err", err)
|
logger.Error("setup wizard could not bind the loopback port", "err", err)
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -199,3 +211,24 @@ func openBrowser(url string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wizardAlreadyRunning probes the requested loopback port and returns its URL
|
||||||
|
// when it serves the setup wizard page, or "" when it does not (another
|
||||||
|
// process, or nothing at all).
|
||||||
|
func wizardAlreadyRunning(port int) string {
|
||||||
|
url := fmt.Sprintf("http://127.0.0.1:%d/", port)
|
||||||
|
client := http.Client{Timeout: 2 * time.Second}
|
||||||
|
resp, err := client.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
body, err := io.ReadAll(io.LimitReader(resp.Body, 1<<16))
|
||||||
|
if err != nil || !strings.Contains(string(body), "SciMesh Worker · Setup") {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user