github.com/iDigitalFlame/xmt@v0.5.4/device/daemon_win.go (about) 1 //go:build windows && !noservice 2 // +build windows,!noservice 3 4 // Copyright (C) 2020 - 2023 iDigitalFlame 5 // 6 // This program is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // any later version. 10 // 11 // This program is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 // 16 // You should have received a copy of the GNU General Public License 17 // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 // 19 20 package device 21 22 import ( 23 "context" 24 "time" 25 26 "github.com/iDigitalFlame/xmt/device/winapi/svc" 27 ) 28 29 // Daemon starts a "Service" (on Windows devices) and will run the function 30 // until interrupted. This function will block while running the function and 31 // can be interrupted via the Windows service control manager or SIGNALS (on 32 // Linux). 33 // 34 // Any errors during runtime or returned from the functions will be returned. 35 // 36 // NOTE: The 'name' argument is the service name on Windows, but is ignored 37 // on *nix systems. 38 func Daemon(name string, f DaemonFunc) error { 39 return svc.Run(name, func(x context.Context, s svc.Service, _ []string) uint32 { 40 var ( 41 e = make(chan error) 42 err error 43 ) 44 s.UpdateState(svc.Running, svc.AcceptStop|svc.AcceptShutdown) 45 go func() { 46 e <- f(x) 47 close(e) 48 }() 49 select { 50 case err = <-e: 51 case <-x.Done(): 52 } 53 if s.UpdateState(svc.StopPending); err != nil && err != ErrQuit { 54 return 1 55 } 56 return 0 57 }) 58 } 59 60 // DaemonTicker starts a "Service" (on Windows devices) and will run the function 61 // every 't' duration until interrupted. This function will block while running 62 // and can be interrupted via the Windows service control manager or SIGNALS (on 63 // Linux). 64 // 65 // Returning the error 'ErrQuit' will break the loop with a non-error. 66 // 67 // Any errors during runtime or returned from the functions will be returned. 68 // Non-nil (non- ErrQuit) error returns will break the loop with an error. 69 // 70 // NOTE: The 'name' argument is the service name on Windows, but is ignored 71 // on *nix systems. 72 func DaemonTicker(name string, t time.Duration, f DaemonFunc) error { 73 return svc.Run(name, func(x context.Context, s svc.Service, _ []string) uint32 { 74 var ( 75 v = time.NewTimer(t) 76 err error 77 ) 78 loop: 79 for s.UpdateState(svc.Running, svc.AcceptStop|svc.AcceptShutdown); ; { 80 select { 81 case <-v.C: 82 if err = f(x); err != nil { 83 break loop 84 } 85 v.Reset(t) 86 case <-x.Done(): 87 break loop 88 } 89 } 90 v.Stop() 91 if s.UpdateState(svc.StopPending); err != nil && err != ErrQuit { 92 return 1 93 } 94 return 0 95 }) 96 }