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 }