package daemon import ( "errors" "fmt" "io/fs" "os" "path/filepath" "slices" "strings" "sync" "github.com/adrg/xdg" ) // EnvVars are variables which are derived based on the environment which the // process is running in. type EnvVars struct { RuntimeDirPath string // TODO should be private to this package StateDirPath string // TODO should be private to this package HTTPSocketPath string } func getRPCSocketDirPath() string { path, err := firstExistingDir( "/run", "/var/run", "/tmp", "/dev/shm", ) if err != nil { panic(fmt.Sprintf("Failed to find directory for RPC socket: %v", err)) } return path } // GetEnvVars will return the EnvVars of the current processes, as determined by // the process's environment. var GetEnvVars = sync.OnceValue(func() (v EnvVars) { // RUNTIME_DIRECTORY/STATE_DIRECTORY are used by the systemd service in // conjunction with the RuntimeDirectory/StateDirectory directives. v.RuntimeDirPath = envOr( "RUNTIME_DIRECTORY", func() string { return filepath.Join(xdg.RuntimeDir, "isle") }, ) v.StateDirPath = envOr( "STATE_DIRECTORY", func() string { return filepath.Join(xdg.StateHome, "isle") }, ) v.HTTPSocketPath = envOr( "ISLE_SOCKET_PATH", func() string { return filepath.Join(getRPCSocketDirPath(), "isle-daemon.sock") }, ) return }) //////////////////////////////////////////////////////////////////////////////// // Jigs func envOr(name string, fallback func() string) string { if v := os.Getenv(name); v != "" { return v } return fallback() } func firstExistingDir(paths ...string) (string, error) { var errs []error for _, path := range paths { stat, err := os.Stat(path) switch { case errors.Is(err, fs.ErrExist): continue case err != nil: errs = append( errs, fmt.Errorf("checking if path %q exists: %w", path, err), ) case !stat.IsDir(): errs = append( errs, fmt.Errorf("path %q exists but is not a directory", path), ) default: return path, nil } } err := fmt.Errorf( "no directory found at any of the following paths: %s", strings.Join(paths, ", "), ) if len(errs) > 0 { err = errors.Join(slices.Insert(errs, 0, err)...) } return "", err }