github.com/iDigitalFlame/xmt@v0.5.4/device/daemon_nix.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 "os" 25 "os/signal" 26 "syscall" 27 "time" 28 ) 29 30 // Daemon starts a "Service" (on Windows devices) and will run the function 31 // until interrupted. This function will block while running the function and 32 // can be interrupted via the Windows service control manager or SIGNALS (on 33 // Linux). 34 // 35 // Any errors during runtime or returned from the functions will be returned. 36 // 37 // NOTE: The 'name' argument is the service name on Windows, but is ignored 38 // on *nix systems. 39 func Daemon(_ string, f DaemonFunc) error { 40 var ( 41 w = make(chan os.Signal, 1) 42 e = make(chan error) 43 x, y = context.WithCancel(context.Background()) 44 err error 45 ) 46 signal.Notify(w, syscall.SIGINT, syscall.SIGTERM) 47 go func() { 48 e <- f(x) 49 close(e) 50 }() 51 select { 52 case err = <-e: 53 case <-x.Done(): 54 } 55 y() 56 signal.Reset(syscall.SIGINT, syscall.SIGTERM) 57 if close(w); err != nil && err != ErrQuit { 58 return err 59 } 60 return nil 61 } 62 63 // DaemonTicker starts a "Service" (on Windows devices) and will run the function 64 // every 't' duration until interrupted. This function will block while running 65 // and can be interrupted via the Windows service control manager or SIGNALS (on 66 // Linux). 67 // 68 // Returning the error 'ErrQuit' will break the loop with a non-error. 69 // 70 // Any errors during runtime or returned from the functions will be returned. 71 // Non-nil (non- ErrQuit) error returns will break the loop with an error. 72 // 73 // NOTE: The 'name' argument is the service name on Windows, but is ignored 74 // on *nix systems. 75 func DaemonTicker(_ string, t time.Duration, f DaemonFunc) error { 76 var ( 77 w = make(chan os.Signal, 1) 78 v = time.NewTimer(t) 79 x, y = context.WithCancel(context.Background()) 80 err error 81 ) 82 signal.Notify(w, syscall.SIGINT, syscall.SIGTERM) 83 loop: 84 for { 85 select { 86 case <-v.C: 87 if err = f(x); err != nil { 88 break loop 89 } 90 v.Reset(t) 91 case <-x.Done(): 92 break loop 93 } 94 } 95 y() 96 v.Stop() 97 signal.Reset(syscall.SIGINT, syscall.SIGTERM) 98 if close(w); err != nil && err != ErrQuit { 99 return err 100 } 101 return nil 102 }