mirror of https://github.com/k3s-io/k3s
112 lines
1.9 KiB
Go
112 lines
1.9 KiB
Go
package driver
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
type Event struct {
|
|
KV *KeyValue
|
|
Err error
|
|
Start bool
|
|
}
|
|
|
|
func matchesKey(prefix bool, key string, kv *KeyValue) bool {
|
|
if kv == nil {
|
|
return false
|
|
}
|
|
if prefix {
|
|
return strings.HasPrefix(kv.Key, key[:len(key)-1])
|
|
}
|
|
return kv.Key == key
|
|
}
|
|
|
|
func (g *Generic) globalWatcher() (chan map[string]interface{}, error) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
g.cancel = cancel
|
|
result := make(chan map[string]interface{}, 100)
|
|
|
|
go func() {
|
|
defer close(result)
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case e := <-g.changes:
|
|
result <- map[string]interface{}{
|
|
"data": e,
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (g *Generic) Watch(ctx context.Context, key string, revision int64) <-chan Event {
|
|
ctx, parentCancel := context.WithCancel(ctx)
|
|
|
|
prefix := strings.HasSuffix(key, "%")
|
|
|
|
events, err := g.broadcaster.Subscribe(ctx, g.globalWatcher)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
watchChan := make(chan Event)
|
|
go func() (returnErr error) {
|
|
defer func() {
|
|
sendErrorAndClose(watchChan, returnErr)
|
|
parentCancel()
|
|
}()
|
|
|
|
start(watchChan)
|
|
|
|
if revision > 0 {
|
|
keys, err := g.replayEvents(ctx, key, revision)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, k := range keys {
|
|
watchChan <- Event{KV: k}
|
|
}
|
|
}
|
|
|
|
for e := range events {
|
|
k, ok := e["data"].(*KeyValue)
|
|
if ok && matchesKey(prefix, key, k) {
|
|
watchChan <- Event{KV: k}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}()
|
|
|
|
return watchChan
|
|
}
|
|
|
|
func start(watchResponses chan Event) {
|
|
watchResponses <- Event{
|
|
Start: true,
|
|
}
|
|
}
|
|
|
|
func sendErrorAndClose(watchResponses chan Event, err error) {
|
|
if err == nil {
|
|
err = io.EOF
|
|
}
|
|
watchResponses <- Event{Err: err}
|
|
close(watchResponses)
|
|
}
|
|
|
|
// Close closes the watcher and cancels all watch requests.
|
|
func (g *Generic) Close() error {
|
|
if g.cancel != nil {
|
|
g.cancel()
|
|
g.cancel = nil
|
|
}
|
|
return nil
|
|
}
|