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  }