EnsureServer checks if the pad server is running; if not, starts it in the background.
(cfg *config.Config)
| 14 | |
| 15 | // EnsureServer checks if the pad server is running; if not, starts it in the background. |
| 16 | func EnsureServer(cfg *config.Config) error { |
| 17 | // Only an explicitly configured local client should auto-manage a local |
| 18 | // background process. Unconfigured or external clients should connect only |
| 19 | // to their configured target. |
| 20 | if !cfg.ManagesLocalServer() { |
| 21 | return nil |
| 22 | } |
| 23 | |
| 24 | if isServerHealthy(cfg.Host, cfg.Port) { |
| 25 | return nil |
| 26 | } |
| 27 | |
| 28 | // Start server as background process |
| 29 | exePath, err := os.Executable() |
| 30 | if err != nil { |
| 31 | return fmt.Errorf("find executable: %w", err) |
| 32 | } |
| 33 | |
| 34 | cmd := exec.Command(exePath, "server", "start") |
| 35 | setSysProcAttr(cmd) |
| 36 | |
| 37 | // Redirect stdout/stderr to log file |
| 38 | logFile, err := os.OpenFile(cfg.LogFile(), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) |
| 39 | if err != nil { |
| 40 | return fmt.Errorf("open log file: %w", err) |
| 41 | } |
| 42 | cmd.Stdout = logFile |
| 43 | cmd.Stderr = logFile |
| 44 | |
| 45 | if err := cmd.Start(); err != nil { |
| 46 | logFile.Close() |
| 47 | return fmt.Errorf("start server: %w", err) |
| 48 | } |
| 49 | |
| 50 | // Write PID file |
| 51 | if err := os.WriteFile(cfg.PIDFile(), []byte(strconv.Itoa(cmd.Process.Pid)), 0644); err != nil { |
| 52 | logFile.Close() |
| 53 | return fmt.Errorf("write PID file: %w", err) |
| 54 | } |
| 55 | |
| 56 | // Release the process so it doesn't become a zombie |
| 57 | cmd.Process.Release() |
| 58 | logFile.Close() |
| 59 | |
| 60 | // Wait for server to become healthy |
| 61 | for i := 0; i < 30; i++ { |
| 62 | time.Sleep(100 * time.Millisecond) |
| 63 | if isServerHealthy(cfg.Host, cfg.Port) { |
| 64 | return nil |
| 65 | } |
| 66 | } |
| 67 | |
| 68 | return fmt.Errorf("server failed to start within 3 seconds. Check %s for errors", cfg.LogFile()) |
| 69 | } |
| 70 | |
| 71 | // StopServer sends a stop signal to the background server process. |
| 72 | func StopServer(cfg *config.Config) error { |