package cli import ( "fmt" "github.com/spf13/cobra" svc "gitea.epss.net.cn/klesh/ss/internal/service" ) func newServiceCmd() *cobra.Command { cmd := &cobra.Command{ Use: "service", Short: "Manage mihomo as a system service", } cmd.AddCommand( newServiceInstallCmd(), newServiceUninstallCmd(), newServiceStartCmd(), newServiceStopCmd(), newServiceRestartCmd(), newServiceReloadCmd(), newServiceStatusCmd(), newServiceRunMacOSCmd(), newServiceRunWindowsCmd(), ) return cmd } func withNameFlag(c *cobra.Command, name *string) { c.Flags().StringVar(name, "name", "mihomo", "Service name (default: mihomo)") } func newServiceInstallCmd() *cobra.Command { var name, description string c := &cobra.Command{ Use: "install", Short: "Install mihomo as a system service", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if err := ensureRoot(); err != nil { return err } m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.InstallService(name, description) { return errSilentFailure } return nil }, } withNameFlag(c, &name) c.Flags().StringVar(&description, "description", "Mihomo proxy service", "Service description") return c } func newServiceUninstallCmd() *cobra.Command { var name string c := &cobra.Command{ Use: "uninstall", Short: "Uninstall mihomo system service", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if err := ensureRoot(); err != nil { return err } m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.UninstallService(name) { return errSilentFailure } return nil }, } withNameFlag(c, &name) return c } func newServiceStartCmd() *cobra.Command { var name string c := &cobra.Command{ Use: "start", Short: "Start mihomo system service", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if err := ensureRoot(); err != nil { return err } m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.StartService(name) { return errSilentFailure } return nil }, } withNameFlag(c, &name) return c } func newServiceStopCmd() *cobra.Command { var name string c := &cobra.Command{ Use: "stop", Short: "Stop mihomo system service", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if err := ensureRoot(); err != nil { return err } m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.StopService(name) { return errSilentFailure } return nil }, } withNameFlag(c, &name) return c } func newServiceRestartCmd() *cobra.Command { var name string c := &cobra.Command{ Use: "restart", Short: "Restart mihomo system service", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { if err := ensureRoot(); err != nil { return err } m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.RestartService(name) { return errSilentFailure } return nil }, } withNameFlag(c, &name) return c } func newServiceReloadCmd() *cobra.Command { c := &cobra.Command{ Use: "reload", Short: "Reload mihomo service configuration (via API)", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { m, err := newManagers("", "", "") if err != nil { return err } if !m.Core.ReloadService() { return errSilentFailure } return nil }, } return c } func newServiceStatusCmd() *cobra.Command { var name string c := &cobra.Command{ Use: "status", Short: "Check mihomo system service status", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, args []string) error { m, err := newManagers("", "", "") if err != nil { return err } status := m.Core.GetServiceStatus(name) fmt.Printf("Service '%s' status: %s\n", name, status) return nil }, } withNameFlag(c, &name) return c } // newServiceRunMacOSCmd is the hidden command the generated launchd plist // invokes, replacing the standalone macos_service_wrapper.py script. func newServiceRunMacOSCmd() *cobra.Command { c := &cobra.Command{ Use: "run-macos [args...]", Hidden: true, Args: cobra.MinimumNArgs(2), RunE: func(cmd *cobra.Command, args []string) error { return svc.RunMacOSWrapper(args[0], args[1], args[2:]) }, } return c } // newServiceRunWindowsCmd is the hidden command sc.exe's binPath= invokes, // replacing windows_service_wrapper.py + pywin32. func newServiceRunWindowsCmd() *cobra.Command { var name, bin, args string c := &cobra.Command{ Use: "run-windows", Hidden: true, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, cmdArgs []string) error { return svc.RunWindowsService(name, bin, args) }, } c.Flags().StringVar(&name, "name", "mihomo", "Service name") c.Flags().StringVar(&bin, "bin", "", "Path to the wrapped executable") c.Flags().StringVar(&args, "args", "", "Command line arguments for the wrapped executable") return c } // errSilentFailure signals a command failure whose message has already been // printed by the underlying manager (matching cli.py's pattern of printing // "❌ ..." then sys.exit(1) without an additional error message). var errSilentFailure = &silentError{} type silentError struct{} func (e *silentError) Error() string { return "" }