diff --git a/cmd/cli/cli.go b/cmd/cli/cli.go index 058e066..9c78909 100644 --- a/cmd/cli/cli.go +++ b/cmd/cli/cli.go @@ -241,7 +241,9 @@ func run(appCallback *AppCallback, stopCh chan struct{}) { // We need to call s.Run() as soon as possible to response to the OS manager, so it // can see ctrld is running and don't mark ctrld as failed service. go func() { - s, err := newService(p, svcConfig) + svcCmd := NewServiceCommand() + svcConfig := svcCmd.createServiceConfig() + s, err := svcCmd.newService(p, svcConfig) if err != nil { p.Fatal().Err(err).Msg("failed create new service") } @@ -1636,7 +1638,8 @@ func exchangeContextWithTimeout(c *dns.Client, timeout time.Duration, msg *dns.M // curCdUID returns the current ControlD UID used by running ctrld process. func curCdUID() string { - if s, _ := newService(&prog{}, svcConfig); s != nil { + svcCmd := NewServiceCommand() + if s, _, _ := svcCmd.initializeServiceManager(); s != nil { // Configure Windows service failure actions if err := ConfigureWindowsServiceFailureActions(ctrldServiceName); err != nil { mainLog.Load().Debug().Err(err).Msgf("failed to configure Windows service %s failure actions", ctrldServiceName) @@ -1770,7 +1773,8 @@ func doValidateCdRemoteConfig(cdUID string, fatal bool) error { // uninstallInvalidCdUID performs self-uninstallation because the ControlD device does not exist. func uninstallInvalidCdUID(p *prog, logger *ctrld.Logger, doStop bool) bool { - s, err := newService(p, svcConfig) + svcCmd := NewServiceCommand() + s, _, err := svcCmd.initializeServiceManager() if err != nil { logger.Warn().Err(err).Msg("failed to create new service") return false diff --git a/cmd/cli/commands_clients.go b/cmd/cli/commands_clients.go index 498d06a..e14db15 100644 --- a/cmd/cli/commands_clients.go +++ b/cmd/cli/commands_clients.go @@ -38,12 +38,13 @@ func NewClientsCommand() (*ClientsCommand, error) { // ListClients lists all connected clients func (cc *ClientsCommand) ListClients(cmd *cobra.Command, args []string) error { // Check service status first - sm, err := NewServiceManager() + sc := NewServiceCommand() + s, _, err := sc.initializeServiceManager() if err != nil { return err } - status, err := sm.Status() + status, err := s.Status() if errors.Is(err, service.ErrNotInstalled) { mainLog.Load().Warn().Msg("service not installed") return nil diff --git a/cmd/cli/commands_log.go b/cmd/cli/commands_log.go index 45aae91..7bf6fed 100644 --- a/cmd/cli/commands_log.go +++ b/cmd/cli/commands_log.go @@ -14,17 +14,11 @@ import ( // LogCommand handles log-related operations type LogCommand struct { - serviceManager *ServiceManager - controlClient *controlClient + controlClient *controlClient } // NewLogCommand creates a new log command handler func NewLogCommand() (*LogCommand, error) { - sm, err := NewServiceManager() - if err != nil { - return nil, err - } - dir, err := socketDir() if err != nil { return nil, fmt.Errorf("failed to find ctrld home dir: %w", err) @@ -32,8 +26,7 @@ func NewLogCommand() (*LogCommand, error) { cc := newControlClient(filepath.Join(dir, ctrldControlUnixSock)) return &LogCommand{ - serviceManager: sm, - controlClient: cc, + controlClient: cc, }, nil } @@ -45,7 +38,13 @@ func (lc *LogCommand) warnRuntimeLoggingNotEnabled() { // SendLogs sends runtime debug logs to ControlD func (lc *LogCommand) SendLogs(cmd *cobra.Command, args []string) error { - status, err := lc.serviceManager.Status() + sc := NewServiceCommand() + s, _, err := sc.initializeServiceManager() + if err != nil { + return err + } + + status, err := s.Status() if errors.Is(err, service.ErrNotInstalled) { mainLog.Load().Warn().Msg("service not installed") return nil @@ -85,7 +84,13 @@ func (lc *LogCommand) SendLogs(cmd *cobra.Command, args []string) error { // ViewLogs views current runtime debug logs func (lc *LogCommand) ViewLogs(cmd *cobra.Command, args []string) error { - status, err := lc.serviceManager.Status() + sc := NewServiceCommand() + s, _, err := sc.initializeServiceManager() + if err != nil { + return err + } + + status, err := s.Status() if errors.Is(err, service.ErrNotInstalled) { mainLog.Load().Warn().Msg("service not installed") return nil diff --git a/cmd/cli/commands_service.go b/cmd/cli/commands_service.go index e8dc1d8..dd5378a 100644 --- a/cmd/cli/commands_service.go +++ b/cmd/cli/commands_service.go @@ -35,7 +35,7 @@ func (sc *ServiceCommand) initializeServiceManager() (service.Service, *prog, er func (sc *ServiceCommand) initializeServiceManagerWithServiceConfig(svcConfig *service.Config) (service.Service, *prog, error) { p := &prog{} - s, err := newService(p, svcConfig) + s, err := sc.newService(p, svcConfig) if err != nil { return nil, nil, fmt.Errorf("failed to create service: %w", err) } @@ -44,6 +44,15 @@ func (sc *ServiceCommand) initializeServiceManagerWithServiceConfig(svcConfig *s return s, p, nil } +// newService creates a new service instance using the provided program and configuration. +func (sc *ServiceCommand) newService(p *prog, svcConfig *service.Config) (service.Service, error) { + s, err := newService(p, svcConfig) + if err != nil { + return nil, fmt.Errorf("failed to create service: %w", err) + } + return s, nil +} + // NewServiceCommand creates a new service command handler func NewServiceCommand() *ServiceCommand { return &ServiceCommand{} diff --git a/cmd/cli/commands_upgrade.go b/cmd/cli/commands_upgrade.go index b6fc472..6d73e7e 100644 --- a/cmd/cli/commands_upgrade.go +++ b/cmd/cli/commands_upgrade.go @@ -22,19 +22,11 @@ const ( // UpgradeCommand handles upgrade-related operations type UpgradeCommand struct { - serviceManager *ServiceManager } // NewUpgradeCommand creates a new upgrade command handler func NewUpgradeCommand() (*UpgradeCommand, error) { - sm, err := NewServiceManager() - if err != nil { - return nil, err - } - - return &UpgradeCommand{ - serviceManager: sm, - }, nil + return &UpgradeCommand{}, nil } // Upgrade performs the upgrade operation @@ -53,19 +45,10 @@ func (uc *UpgradeCommand) Upgrade(cmd *cobra.Command, args []string) error { mainLog.Load().Fatal().Err(err).Msg("failed to get current ctrld binary path") } - // Create service config with executable path - sc := &service.Config{ - Name: ctrldServiceName, - DisplayName: "Control-D Helper Service", - Description: "A highly configurable, multi-protocol DNS forwarding proxy", - Option: service.KeyValue{}, - Executable: bin, - } - readConfig(false) v.Unmarshal(&cfg) - p := &prog{} - s, err := newService(p, sc) + svcCmd := NewServiceCommand() + s, p, err := svcCmd.initializeServiceManager() if err != nil { mainLog.Load().Error().Msg(err.Error()) return nil diff --git a/cmd/cli/prog.go b/cmd/cli/prog.go index 8f56b83..c847ebf 100644 --- a/cmd/cli/prog.go +++ b/cmd/cli/prog.go @@ -79,13 +79,6 @@ var logf = func(format string, args ...any) { //lint:ignore U1000 use in newLoopbackOSConfigurator var noopLogf = func(format string, args ...any) {} -var svcConfig = &service.Config{ - Name: ctrldServiceName, - DisplayName: "Control-D Helper Service", - Description: "A highly configurable, multi-protocol DNS forwarding proxy", - Option: service.KeyValue{}, -} - var useSystemdResolved = false type prog struct {