gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/system/service.v2/service_windows.go (about) 1 package svc 2 3 import ( 4 "gitee.com/sy_183/go-common/lifecycle.v2" 5 "golang.org/x/sys/windows/svc" 6 "os" 7 "os/signal" 8 ) 9 10 var isWindowsService = false 11 12 func init() { 13 var err error 14 isWindowsService, err = svc.IsWindowsService() 15 if err != nil { 16 panic(err) 17 } 18 } 19 20 type windowsService struct { 21 name string 22 app lifecycle.Lifecycle 23 exitCode int 24 25 notifySignals []os.Signal 26 signalCallback func(sig os.Signal) (exit bool) 27 exitCodeGetter func(err *Error) int 28 } 29 30 func New(name string, app lifecycle.Lifecycle, options ...Option) Service { 31 ws := &windowsService{ 32 name: name, 33 app: app, 34 notifySignals: DefaultNotifySignals[:], 35 signalCallback: DefaultSignalCallback, 36 exitCodeGetter: DefaultExitCodeGetter, 37 } 38 for _, option := range options { 39 option.apply(ws) 40 } 41 return ws 42 } 43 44 func (ws *windowsService) setSignalNotify(callback func(sig os.Signal) (exit bool), sig ...os.Signal) { 45 ws.signalCallback = callback 46 ws.notifySignals = sig 47 } 48 49 func (ws *windowsService) setExitCodeGetter(exitCodeGetter func(err *Error) int) { 50 ws.exitCodeGetter = exitCodeGetter 51 } 52 53 func (ws *windowsService) Execute(args []string, r <-chan svc.ChangeRequest, s chan<- svc.Status) (svcSpecificEC bool, exitCode uint32) { 54 const cmdsAccepted = svc.AcceptStop | svc.AcceptShutdown 55 56 ws.app.Background() 57 s <- svc.Status{State: svc.StartPending} 58 59 startedWaiter := ws.app.Waiter(lifecycle.FutureTypeStarted) 60 closedWaiter := ws.app.Waiter(lifecycle.FutureTypeClosed) 61 62 for { 63 select { 64 case err := <-startedWaiter: 65 if err != nil { 66 return true, uint32(ws.exitCodeGetter(&Error{Type: StartError, Err: err})) 67 } 68 s <- svc.Status{State: svc.Running, Accepts: cmdsAccepted} 69 case err := <-closedWaiter: 70 if err != nil { 71 return true, uint32(ws.exitCodeGetter(&Error{Type: ExitError, Err: err})) 72 } 73 return false, 0 74 case c := <-r: 75 switch c.Cmd { 76 case svc.Interrogate: 77 s <- c.CurrentStatus 78 case svc.Stop, svc.Shutdown: 79 s <- svc.Status{State: svc.StopPending} 80 ws.app.Close() 81 } 82 } 83 } 84 } 85 86 func (ws *windowsService) Run() int { 87 if isWindowsService { 88 if err := svc.Run(ws.name, ws); err != nil { 89 return ws.exitCodeGetter(&Error{Type: ServiceError, Err: err}) 90 } 91 return ws.exitCode 92 } 93 ws.app.Background() 94 95 sigChan := make(chan os.Signal) 96 signal.Notify(sigChan, ws.notifySignals...) 97 98 startedWaiter := ws.app.Waiter(lifecycle.FutureTypeStarted) 99 closedWaiter := ws.app.Waiter(lifecycle.FutureTypeClosed) 100 for { 101 select { 102 case sig := <-sigChan: 103 if ws.signalCallback(sig) { 104 ws.app.Close() 105 } 106 case err := <-startedWaiter: 107 if err != nil { 108 return ws.exitCodeGetter(&Error{Type: StartError, Err: err}) 109 } 110 case err := <-closedWaiter: 111 if err != nil { 112 return ws.exitCodeGetter(&Error{Type: ExitError, Err: err}) 113 } 114 return 0 115 } 116 } 117 }