Documentation
¶
Overview ¶
Package service manages the git-treeline router as a system service. Supports macOS LaunchAgents and Linux systemd user units.
When GTL_HOME is set, labels and paths are suffixed with ".dev" to avoid colliding with the production install.
Index ¶
- Constants
- func Bounce(wait time.Duration) error
- func CleanHosts() error
- func GeneratePfAnchor(routerPort int) string
- func GeneratePlist(gtlPath string) (string, error)
- func GenerateUnit(gtlPath string) (string, error)
- func Install(gtlPath string, port int) (string, error)
- func InstallPfReloadDaemon() error
- func InstallPortForward(routerPort int) error
- func InstalledBinaryPath() string
- func IsInstalled() bool
- func IsPfReloadDaemonInstalled() bool
- func IsPortForwardConfigured() bool
- func IsRunning() bool
- func LaunchLabel() string
- func ManagedHosts() ([]string, error)
- func MissingHosts(expected []string) []string
- func NeedsHostsSync(expected []string) bool
- func PfReloadDaemonPath() string
- func PlistPath() string
- func Reload(wait time.Duration) error
- func ReloadPortForward() error
- func RouterVersionFile() string
- func RunningPID() int
- func RunningRouterVersion() string
- func StableExecutablePath() (string, error)
- func SyncHosts(hostnames []string) error
- func SystemdUnit() string
- func Uninstall() error
- func UninstallPfReloadDaemon() error
- func UninstallPortForward() error
- func UnitPath() string
- func WriteRouterVersion(version string)
- type HealthCheck
- type PortForwardStatus
Constants ¶
const DefaultBounceTimeout = 5 * time.Second
DefaultBounceTimeout is the default deadline for verifying that a bounced router has come back up (i.e. written its version file).
const PfReloadDaemonLabel = "dev.treeline.pfreload"
PfReloadDaemonLabel is the launchd label for our boot-time pf reloader. Lives in /Library/LaunchDaemons (system-level, runs as root). The daemon exists solely so pf rules survive a reboot — macOS loads pf.conf at boot via Apple's own LaunchDaemon but does NOT enable pf. Our daemon re-runs `pfctl -ef /etc/pf.conf` to enable pf and load our rdr rule.
The daemon invokes Apple's signed /sbin/pfctl directly — it does NOT reference our gtl binary, so no notarization or code-signing concerns apply. The plist itself is a static config file.
Variables ¶
This section is empty.
Functions ¶
func Bounce ¶ added in v0.40.0
Bounce restarts the running router service so it picks up changes that don't require a new service definition (e.g. the `gtl` binary on disk has been upgraded by Homebrew, but the launchd-managed process is still the old build). On macOS this is `launchctl kickstart -k`; on Linux it is `systemctl --user restart`.
Bounce verifies the restart by waiting for the router to write a fresh `router.version` file. Returns an error if no new write is observed within `wait`.
Use Reload (not Bounce) when the service definition itself changed.
func CleanHosts ¶
func CleanHosts() error
CleanHosts removes all git-treeline entries from /etc/hosts.
func GeneratePfAnchor ¶
GeneratePfAnchor returns the pf anchor content for testing.
func GeneratePlist ¶
GeneratePlist returns the plist XML content as a string (for testing).
func GenerateUnit ¶
GenerateUnit returns the systemd unit content as a string (for testing).
func Install ¶
Install writes a service definition and activates it. Returns the path to the written file.
func InstallPfReloadDaemon ¶ added in v0.40.1
func InstallPfReloadDaemon() error
InstallPfReloadDaemon writes the LaunchDaemon plist to /Library/LaunchDaemons and bootstraps it so it runs at every boot. Requires sudo. Idempotent — safe to call when already installed.
macOS-only. On other platforms returns nil (no-op) since iptables on Linux distros generally persist their own rules via netfilter-persistent or iptables-save and don't need a separate boot service.
func InstallPortForward ¶
InstallPortForward sets up an OS-level redirect from port 443 to the router port so users can access worktrees at https://{branch}.localhost without typing a port number. Requires sudo.
func InstalledBinaryPath ¶
func InstalledBinaryPath() string
InstalledBinaryPath reads the LaunchAgent plist (or systemd unit) and returns the binary path embedded in the service definition. Returns "" if the service file doesn't exist or can't be parsed.
func IsInstalled ¶ added in v0.40.1
func IsInstalled() bool
IsInstalled reports whether the service definition exists on disk for the current user, regardless of whether it's currently running. Used by `gtl serve restart --if-installed` so tooling integrations (Homebrew post_install) can safely be a no-op on machines where the user never installed the router.
func IsPfReloadDaemonInstalled ¶ added in v0.40.1
func IsPfReloadDaemonInstalled() bool
IsPfReloadDaemonInstalled reports whether our LaunchDaemon plist exists on disk. Read-only; no sudo needed.
func IsPortForwardConfigured ¶
func IsPortForwardConfigured() bool
IsPortForwardConfigured checks whether the port 443 redirect is in place on disk (pf.conf or iptables rules saved). Note: this can return true when the rules are not actually loaded into the kernel — see PortForwardActive for an authoritative check.
func LaunchLabel ¶
func LaunchLabel() string
func ManagedHosts ¶
ManagedHosts returns the hostnames currently in the managed block.
func MissingHosts ¶
MissingHosts returns hostnames from expected that are not yet present in the managed /etc/hosts block. If the hosts file cannot be read, all expected hostnames are returned (conservative: assume sync is needed).
func NeedsHostsSync ¶
NeedsHostsSync reports whether macOS hosts file needs updating for the given set of expected hostnames.
func PfReloadDaemonPath ¶ added in v0.40.1
func PfReloadDaemonPath() string
PfReloadDaemonPath returns the on-disk plist path. macOS-only; on other platforms returns "" since we don't ship this daemon there.
func Reload ¶ added in v0.40.0
Reload tears down the existing service registration and re-registers it from the on-disk service definition. Use this after writing a new plist or systemd unit so launchd/systemd actually pick up the changes.
On macOS that's `launchctl bootout` followed by `launchctl bootstrap`. On Linux that's `systemctl --user daemon-reload` followed by `restart`.
func ReloadPortForward ¶ added in v0.40.0
func ReloadPortForward() error
ReloadPortForward re-applies the port-forwarding rules from disk into the running kernel ruleset. Useful after a reboot/network change wiped them without changing pf.conf or iptables-save state.
macOS requires sudo. Linux uses the same mechanism as install (currently re-running iptables rules); we delegate to the same install path because it is idempotent.
func RouterVersionFile ¶
func RouterVersionFile() string
RouterVersionFile returns the path to the file where the running router records its version on startup.
func RunningPID ¶ added in v0.40.0
func RunningPID() int
RunningPID returns the PID of the running service process, or 0 if it cannot be determined. On macOS, parses `launchctl print` output for the authoritative PID launchd has registered for our label. On Linux, reads the MainPID from `systemctl --user show`.
func RunningRouterVersion ¶
func RunningRouterVersion() string
RunningRouterVersion reads the version recorded by the running router. Returns "" if the file doesn't exist or can't be read.
func StableExecutablePath ¶
StableExecutablePath returns a path suitable for embedding in a service definition (launchd plist, systemd unit). On Homebrew installs, os.Executable() resolves symlinks and returns a versioned Cellar path (e.g. /opt/homebrew/Cellar/git-treeline/0.38.0/bin/gtl) that breaks after `brew upgrade`. This function detects that case and returns the stable symlink path instead (e.g. /opt/homebrew/bin/gtl).
func SyncHosts ¶
SyncHosts updates /etc/hosts with entries for the given hostnames. On macOS this fixes Safari's failure to resolve *.localhost. For custom TLDs (non-.localhost), this is required on all platforms. Requires sudo.
func SystemdUnit ¶
func SystemdUnit() string
func Uninstall ¶
func Uninstall() error
Uninstall stops the service and removes the definition file.
func UninstallPfReloadDaemon ¶ added in v0.40.1
func UninstallPfReloadDaemon() error
UninstallPfReloadDaemon removes the LaunchDaemon. Symmetric with install — requires sudo. Idempotent.
func UninstallPortForward ¶
func UninstallPortForward() error
UninstallPortForward removes the OS-level port 443 redirect.
func WriteRouterVersion ¶
func WriteRouterVersion(version string)
WriteRouterVersion writes the current version to the version file. Called by the router on startup.
Types ¶
type HealthCheck ¶
type HealthCheck struct {
Name string `json:"name"`
Status string `json:"status"` // "ok", "warn", "error"
Detail string `json:"detail"`
Fix string `json:"fix,omitempty"`
}
HealthCheck represents a single doctor check result.
func CheckHealth ¶
func CheckHealth(routerPort int, cliVersion string) []HealthCheck
CheckHealth runs all serve-related health checks and returns the results.
type PortForwardStatus ¶ added in v0.40.0
type PortForwardStatus struct {
// ConfiguredOnDisk is true when pf.conf (macOS) or saved iptables rules
// (Linux) reference our redirect.
ConfiguredOnDisk bool
// LoadedInKernel is true when the running ruleset includes our redirect.
// On macOS this requires both pf to be enabled AND our rdr rule to be
// in the active anchor.
LoadedInKernel bool
// PfEnabled (macOS only) reports the running pf status. Meaningful only
// when PfStateKnown is true. Meaningless on Linux.
PfEnabled bool
// PfStateKnown (macOS only) is true when `pfctl -s info` succeeded —
// without it, callers must not interpret PfEnabled=false as proof that
// pf is actually disabled. On modern macOS, `pfctl -s info` may
// require sudo; without it, returns an error.
PfStateKnown bool
// KernelStateKnown is true when we successfully queried the kernel rule
// list. On macOS, `pfctl -s nat` (and per-anchor variants) typically
// require sudo — if our calls fail with permission errors, this is
// false, and LoadedInKernel should not be trusted as authoritative.
KernelStateKnown bool
// Detail is a one-line human-readable summary, or "" when everything is
// healthy.
Detail string
}
PortForwardStatus reports whether the port-forwarding rules are not just configured on disk but actually loaded in the kernel right now. This is what determines whether traffic to :443 will reach the router.
func CheckPortForward ¶ added in v0.40.0
func CheckPortForward(routerPort int) PortForwardStatus
CheckPortForward queries the running kernel state of our port-forwarding rules. Requires sudo on macOS for full accuracy; without sudo, falls back to the on-disk check and returns LoadedInKernel = false (unknown).
routerPort is the port the rdr should forward to; used to detect a rule that exists but points to the wrong port.