Files
public/myconsul/kv/watcher.go
2021-04-23 17:22:49 +08:00

99 lines
1.8 KiB
Go

package kv
import (
"bytes"
"fmt"
"strings"
"sync"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/api/watch"
"github.com/tidwall/gjson"
)
func newWatcher(path string) (*watcher, error) {
wp, err := watch.Parse(map[string]interface{}{"type": "keyprefix", "prefix": path})
if err != nil {
return nil, err
}
return &watcher{
Plan: wp,
lastValues: make(map[string][]byte),
err: make(chan error, 1),
}, nil
}
type watcher struct {
*watch.Plan
lastValues map[string][]byte
hybridHandler watch.HybridHandlerFunc
stopChan chan interface{}
err chan error
sync.RWMutex
}
func (w *watcher) getValue(path string) []byte {
w.RLock()
defer w.RUnlock()
return w.lastValues[path]
}
func (w *watcher) updateValue(path string, value []byte) {
w.Lock()
defer w.Unlock()
if len(value) == 0 {
delete(w.lastValues, path)
} else {
w.lastValues[path] = value
}
}
func (w *watcher) setHybridHandler(prefix string, handler func(*Result)) {
w.hybridHandler = func(bp watch.BlockingParamVal, data interface{}) {
kvPairs := data.(api.KVPairs)
ret := &Result{}
for _, k := range kvPairs {
path := strings.TrimSuffix(strings.TrimPrefix(k.Key, prefix+"/"), "/")
v := w.getValue(path)
if len(k.Value) == 0 && len(v) == 0 {
continue
}
if bytes.Equal(k.Value, v) {
continue
}
ret.g = gjson.ParseBytes(k.Value)
ret.k = path
w.updateValue(path, k.Value)
handler(ret)
}
}
}
func (w *watcher) run(address string, conf *api.Config) error {
w.stopChan = make(chan interface{})
w.Plan.HybridHandler = w.hybridHandler
go func() {
w.err <- w.RunWithConfig(address, conf)
}()
select {
case err := <-w.err:
return fmt.Errorf("run fail: %w", err)
case <-w.stopChan:
w.Stop()
return nil
}
}
func (w *watcher) stop() {
close(w.stopChan)
}