Skip to content

Commit

Permalink
Switched core dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
markdicksonjr committed Sep 5, 2019
1 parent 80adffa commit e7183e6
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 114 deletions.
17 changes: 4 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,20 @@ run immediately.

The various lifecycle stages of services can be managed (by default):

`binaryName install`
`binaryName install` or `binaryName install [args...]`

`binaryName help`

`binaryName remove`
`binaryName uninstall`

`binaryName start`

`binaryName stop`

`binaryName status`

To customize these flags, you can handle them yourself and set the "Command" property on the Behavior you pass to the
service at creation time.

If you're debugging locally, just dont use one of the commands above:
For direct invocation:

`binaryName ...otherArgs`

## Restrictions

Due to a third-party implementation detail, service names with spaces will have those spaces converted to underscores.

## Credits

[github.com/takama/daemon](http://github.com/takama/daemon)
[github.com/kardianos/service](https://github.com/kardianos/service)
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@ module github.com/markdicksonjr/simple-daemon

go 1.12

require (
github.com/takama/daemon v0.11.0
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 // indirect
)
require github.com/kardianos/service v1.0.0
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
github.com/takama/daemon v0.11.0 h1:6axxBnHV48vrsT9OZrrJ8tuwMEa6fNsTAHaS1Cd4vyY=
github.com/takama/daemon v0.11.0/go.mod h1:So5Nv647d/sgbZNAfiWtw6egowH8vNNrPXAwooWeElk=
github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 h1:FDfvYgoVsA7TTZSbgiqjAbfPbK47CNHdWl3h/PJtii0=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
147 changes: 53 additions & 94 deletions lib.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package simple_daemon

import (
"github.com/takama/daemon"
"github.com/kardianos/service"
"log"
"os"
"os/signal"
"syscall"
)

type Info struct {
Expand All @@ -15,116 +13,77 @@ type Info struct {
}

type Behavior struct {
WorkFn func() error
ExitFn func() error
StdLog *log.Logger
ErrLog *log.Logger
Command string
WorkFn func() error
ExitFn func() error
}

func Start(info Info, behavior Behavior) error {
srv, err := daemon.New(info.Name, info.Description, info.Dependencies...)
if err != nil {
return err
}

s := ManagedService{
Daemon: srv,
info: info,
workFn: behavior.WorkFn,
exitFn: behavior.ExitFn,
stdlog: behavior.StdLog,
errlog: behavior.ErrLog,
command: behavior.Command,
}
type program struct {
B Behavior
}

if s.stdlog == nil {
s.stdlog = log.New(os.Stdout, "", 0)
}
func (p *program) Start(s service.Service) error {
go p.run()
return nil
}

if s.errlog == nil {
s.errlog = log.New(os.Stderr, "", 0)
func (p *program) run() {
if err := p.B.WorkFn(); err != nil {
log.Fatal(err) // todo
}
}

status, err := s.Manage()
if err != nil {
return err
func (p *program) Stop(s service.Service) error {
if p.B.ExitFn != nil {
if err := p.B.ExitFn(); err != nil {
return err
}
}

s.stdlog.Println(status)

return nil
}

type ManagedService struct {
daemon.Daemon
workFn func() error
exitFn func() error
info Info
stdlog *log.Logger
errlog *log.Logger
command string
}
func Start(info Info, behavior Behavior) error {
svcConfig := &service.Config{
Name: info.Name,
DisplayName: info.Name,
Description: info.Description,
Arguments: nil,
}

func (s *ManagedService) Manage() (string, error) {
usage := "Usage: " + s.info.Name + " install | remove | start | stop | status"
command := s.command
if len(os.Args) > 2 && os.Args[1] == "install" {
svcConfig.Arguments = os.Args[2:]
}

// if received any kind of command, and we haven't specified one ourselves, do it
if len(command) == 0 && len(os.Args) > 1 {
command = os.Args[1]
prg := &program{
B: behavior,
}
s, err := service.New(prg, svcConfig)
if err != nil {
log.Fatal(err)
}

if len(command) > 0 {
switch command {
case "install":
return s.Install(os.Args[2:]...)
case "remove":
return s.Remove()
case "start":
if len(os.Args) > 1 {
if os.Args[1] == "install" {
return s.Install()
} else if os.Args[1] == "uninstall" {
return s.Uninstall()
} else if os.Args[1] == "start" {
return s.Start()
case "stop":
} else if os.Args[1] == "stop" {
return s.Stop()
case "status":
return s.Status()
case "help":
return usage, nil
default:
break
} else if os.Args[1] == "status" {
status, err := s.Status()
if err != nil {
log.Fatal(err)
}
log.Println(status)
return nil
}
}

interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt, os.Kill, syscall.SIGTERM)

workError := make(chan error, 1)

go func() {
if err := s.workFn(); err != nil {
interrupt <- os.Kill
}
}()
// TODO: improve loggers

for {
select {
case err := <-workError:
if s.exitFn != nil {
if exitErr := s.exitFn(); exitErr != nil && s.errlog != nil { // TODO: do something meaningful with this error
s.errlog.Println(exitErr)
}
}
return "An error occurred", err
case killSignal := <-interrupt:
var err error

if s.exitFn != nil {
err = s.exitFn()
}

if killSignal == os.Interrupt {
return "Daemon was interrupted by system signal", err
}
return "Daemon was killed", err
}
if err = s.Run(); err != nil {
return err
}
return nil
}
21 changes: 20 additions & 1 deletion sample/main.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,37 @@
package main

import (
"flag"
simple_daemon "github.com/markdicksonjr/simple-daemon"
"log"
"os"
)

// in this app, you should run ./main.exe install --name bob
// then, start the service. You should see "testlogfile" containing the correct response
func main() {
f, err := os.OpenFile("testlogfile", os.O_RDWR | os.O_CREATE | os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()

log.SetOutput(f)

if err := simple_daemon.Start(simple_daemon.Info{
Name: "Test Daemon",
Description: "A simple test daemon",
Dependencies: nil,
}, simple_daemon.Behavior{
WorkFn: func() error {
log.Println("simple log")
name := flag.String("name", "", "some name to print")
flag.Parse()

if *name != "bob" {
log.Println("your name should be bob,", *name)
} else {
log.Println("simple log for", *name)
}
return nil
},
}); err != nil {
Expand Down

0 comments on commit e7183e6

Please sign in to comment.