etcd/store/watcher.go
2013-06-30 10:09:05 -07:00

126 lines
2.2 KiB
Go

package store
import (
"path"
"strconv"
"strings"
)
type WatcherHub struct {
watchers map[string][]Watcher
}
type Watcher struct {
c chan Response
}
// global watcher
var w *WatcherHub
// init the global watcher
func init() {
w = createWatcherHub()
}
// create a new watcher
func createWatcherHub() *WatcherHub {
w := new(WatcherHub)
w.watchers = make(map[string][]Watcher)
return w
}
func GetWatcherHub() *WatcherHub {
return w
}
// register a function with channel and prefix to the watcher
func AddWatcher(prefix string, c chan Response, sinceIndex uint64) error {
prefix = "/" + path.Clean(prefix)
if sinceIndex != 0 && sinceIndex >= s.ResponseStartIndex {
for i := sinceIndex; i <= s.Index; i++ {
if check(prefix, i) {
c <- s.ResponseMap[strconv.FormatUint(i, 10)]
return nil
}
}
}
_, ok := w.watchers[prefix]
if !ok {
w.watchers[prefix] = make([]Watcher, 0)
watcher := Watcher{c}
w.watchers[prefix] = append(w.watchers[prefix], watcher)
} else {
watcher := Watcher{c}
w.watchers[prefix] = append(w.watchers[prefix], watcher)
}
return nil
}
// check if the response has what we are watching
func check(prefix string, index uint64) bool {
resp, ok := s.ResponseMap[strconv.FormatUint(index, 10)]
if !ok {
// not storage system command
return false
} else {
path := resp.Key
if strings.HasPrefix(path, prefix) {
prefixLen := len(prefix)
if len(path) == prefixLen || path[prefixLen] == '/' {
return true
}
}
}
return false
}
// notify the watcher a action happened
func notify(resp Response) error {
resp.Key = path.Clean(resp.Key)
segments := strings.Split(resp.Key, "/")
currPath := "/"
// walk through all the pathes
for _, segment := range segments {
currPath = path.Join(currPath, segment)
watchers, ok := w.watchers[currPath]
if ok {
newWatchers := make([]Watcher, 0)
// notify all the watchers
for _, watcher := range watchers {
watcher.c <- resp
}
if len(newWatchers) == 0 {
// we have notified all the watchers at this path
// delete the map
delete(w.watchers, currPath)
} else {
w.watchers[currPath] = newWatchers
}
}
}
return nil
}