github.com/safing/portbase@v0.19.5/utils/broadcastflag.go (about) 1 package utils 2 3 import ( 4 "sync" 5 6 "github.com/tevino/abool" 7 ) 8 9 // BroadcastFlag is a simple system to broadcast a flag value. 10 type BroadcastFlag struct { 11 flag *abool.AtomicBool 12 signal chan struct{} 13 lock sync.Mutex 14 } 15 16 // Flag receives changes from its broadcasting flag. 17 // A Flag must only be used in one goroutine and is not concurrency safe, 18 // but fast. 19 type Flag struct { 20 flag *abool.AtomicBool 21 signal chan struct{} 22 broadcaster *BroadcastFlag 23 } 24 25 // NewBroadcastFlag returns a new BroadcastFlag. 26 // In the initial state, the flag is not set and the signal does not trigger. 27 func NewBroadcastFlag() *BroadcastFlag { 28 return &BroadcastFlag{ 29 flag: abool.New(), 30 signal: make(chan struct{}), 31 lock: sync.Mutex{}, 32 } 33 } 34 35 // NewFlag returns a new Flag that listens to this broadcasting flag. 36 // In the initial state, the flag is set and the signal triggers. 37 // You can call Refresh immediately to get the current state from the 38 // broadcasting flag. 39 func (bf *BroadcastFlag) NewFlag() *Flag { 40 newFlag := &Flag{ 41 flag: abool.NewBool(true), 42 signal: make(chan struct{}), 43 broadcaster: bf, 44 } 45 close(newFlag.signal) 46 return newFlag 47 } 48 49 // NotifyAndReset notifies all flags of this broadcasting flag and resets the 50 // internal broadcast flag state. 51 func (bf *BroadcastFlag) NotifyAndReset() { 52 bf.lock.Lock() 53 defer bf.lock.Unlock() 54 55 // Notify all flags of the change. 56 bf.flag.Set() 57 close(bf.signal) 58 59 // Reset 60 bf.flag = abool.New() 61 bf.signal = make(chan struct{}) 62 } 63 64 // Signal returns a channel that waits for the flag to be set. This does not 65 // reset the Flag itself, you'll need to call Refresh for that. 66 func (f *Flag) Signal() <-chan struct{} { 67 return f.signal 68 } 69 70 // IsSet returns whether the flag was set since the last Refresh. 71 // This does not reset the Flag itself, you'll need to call Refresh for that. 72 func (f *Flag) IsSet() bool { 73 return f.flag.IsSet() 74 } 75 76 // Refresh fetches the current state from the broadcasting flag. 77 func (f *Flag) Refresh() { 78 f.broadcaster.lock.Lock() 79 defer f.broadcaster.lock.Unlock() 80 81 // Copy current flag and signal from the broadcasting flag. 82 f.flag = f.broadcaster.flag 83 f.signal = f.broadcaster.signal 84 }