diff --git a/README.md b/README.md index 8bc22e0..c673900 100644 --- a/README.md +++ b/README.md @@ -1,182 +1,182 @@ -Go Daemon -========= +# Go Daemon A daemon package for use with Go (golang) services with no dependencies [![GoDoc](https://godoc.org/github.com/takama/daemon?status.svg)](https://godoc.org/github.com/takama/daemon) -### Examples +## Examples + +### Simplest example (just install self as daemon) -Simplest example (just install self as daemon): ```go package main import ( - "fmt" - "log" + "fmt" + "log" - "github.com/takama/daemon" + "github.com/takama/daemon" ) func main() { - service, err := daemon.New("name", "description") - if err != nil { - log.Fatal("Error: ", err) - } - status, err := service.Install() - if err != nil { - log.Fatal(status, "\nError: ", err) - } - fmt.Println(status) + service, err := daemon.New("name", "description") + if err != nil { + log.Fatal("Error: ", err) + } + status, err := service.Install() + if err != nil { + log.Fatal(status, "\nError: ", err) + } + fmt.Println(status) } ``` -Real example: +### Real example + ```go // Example of a daemon with echo service package main import ( - "fmt" - "log" - "net" - "os" - "os/signal" - "syscall" - - "github.com/takama/daemon" + "fmt" + "log" + "net" + "os" + "os/signal" + "syscall" + + "github.com/takama/daemon" ) const ( - // name of the service - name = "myservice" - description = "My Echo Service" + // name of the service + name = "myservice" + description = "My Echo Service" - // port which daemon should be listen - port = ":9977" + // port which daemon should be listen + port = ":9977" ) -// dependencies that are NOT required by the service, but might be used +// dependencies that are NOT required by the service, but might be used var dependencies = []string{"dummy.service"} var stdlog, errlog *log.Logger // Service has embedded daemon type Service struct { - daemon.Daemon + daemon.Daemon } // Manage by daemon commands or run the daemon func (service *Service) Manage() (string, error) { - usage := "Usage: myservice install | remove | start | stop | status" - - // if received any kind of command, do it - if len(os.Args) > 1 { - command := os.Args[1] - switch command { - case "install": - return service.Install() - case "remove": - return service.Remove() - case "start": - return service.Start() - case "stop": - return service.Stop() - case "status": - return service.Status() - default: - return usage, nil - } - } - - // Do something, call your goroutines, etc - - // Set up channel on which to send signal notifications. - // We must use a buffered channel or risk missing the signal - // if we're not ready to receive when the signal is sent. - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) - - // Set up listener for defined host and port - listener, err := net.Listen("tcp", port) - if err != nil { - return "Possibly was a problem with the port binding", err - } - - // set up channel on which to send accepted connections - listen := make(chan net.Conn, 100) - go acceptConnection(listener, listen) - - // loop work cycle with accept connections or interrupt - // by system signal - for { - select { - case conn := <-listen: - go handleClient(conn) - case killSignal := <-interrupt: - stdlog.Println("Got signal:", killSignal) - stdlog.Println("Stoping listening on ", listener.Addr()) - listener.Close() - if killSignal == os.Interrupt { - return "Daemon was interruped by system signal", nil - } - return "Daemon was killed", nil - } - } - - // never happen, but need to complete code - return usage, nil + usage := "Usage: myservice install | remove | start | stop | status" + + // if received any kind of command, do it + if len(os.Args) > 1 { + command := os.Args[1] + switch command { + case "install": + return service.Install() + case "remove": + return service.Remove() + case "start": + return service.Start() + case "stop": + return service.Stop() + case "status": + return service.Status() + default: + return usage, nil + } + } + + // Do something, call your goroutines, etc + + // Set up channel on which to send signal notifications. + // We must use a buffered channel or risk missing the signal + // if we're not ready to receive when the signal is sent. + interrupt := make(chan os.Signal, 1) + signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM) + + // Set up listener for defined host and port + listener, err := net.Listen("tcp", port) + if err != nil { + return "Possibly was a problem with the port binding", err + } + + // set up channel on which to send accepted connections + listen := make(chan net.Conn, 100) + go acceptConnection(listener, listen) + + // loop work cycle with accept connections or interrupt + // by system signal + for { + select { + case conn := <-listen: + go handleClient(conn) + case killSignal := <-interrupt: + stdlog.Println("Got signal:", killSignal) + stdlog.Println("Stoping listening on ", listener.Addr()) + listener.Close() + if killSignal == os.Interrupt { + return "Daemon was interruped by system signal", nil + } + return "Daemon was killed", nil + } + } + + // never happen, but need to complete code + return usage, nil } // Accept a client connection and collect it in a channel func acceptConnection(listener net.Listener, listen chan<- net.Conn) { - for { - conn, err := listener.Accept() - if err != nil { - continue - } - listen <- conn - } + for { + conn, err := listener.Accept() + if err != nil { + continue + } + listen <- conn + } } func handleClient(client net.Conn) { - for { - buf := make([]byte, 4096) - numbytes, err := client.Read(buf) - if numbytes == 0 || err != nil { - return - } - client.Write(buf[:numbytes]) - } + for { + buf := make([]byte, 4096) + numbytes, err := client.Read(buf) + if numbytes == 0 || err != nil { + return + } + client.Write(buf[:numbytes]) + } } func init() { - stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime) - errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime) + stdlog = log.New(os.Stdout, "", log.Ldate|log.Ltime) + errlog = log.New(os.Stderr, "", log.Ldate|log.Ltime) } func main() { - srv, err := daemon.New(name, description, dependencies...) - if err != nil { - errlog.Println("Error: ", err) - os.Exit(1) - } - service := &Service{srv} - status, err := service.Manage() - if err != nil { - errlog.Println(status, "\nError: ", err) - os.Exit(1) - } - fmt.Println(status) + srv, err := daemon.New(name, description, dependencies...) + if err != nil { + errlog.Println("Error: ", err) + os.Exit(1) + } + service := &Service{srv} + status, err := service.Manage() + if err != nil { + errlog.Println(status, "\nError: ", err) + os.Exit(1) + } + fmt.Println(status) } ``` -Cron example: -``` -See example/cron_example.go -``` +### Cron example + +See `examples/cron/cron_job.go` ## Contributors (unsorted) @@ -196,8 +196,10 @@ See example/cron_example.go - [1for](https://github.com/1for) - [okamura](https://github.com/sidepelican) - [0X8C - Demired](https://github.com/Demired) +- [Maximus](https://github.com/maximus12793) All the contributors are welcome. If you would like to be the contributor please accept some rules. + - The pull requests will be accepted only in "develop" branch - All modifications or additions should be tested - Sorry, We will not accept code with any dependency, only standard library