File size: 2,558 Bytes
6a7089a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package report

import (
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"runtime"
	"strings"
)

var daemonExecCommand = exec.Command

func IsDaemonInstalled() bool {
	manager, err := currentDaemonManager()
	if err != nil {
		return false
	}
	_, err = os.Stat(manager.ServicePath())
	return err == nil
}

func IsDaemonRunning() bool {
	manager, err := currentDaemonManager()
	if err != nil {
		return false
	}
	status, err := manager.Status()
	if err != nil {
		return false
	}
	return daemonStatusLooksRunning(status)
}

// Internal copy of simplified daemon manager discovery for status checks
type daemonInfo struct {
	osName string
	userID string
}

func currentDaemonManager() (daemonService, error) {
	u, err := user.Current()
	if err != nil {
		return nil, err
	}
	info := daemonInfo{osName: runtime.GOOS, userID: u.Uid}
	switch info.osName {
	case "linux":
		return &systemdStatus{userID: u.Uid}, nil
	case "darwin":
		return &launchdStatus{userID: u.Uid}, nil
	default:
		return nil, fmt.Errorf("unsupported OS")
	}
}

type daemonService interface {
	ServicePath() string
	Status() (string, error)
}

type systemdStatus struct{ userID string }

func (s *systemdStatus) ServicePath() string {
	if configHome := strings.TrimSpace(os.Getenv("XDG_CONFIG_HOME")); configHome != "" {
		return filepath.Join(configHome, "systemd", "user", "pinchtab.service")
	}
	home, _ := os.UserHomeDir()
	return filepath.Join(home, ".config", "systemd", "user", "pinchtab.service")
}
func (s *systemdStatus) Status() (string, error) {
	return runDaemonCommand("systemctl", "--user", "status", "pinchtab.service", "--no-pager")
}

type launchdStatus struct{ userID string }

func (s *launchdStatus) ServicePath() string {
	home, _ := os.UserHomeDir()
	return filepath.Join(home, "Library", "LaunchAgents", "com.pinchtab.pinchtab.plist")
}
func (s *launchdStatus) Status() (string, error) {
	return runDaemonCommand("launchctl", "print", "gui/"+s.userID+"/com.pinchtab.pinchtab")
}

func runDaemonCommand(name string, args ...string) (string, error) {
	cmd := daemonExecCommand(name, args...)
	output, err := cmd.CombinedOutput()
	trimmed := strings.TrimSpace(string(output))
	if err == nil {
		return trimmed, nil
	}
	if trimmed == "" {
		return "", fmt.Errorf("%s %s: %w", name, strings.Join(args, " "), err)
	}
	return "", fmt.Errorf("%s %s: %w: %s", name, strings.Join(args, " "), err, trimmed)
}

func daemonStatusLooksRunning(status string) bool {
	return strings.Contains(status, "state = running") ||
		strings.Contains(status, "Active: active (running)")
}