mirror of
https://github.com/xxjwxc/public.git
synced 2025-09-26 20:01:19 +08:00
99 lines
1.8 KiB
Go
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)
|
|
}
|