daemon

package
v0.22.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 22, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package daemon implements background-process lifecycle for wick: Start/Stop/Restart/Status with a PID file. Targets headless environments where the system tray is not usable (Termux, SSH sessions, Linux servers).

The daemon re-execs the same binary with the existing `all` subcommand (server + worker in one process), detached from the caller's terminal so the parent shell can exit without killing it. Output goes to a log file alongside the PID file so users can tail it after start.

Index

Constants

This section is empty.

Variables

View Source
var ErrAlreadyRunning = errors.New("daemon already running")

ErrAlreadyRunning signals Start was called while a live daemon was already recorded in the PID file.

View Source
var ErrNotInstalled = errors.New("service not installed")

ErrNotInstalled signals UninstallService was called when no service integration was found.

View Source
var ErrNotRunning = errors.New("daemon not running")

ErrNotRunning signals Stop was called with no live daemon recorded.

Functions

func InstallService

func InstallService(p Paths, appName string) error

InstallService registers the binary to launch at user login / boot. Routing depends on the runtime environment:

GUI present (Win / Mac / desktop Linux) → forwards to the same
internal/autostart entry the tray uses AND flips
userconfig.AutoStartApp=true so the tray's `Auto-start app at
login` checkbox stays in sync with what the CLI did.

Headless (Termux, Linux server / RPi) → writes a daemon-style
auto-start unit (systemd-user or Termux:Boot script) that runs
`<exe> all` directly.

Re-running install over an existing install is safe — the GUI path rewrites the autostart entry, the headless path rewrites the unit.

func ReadPID added in v0.16.13

func ReadPID(p Paths) (int, time.Time, error)

ReadPID returns the PID recorded in p.PIDFile plus the file mtime (best-effort start time). Exported for the systemd jalur in `status`, where Check() can't be used — the systemd-spawned process self-writes run.pid but no `start` parent verified it. os.ErrNotExist is returned verbatim when the file is absent.

func Restart

func Restart(p Paths, timeout time.Duration, args []string) (int, error)

Restart stops the running daemon (if any) then starts a fresh instance with the supplied argv tail.

func SelfRegister added in v0.16.13

func SelfRegister(p Paths, src Source) error

SelfRegister writes the running process's own PID + source to the daemon files. Called from `<app> all` on boot so the PID file is accurate no matter who spawned the process — systemd, the daemon parent, or a direct foreground run. Idempotent across restarts.

func ServiceActive added in v0.16.13

func ServiceActive(appName string) bool

ServiceActive reports whether systemctl considers the unit active (running). Best-effort; used by `status` for the systemd jalur.

func ServiceCtl added in v0.16.13

func ServiceCtl(appName, verb string) error

ServiceCtl runs `systemctl --user <verb> <app>.service` and returns the combined error. verb is start | stop | restart. Intentional stop/restart here means systemd does NOT treat the exit as a failure, so Restart=on-failure won't respawn behind our back.

func ServiceManaged added in v0.16.13

func ServiceManaged(appName string) bool

ServiceManaged reports whether a systemd-user unit for appName is installed AND enabled — i.e. systemd is the authority for this app's lifecycle, so start/stop/restart must delegate to systemctl rather than spawn a second PID-file daemon. False on Termux (no systemd) and when the unit file is absent.

func Start

func Start(p Paths, args []string) (int, error)

Start spawns the binary with the supplied subcommand detached from the caller's terminal, redirecting stdout+stderr to the daemon log file. Returns ErrAlreadyRunning if a live daemon is already recorded in the PID file.

args is the full argv tail passed to the spawned binary — callers choose between "all" (headless server + worker, default daemon mode) and "tray" (interactive tray icon on GUI hosts).

func Stop

func Stop(p Paths, timeout time.Duration) error

Stop sends SIGTERM (or the OS equivalent) to the running daemon and waits up to timeout for it to exit. Falls back to a force kill if the process is still alive at the deadline. ErrNotRunning is returned if no live daemon was recorded.

func TailLog

func TailLog(p Paths, n int64, w io.Writer) error

TailLog copies the last n bytes of the daemon log to w. Convenience for `status` output. Returns nil if the log doesn't exist yet.

func UninstallService

func UninstallService(p Paths, appName string) error

UninstallService removes whichever auto-start mechanism is in place. ErrNotInstalled is returned if nothing was registered. On the GUI path it also flips userconfig.AutoStartApp=false so the tray's checkbox follows the CLI.

func WriteSource added in v0.16.13

func WriteSource(p Paths, src Source)

WriteSource records the spawn Source next to run.pid. Best-effort — a failure here only degrades `status` reporting, never blocks boot.

Types

type Paths

type Paths struct {
	Dir     string // ~/.<appname>/
	PIDFile string // run.pid
	LogFile string // daemon.log
	ExePath string // resolved path to the currently running binary
}

Paths bundles the per-app filesystem locations used by the daemon.

func ResolvePaths

func ResolvePaths(appName string) (Paths, error)

ResolvePaths returns the canonical daemon paths for an app. The directory is created if missing.

type ServiceState

type ServiceState struct {
	Installed bool   // unit / script / login-item is registered with the OS
	Active    bool   // best-effort runtime check; not always supported
	Path      string // canonical location of the registration
	Backend   string // "autostart-gui", "systemd-user", "termux-boot", "headless-unsupported"
	Note      string // free-form hint shown in `service status`
}

ServiceState describes whether per-OS auto-start integration is installed and (where the platform exposes it) whether the service is currently active.

func ServiceStatus

func ServiceStatus(p Paths, appName string) (ServiceState, error)

ServiceStatus reports the registration state for whichever backend applies to the current host. On GUI hosts Installed/Active reflects the actual OS entry (what fires at login); a separate note flags when userconfig.AutoStartApp disagrees so the user can spot drift.

type Source added in v0.16.13

type Source string

Source labels the spawn origin of a running daemon, recorded in the run.source file next to run.pid so `status` can report it without guessing.

const (
	SourceCLI     Source = "cli"     // direct `<app> all` / `<app> start` from a shell
	SourceSystemd Source = "systemd" // spawned by the systemd-user unit
	SourceTray    Source = "tray"    // GUI tray started the server in-process
	SourceUnknown Source = "unknown"
)

func DetectSource added in v0.16.13

func DetectSource() Source

DetectSource inspects the current process environment to decide how it was spawned. systemd injects INVOCATION_ID into every unit it starts, which is the most reliable signal that systemd owns this process. The caller (`<app> all`) records the result so later `status`/`stop` calls know the supervisor without re-deriving it from a different process.

func ReadSource added in v0.16.13

func ReadSource(p Paths) Source

ReadSource returns the recorded spawn Source, or SourceUnknown when the file is missing / unreadable.

type Status

type Status struct {
	Running bool
	PID     int
	Started time.Time // mtime of PID file as a best-effort start time
	LogFile string
	PIDFile string
}

Status reflects the running state of the daemon.

func Check

func Check(p Paths) (Status, error)

Check inspects the PID file and returns the current daemon state. Stale PID files (process no longer alive) are reported as not running; callers may then proceed with Start without manually cleaning up.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL