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  }