github.com/iDigitalFlame/xmt@v0.5.4/man/guardian.go (about)

     1  // Copyright (C) 2020 - 2023 iDigitalFlame
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU General Public License as published by
     5  // the Free Software Foundation, either version 3 of the License, or
     6  // any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU General Public License
    14  // along with this program.  If not, see <https://www.gnu.org/licenses/>.
    15  //
    16  
    17  // Package man is the implementation of the Guardian and Sentinel structs. These
    18  // can be used to guard against accidental launching of multiple processes and
    19  // can determine if targets are 'alive'.
    20  //
    21  // Windows clients have many options using built-in API calls, while other
    22  // options such as TCP or Sockets (Named Pipes on Windows, UDS on *nix) to use
    23  // generic control structs.
    24  //
    25  // Sentinel is a struct that can be Marshaled/Unmashaled from a file or network
    26  // stream with optional encryption capabilities. Sentinels can launch
    27  // applications in may different ways, including downloading, injecting or
    28  // directly executing.
    29  package man
    30  
    31  import (
    32  	"context"
    33  
    34  	"github.com/iDigitalFlame/xmt/util/xerr"
    35  )
    36  
    37  // Guardian is a struct that is used to maintain a running process that will
    38  // re-establish itself if it is not detected running.
    39  //
    40  // Guardian instances use Linker interfaces to determine status.
    41  type Guardian struct {
    42  	_    [0]func()
    43  	ch   chan struct{}
    44  	sock listener
    45  }
    46  
    47  // Wait will block until the Guardian is closed.
    48  func (g *Guardian) Wait() {
    49  	<-g.ch
    50  }
    51  
    52  // Close will close the Guardian and stops the listener.
    53  //
    54  // Any errors during listener close will be returned.
    55  //
    56  // This function will block until the Guardian fully closes.
    57  func (g *Guardian) Close() error {
    58  	if g.sock == nil {
    59  		return nil
    60  	}
    61  	err := g.sock.Close()
    62  	close(g.ch)
    63  	g.sock = nil
    64  	return err
    65  }
    66  
    67  // Done returns a channel that's closed when this Guardian is closed.
    68  //
    69  // This can be used to monitor a Guardian's status using a select statement.
    70  func (g *Guardian) Done() <-chan struct{} {
    71  	return g.ch
    72  }
    73  func (g *Guardian) wait(x context.Context) {
    74  	select {
    75  	case <-g.ch:
    76  	case <-x.Done():
    77  		g.Close()
    78  	}
    79  }
    80  
    81  // MustGuard returns a Guardian instance that watches on the name provided.
    82  //
    83  // This function must complete and will panic if an error occurs, otherwise a
    84  // Guardian instance is returned.
    85  //
    86  // This function defaults to the 'Pipe' Linker if a nil Linker is specified.
    87  func MustGuard(l Linker, n string) *Guardian {
    88  	g, err := GuardContext(context.Background(), l, n)
    89  	if err != nil {
    90  		panic(err)
    91  	}
    92  	return g
    93  }
    94  
    95  // Guard will attempt to create a Guardian instance on the provided name using
    96  // the specified Linker.
    97  //
    98  // This function will return an error if the name is already being listened on.
    99  //
   100  // This function defaults to the 'Pipe' Linker if a nil Linker is specified.
   101  func Guard(l Linker, n string) (*Guardian, error) {
   102  	return GuardContext(context.Background(), l, n)
   103  }
   104  
   105  // MustGuardContext returns a Guardian instance that watches on the name provided.
   106  //
   107  // This function must complete and will panic if an error occurs, otherwise a
   108  // Guardian instance is returned.
   109  //
   110  // This function also takes a context.Context to be used for resource control.
   111  func MustGuardContext(x context.Context, l Linker, n string) *Guardian {
   112  	g, err := GuardContext(x, l, n)
   113  	if err != nil {
   114  		panic(err)
   115  	}
   116  	return g
   117  }
   118  
   119  // GuardContext will attempt to create a Guardian instance on the provided name.
   120  //
   121  // This function will return an error if the name is already being listened on.
   122  //
   123  // This function will choose the proper connection method based on the host
   124  // operating system.
   125  //
   126  // This function also takes a context.Context to be used for resource control.
   127  func GuardContext(x context.Context, l Linker, n string) (*Guardian, error) {
   128  	if len(n) == 0 {
   129  		return nil, xerr.Sub("empty or invalid Guardian name", 0x10)
   130  	}
   131  	if l == nil {
   132  		l = Pipe
   133  	}
   134  	v, err := l.create(n)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	g := &Guardian{ch: make(chan struct{}), sock: v}
   139  	if x != nil && x != context.Background() {
   140  		go g.wait(x)
   141  	}
   142  	go v.Listen()
   143  	return g, nil
   144  }