github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zcli/service.go (about) 1 package zcli 2 3 import ( 4 "context" 5 "log" 6 "os" 7 "strings" 8 "sync" 9 "time" 10 11 "github.com/sohaha/zlsgo/zerror" 12 "github.com/sohaha/zlsgo/zfile" 13 "github.com/sohaha/zlsgo/zshell" 14 "github.com/sohaha/zlsgo/zutil" 15 "github.com/sohaha/zlsgo/zutil/daemon" 16 ) 17 18 type ( 19 app struct { 20 run func() 21 status bool 22 } 23 serviceStop struct { 24 } 25 serviceStart struct { 26 } 27 serviceRestart struct { 28 } 29 serviceInstall struct { 30 } 31 serviceUnInstall struct { 32 } 33 serviceStatus struct { 34 } 35 ) 36 37 var ( 38 service daemon.ServiceIface 39 serviceErr error 40 once sync.Once 41 ) 42 43 var s = make(chan struct{}) 44 45 func (a *app) Start(daemon.ServiceIface) error { 46 a.status = true 47 err := make(chan error, 1) 48 go func() { 49 err <- zerror.TryCatch(func() error { 50 a.run() 51 return nil 52 }) 53 s <- struct{}{} 54 }() 55 return <-err 56 } 57 58 func (a *app) Stop(daemon.ServiceIface) error { 59 if !a.status { 60 return nil 61 } 62 ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) 63 defer cancel() 64 select { 65 case <-s: 66 case <-ctx.Done(): 67 // return errors.New("forced timeout") 68 } 69 return nil 70 } 71 72 func (*serviceStatus) Flags(_ *Subcommand) { 73 CheckErr(serviceErr, true) 74 } 75 76 func (*serviceStatus) Run(_ []string) { 77 log.Printf("%s: %s\n", service.String(), service.Status()) 78 } 79 80 func (*serviceInstall) Flags(_ *Subcommand) { 81 CheckErr(serviceErr, true) 82 } 83 84 func (*serviceInstall) Run(_ []string) { 85 CheckErr(service.Install(), true) 86 CheckErr(service.Start(), true) 87 } 88 89 func (*serviceUnInstall) Flags(_ *Subcommand) { 90 CheckErr(serviceErr, true) 91 } 92 93 func (*serviceUnInstall) Run(_ []string) { 94 CheckErr(service.Uninstall(), true) 95 } 96 97 func (*serviceStart) Flags(_ *Subcommand) { 98 CheckErr(serviceErr, true) 99 } 100 101 func (*serviceStart) Run(_ []string) { 102 CheckErr(service.Start(), true) 103 } 104 105 func (*serviceStop) Flags(_ *Subcommand) { 106 CheckErr(serviceErr, true) 107 } 108 109 func (*serviceStop) Run(_ []string) { 110 CheckErr(service.Stop(), true) 111 } 112 113 func (*serviceRestart) Flags(_ *Subcommand) { 114 CheckErr(serviceErr, true) 115 } 116 117 func (*serviceRestart) Run(_ []string) { 118 CheckErr(service.Restart(), true) 119 } 120 121 // LaunchServiceRun Launch Service and run 122 func LaunchServiceRun(name string, description string, fn func(), config ...*daemon.Config) error { 123 _, _ = LaunchService(name, description, fn, config...) 124 Parse() 125 if *flagDetach { 126 return zshell.BgRun(strings.Join(runCmd, " ")) 127 } 128 if serviceErr != nil && (serviceErr != daemon.ErrNoServiceSystemDetected && !daemon.IsPermissionError(serviceErr)) { 129 return serviceErr 130 } 131 if service == nil { 132 fn() 133 return nil 134 } 135 return service.Run() 136 } 137 138 // LaunchService Launch Service 139 func LaunchService(name string, description string, fn func(), config ...*daemon.Config) (daemon.ServiceIface, error) { 140 once.Do(func() { 141 userService := false 142 if zutil.IsMac() { 143 userService = true 144 } 145 daemonConfig := &daemon.Config{ 146 Name: name, 147 Description: description, 148 Options: map[string]interface{}{ 149 "UserService": userService, 150 }, 151 } 152 if len(os.Args) > 2 { 153 daemonConfig.Arguments = os.Args[2:] 154 } 155 156 if len(config) > 0 { 157 nconf := config[0] 158 if nconf.Name == "" { 159 nconf.Name = name 160 } 161 if nconf.Description == "" { 162 nconf.Description = description 163 } 164 if len(nconf.Options) == 0 { 165 nconf.Options = daemonConfig.Options 166 } 167 if len(nconf.Arguments) == 0 { 168 nconf.Arguments = daemonConfig.Arguments 169 } 170 daemonConfig = nconf 171 } 172 173 // The file path is redirected to the current execution file path 174 _, gogccflags, _, _ := zshell.Run("go env GOGCCFLAGS") 175 if !strings.Contains( 176 gogccflags, zfile.RealPath(zfile.ProgramPath()+"../../../..")) { 177 zfile.ProjectPath = zfile.ProgramPath() 178 } 179 180 service, serviceErr = daemon.New(&app{ 181 run: fn, 182 }, daemonConfig) 183 184 Add("install", GetLangText("install"), &serviceInstall{}) 185 Add("uninstall", GetLangText("uninstall"), &serviceUnInstall{}) 186 Add("status", GetLangText("status"), &serviceStatus{}) 187 Add("start", GetLangText("start"), &serviceStart{}) 188 Add("stop", GetLangText("stop"), &serviceStop{}) 189 Add("restart", GetLangText("restart"), &serviceRestart{}) 190 }) 191 192 return service, serviceErr 193 }