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 }