diff --git a/daemon/daemon.go b/daemon/daemon.go new file mode 100644 index 0000000..f47af2e --- /dev/null +++ b/daemon/daemon.go @@ -0,0 +1,50 @@ +// Package daemon provides utilities for daemons. +package daemon + +import "io" +import "os" +import "syscall" +import "strconv" +import "os/signal" + +// PidFile is a string that contains a path to a pidfile. +type PidFile string + +// Start writes to the pidfile. +func (pidfile PidFile) Start () error { + return os.WriteFile(string(pidfile), []byte(strconv.Itoa(os.Getpid())), 0644) +} + +// Close deletes the pidfile. +func (pidfile PidFile) Close () error { + return os.Remove(string(pidfile)) +} + +// Empty returns true if the object is zero value (an empty string). +func (pidfile PidFile) Empty () bool { + return pidfile == "" +} + +// OnSigint calls the specified function once sigint is recieved. This function +// does not block, and spawns a goroutine that waits. For this reason, the +// callback must be safe to call concurrently. +func OnSigint (callback func ()) { + go func () { + sigintNotify := make(chan os.Signal, 1) + signal.Notify(sigintNotify, os.Interrupt, syscall.SIGTERM) + + <-sigintNotify + callback() + } () +} + +// CloseOnSigint is like OnSigint, but takes an io.Closer. +func CloseOnSigint (closer io.Closer) { + OnSigint(func () { closer.Close() }) +} + +// ShutdownOnSigint is like OnSigint, but takes an object with a Shutdown() +// method. +func ShutdownOnSigint (shutdowner interface { Shutdown() error }) { + OnSigint(func () { shutdowner.Shutdown() }) +}