From dd1be0e0c12b39f774eae783ce0ca35cfd4d5917 Mon Sep 17 00:00:00 2001 From: Christian Rocha Date: Mon, 11 May 2026 19:27:43 -0400 Subject: [PATCH] refactor(server): derive per-host cache dir from parsed host URL Co-Authored-By: Charm Crush --- internal/cmd/root.go | 28 ++++++++++++++++++---------- internal/cmd/server.go | 12 ++++++------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/internal/cmd/root.go b/internal/cmd/root.go index a13b56fced053cf0a9f35619db19c1bc7f313b1b..c53438969d0e9f0602b763915afa4476b3a2a108 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -426,7 +426,7 @@ func ensureServer(cmd *cobra.Command, hostURL *url.URL) error { // duration of "spawn + readiness probe" and released before the caller // resumes its normal lifetime. func spawnAndWaitReady(cmd *cobra.Command, hostURL *url.URL) error { - chDir, err := perHostServerDir() + chDir, err := perHostServerDir(hostURL) if err != nil { return err } @@ -435,7 +435,7 @@ func spawnAndWaitReady(cmd *cobra.Command, hostURL *url.URL) error { // If the lock itself is unavailable, fall back to the // unsynchronized path rather than blocking the user. slog.Warn("Failed to acquire spawn lock, proceeding without single-flight", "error", err) - if err := startDetachedServer(cmd); err != nil { + if err := startDetachedServer(cmd, hostURL); err != nil { return err } return waitForServerReady(cmd.Context(), hostURL) @@ -452,7 +452,7 @@ func spawnAndWaitReady(cmd *cobra.Command, hostURL *url.URL) error { return nil } - if err := startDetachedServer(cmd); err != nil { + if err := startDetachedServer(cmd, hostURL); err != nil { return err } return waitForServerReady(cmd.Context(), hostURL) @@ -469,17 +469,25 @@ func quickHealthProbe(ctx context.Context, hostURL *url.URL) error { } // perHostServerDir returns (and creates) the cache directory used for -// per-host server state (logs, start.lock, etc.). It mirrors the path -// computed in startDetachedServer so both code paths stay in sync. -func perHostServerDir() (string, error) { - safeClientHost := safeNameRegexp.ReplaceAllString(clientHost, "_") - chDir := filepath.Join(config.GlobalCacheDir(), "server-"+safeClientHost) +// per-host server state (logs, start.lock, etc.). The path is derived +// from the parsed host URL rather than the global flag so the same key +// is computed regardless of where the host came from. +func perHostServerDir(hostURL *url.URL) (string, error) { + chDir := filepath.Join(config.GlobalCacheDir(), "server-"+safeHostName(hostURL)) if err := os.MkdirAll(chDir, 0o700); err != nil { return "", fmt.Errorf("failed to create server working directory: %v", err) } return chDir, nil } +// safeHostName returns a filesystem-safe identifier for hostURL, +// suitable for use as a directory name. It mirrors the input shape of +// the --host flag so client and server compute the same key. +func safeHostName(hostURL *url.URL) string { + return safeNameRegexp.ReplaceAllString( + hostURL.Scheme+"://"+hostURL.Host+hostURL.Path, "_") +} + // serverReadyTimeout returns the total budget for the readiness probe. // Overridable via CRUSH_SERVER_READY_TIMEOUT (parsed as a Go duration). func serverReadyTimeout() time.Duration { @@ -631,13 +639,13 @@ func restartIfStale(cmd *cobra.Command, hostURL *url.URL) (restarted bool, err e var safeNameRegexp = regexp.MustCompile(`[^a-zA-Z0-9._-]`) -func startDetachedServer(cmd *cobra.Command) error { +func startDetachedServer(cmd *cobra.Command, hostURL *url.URL) error { exe, err := os.Executable() if err != nil { return fmt.Errorf("failed to get executable path: %v", err) } - chDir, err := perHostServerDir() + chDir, err := perHostServerDir(hostURL) if err != nil { return err } diff --git a/internal/cmd/server.go b/internal/cmd/server.go index 460d5280e18930c2008db1199aac18a5b281a83d..0033632af2e547711a60dbc8d1314abf393f56a5 100644 --- a/internal/cmd/server.go +++ b/internal/cmd/server.go @@ -42,7 +42,12 @@ var serverCmd = &cobra.Command{ return fmt.Errorf("failed to load configuration: %v", err) } - logFile := filepath.Join(config.GlobalCacheDir(), "server-"+safeNameRegexp.ReplaceAllString(serverHost, "_"), "crush.log") + hostURL, err := server.ParseHostURL(serverHost) + if err != nil { + return fmt.Errorf("invalid server host: %v", err) + } + + logFile := filepath.Join(config.GlobalCacheDir(), "server-"+safeHostName(hostURL), "crush.log") if term.IsTerminal(os.Stderr.Fd()) { crushlog.Setup(logFile, debug, os.Stderr) @@ -50,11 +55,6 @@ var serverCmd = &cobra.Command{ crushlog.Setup(logFile, debug) } - hostURL, err := server.ParseHostURL(serverHost) - if err != nil { - return fmt.Errorf("invalid server host: %v", err) - } - srv := server.NewServer(cfg, hostURL.Scheme, hostURL.Host) srv.SetLogger(slog.Default()) slog.Info("Starting Crush server...", "addr", serverHost)