gitee.com/h79/goutils@v1.22.10/common/watcher/watcher.go (about)

     1  package watcher
     2  
     3  import (
     4  	"gitee.com/h79/goutils/common/system"
     5  	"sync/atomic"
     6  	"time"
     7  )
     8  
     9  type DoChanged interface {
    10  	Changed() bool
    11  }
    12  type Func func() bool
    13  
    14  func (f Func) Changed() bool {
    15  	return f.Changed()
    16  }
    17  
    18  type Watcher struct {
    19  	stop      chan bool
    20  	update    chan bool
    21  	changed   chan bool
    22  	method    int32
    23  	ticker    time.Duration
    24  	doChanged DoChanged
    25  	running   system.RunningCheck
    26  }
    27  
    28  const (
    29  	UnkMethod    = iota
    30  	NormalMethod //default
    31  	ChanMethod
    32  )
    33  
    34  type Option func(w *Watcher)
    35  
    36  func NewWatcher(cha DoChanged, opts ...Option) *Watcher {
    37  	w := &Watcher{
    38  		method:    UnkMethod,
    39  		doChanged: cha,
    40  		ticker:    time.Second,
    41  		update:    make(chan bool),
    42  		stop:      make(chan bool),
    43  	}
    44  	w.UseMethod(NormalMethod)
    45  	for i := range opts {
    46  		opts[i](w)
    47  	}
    48  	return w
    49  }
    50  
    51  func (w *Watcher) Update() {
    52  	w.update <- true
    53  	w.run()
    54  }
    55  
    56  func (w *Watcher) Stop() {
    57  	system.Stop(time.Second, w.stop)
    58  }
    59  
    60  func (w *Watcher) UseMethod(method int32) {
    61  	oldMethod := atomic.LoadInt32(&w.method)
    62  	if oldMethod == method {
    63  		return
    64  	}
    65  	atomic.StoreInt32(&w.method, method)
    66  	if oldMethod == ChanMethod {
    67  		close(w.changed)
    68  	}
    69  	if method == ChanMethod {
    70  		w.changed = make(chan bool)
    71  		w.run()
    72  	} else if method == NormalMethod {
    73  		w.run()
    74  	}
    75  }
    76  
    77  func (w *Watcher) Changed() <-chan bool {
    78  	return w.changed
    79  }
    80  
    81  func (w *Watcher) run() {
    82  	w.running.GoRunning(func() {
    83  		ticker := time.NewTicker(w.ticker)
    84  		defer ticker.Stop()
    85  		for {
    86  			select {
    87  
    88  			case <-w.update:
    89  				if w.doChanged.Changed() && atomic.LoadInt32(&w.method) == ChanMethod {
    90  					w.changed <- true
    91  				}
    92  
    93  			case <-ticker.C:
    94  				if w.doChanged.Changed() && atomic.LoadInt32(&w.method) == ChanMethod {
    95  					w.changed <- true
    96  				}
    97  
    98  			case <-w.stop:
    99  				w.stop <- true
   100  				return
   101  
   102  			case <-system.Closed():
   103  				return
   104  			}
   105  		}
   106  	})
   107  }
   108  
   109  func WithTickerOption(ticker time.Duration) Option {
   110  	if ticker <= 0 {
   111  		ticker = time.Second
   112  	}
   113  	return func(w *Watcher) {
   114  		w.ticker = ticker
   115  	}
   116  }
   117  
   118  func WithChangedOption(changed DoChanged) Option {
   119  	return func(w *Watcher) {
   120  		w.doChanged = changed
   121  	}
   122  }
   123  
   124  func WithMethodOption(method int32) Option {
   125  	return func(w *Watcher) {
   126  		w.UseMethod(method)
   127  	}
   128  }