gitee.com/quant1x/gox@v1.21.2/daemon/daemon.go (about) 1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by 3 // license that can be found in the LICENSE file. 4 5 /* 6 Package daemon v1.0.0 for use with Go (golang) services. 7 8 Package daemon provides primitives for daemonization of golang services. In the 9 current implementation the only supported operating systems are macOS, FreeBSD, 10 Linux and Windows. Also to note, for global daemons one must have root rights to 11 install or remove the service. The only exception is macOS where there is an 12 implementation of a user daemon that can installed or removed by the current 13 user. 14 15 Example: 16 17 // Example of a daemon with echo service 18 package main 19 20 import ( 21 "fmt" 22 "log" 23 "net" 24 "os" 25 "os/signal" 26 "syscall" 27 28 "github.com/takama/daemon" 29 ) 30 31 const ( 32 33 // name of the service 34 name = "myservice" 35 description = "My Echo Service" 36 37 // port which daemon should be listen 38 port = ":9977" 39 ) 40 41 // dependencies that are NOT required by the service, but might be used 42 var dependencies = []string{"dummy.service"} 43 44 var stdlog, errlog *log.Logger 45 46 // Service has embedded daemon 47 type Service struct { 48 daemon.Daemon 49 } 50 51 // Manage by daemon commands or run the daemon 52 func (service *Service) Manage() (string, error) { 53 54 usage := "Usage: myservice install | remove | start | stop | status" 55 56 // if received any kind of command, do it 57 if len(os.Args) > 1 { 58 command := os.Args[1] 59 switch command { 60 case "install": 61 return service.Install() 62 case "remove": 63 return service.Remove() 64 case "start": 65 return service.Start() 66 case "stop": 67 return service.Stop() 68 case "status": 69 return service.Status() 70 default: 71 return usage, nil 72 } 73 } 74 75 // Do something, call your goroutines, etc 76 77 // Set up channel on which to send signal notifications. 78 // We must use a buffered channel or risk missing the signal 79 // if we're not ready to receive when the signal is sent. 80 interrupt := make(chan os.Signal, 1) 81 signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) 82 83 // Set up listener for defined host and port 84 listener, err := net.Listen("tcp", port) 85 if err != nil { 86 return "Possibly was a problem with the port binding", err 87 } 88 89 // set up channel on which to send accepted connections 90 listen := make(chan net.Conn, 100) 91 go acceptConnection(listener, listen) 92 93 // loop work cycle with accept connections or interrupt 94 // by system signal 95 for { 96 select { 97 case conn := <-listen: 98 go handleClient(conn) 99 case killSignal := <-interrupt: 100 stdlog.Println("Got signal:", killSignal) 101 stdlog.Println("Stoping listening on ", listener.Addr()) 102 listener.Close() 103 if killSignal == os.Interrupt { 104 return "Daemon was interrupted by system signal", nil 105 } 106 return "Daemon was killed", nil 107 } 108 } 109 110 // never happen, but need to complete code 111 return usage, nil 112 } 113 114 // Accept a client connection and collect it in a channel 115 func acceptConnection(listener net.Listener, listen chan<- net.Conn) { 116 for { 117 conn, err := listener.Accept() 118 if err != nil { 119 continue 120 } 121 listen <- conn 122 } 123 } 124 125 func handleClient(client net.Conn) { 126 for { 127 buf := make([]byte, 4096) 128 numbytes, err := client.Read(buf) 129 if numbytes == 0 || err != nil { 130 return 131 } 132 client.Write(buf[:numbytes]) 133 } 134 } 135 136 func init() { 137 stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime) 138 errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime) 139 } 140 141 func main() { 142 srv, err := daemon.New(name, description, daemon.SystemDaemon, dependencies...) 143 if err != nil { 144 errlog.Println("Error: ", err) 145 os.Exit(1) 146 } 147 service := &Service{srv} 148 status, err := service.Manage() 149 if err != nil { 150 errlog.Println(status, "\nError: ", err) 151 os.Exit(1) 152 } 153 fmt.Println(status) 154 } 155 156 Go daemon 157 */ 158 package daemon 159 160 import ( 161 "errors" 162 "runtime" 163 "strings" 164 ) 165 166 // Status constants. 167 const ( 168 statNotInstalled = "Service not installed" 169 ) 170 171 // Daemon interface has a standard set of methods/commands 172 type Daemon interface { 173 // GetTemplate - gets service config template 174 GetTemplate() string 175 176 // SetTemplate - sets service config template 177 SetTemplate(string) error 178 179 // Install the service into the system 180 Install(args ...string) (string, error) 181 182 // Remove the service and all corresponding files from the system 183 Remove() (string, error) 184 185 // Start the service 186 Start() (string, error) 187 188 // Stop the service 189 Stop() (string, error) 190 191 // Status - check the service status 192 Status() (string, error) 193 194 // Run - run executable service 195 Run(e Executable) (string, error) 196 } 197 198 // Executable interface defines controlling methods of executable service 199 type Executable interface { 200 // Start - non-blocking start service 201 Start() 202 // Stop - non-blocking stop service 203 Stop() 204 // Run - blocking run service 205 Run() 206 } 207 208 // Kind is type of the daemon 209 type Kind string 210 211 const ( 212 // UserAgent is a user daemon that runs as the currently logged in user and 213 // stores its property list in the user’s individual LaunchAgents directory. 214 // In other words, per-user agents provided by the user. Valid for macOS only. 215 UserAgent Kind = "UserAgent" 216 217 // GlobalAgent is a user daemon that runs as the currently logged in user and 218 // stores its property list in the users' global LaunchAgents directory. In 219 // other words, per-user agents provided by the administrator. Valid for macOS 220 // only. 221 GlobalAgent Kind = "GlobalAgent" 222 223 // GlobalDaemon is a system daemon that runs as the root user and stores its 224 // property list in the global LaunchDaemons directory. In other words, 225 // system-wide daemons provided by the administrator. Valid for macOS only. 226 GlobalDaemon Kind = "GlobalDaemon" 227 228 // SystemDaemon is a system daemon that runs as the root user. In other words, 229 // system-wide daemons provided by the administrator. Valid for FreeBSD, Linux 230 // and Windows only. 231 SystemDaemon Kind = "SystemDaemon" 232 ) 233 234 // New - Create a new daemon 235 // 236 // name: name of the service 237 // 238 // description: any explanation, what is the service, its purpose 239 // 240 // kind: what kind of daemon to create 241 func New(name, description string, kind Kind, dependencies ...string) (Daemon, error) { 242 switch runtime.GOOS { 243 case "darwin": 244 if kind == SystemDaemon { 245 return nil, errors.New("Invalid daemon kind specified") 246 } 247 case "freebsd": 248 if kind != SystemDaemon { 249 return nil, errors.New("Invalid daemon kind specified") 250 } 251 case "linux": 252 if kind != SystemDaemon { 253 return nil, errors.New("Invalid daemon kind specified") 254 } 255 case "windows": 256 if kind != SystemDaemon { 257 return nil, errors.New("Invalid daemon kind specified") 258 } 259 } 260 261 return newDaemon(strings.Join(strings.Fields(name), "_"), description, kind, dependencies) 262 }