//go:build kanholec_gui package gui import ( "fmt" "os" "os/exec" "path/filepath" "runtime" ) type ServiceManager struct { binaryPath string serviceName string } func NewServiceManager() *ServiceManager { exe, _ := os.Executable() return &ServiceManager{ binaryPath: exe, serviceName: "kanholec", } } func (s *ServiceManager) IsInstalled() bool { if runtime.GOOS != "windows" { return false } cmd := exec.Command("sc", "query", s.serviceName) err := cmd.Run() return err == nil } func (s *ServiceManager) Install(configPath string) error { if runtime.GOOS != "windows" { return fmt.Errorf("service installation is only supported on Windows") } if s.IsInstalled() { return fmt.Errorf("service %q is already installed", s.serviceName) } args := []string{ "create", s.serviceName, "binPath=", fmt.Sprintf(`"%s" -c "%s"`, s.binaryPath, configPath), "DisplayName=", "kanholec - kanhole Client", "start=", "auto", "obj=", "LocalSystem", } cmd := exec.Command("sc", args...) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to install service: %s: %w", string(out), err) } descArgs := []string{"description", s.serviceName, "kanhole reverse proxy client service"} cmd = exec.Command("sc", descArgs...) cmd.Run() return nil } func (s *ServiceManager) Uninstall() error { if runtime.GOOS != "windows" { return fmt.Errorf("service management is only supported on Windows") } if !s.IsInstalled() { return fmt.Errorf("service %q is not installed", s.serviceName) } s.Stop() cmd := exec.Command("sc", "delete", s.serviceName) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to uninstall service: %s: %w", string(out), err) } return nil } func (s *ServiceManager) Start() error { if runtime.GOOS != "windows" { return fmt.Errorf("service management is only supported on Windows") } cmd := exec.Command("sc", "start", s.serviceName) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to start service: %s: %w", string(out), err) } return nil } func (s *ServiceManager) Stop() error { if runtime.GOOS != "windows" { return fmt.Errorf("service management is only supported on Windows") } cmd := exec.Command("sc", "stop", s.serviceName) out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to stop service: %s: %w", string(out), err) } return nil } func (s *ServiceManager) IsRunning() bool { if runtime.GOOS != "windows" { return false } cmd := exec.Command("sc", "query", s.serviceName) out, err := cmd.CombinedOutput() if err != nil { return false } return contains(string(out), "RUNNING") } func (s *ServiceManager) GetConfigPath() string { programData := os.Getenv("ProgramData") if programData == "" { programData = `C:\ProgramData` } return filepath.Join(programData, "kanholec", "kanholec.toml") } func contains(s, substr string) bool { return len(s) >= len(substr) && searchString(s, substr) } func searchString(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false }