Read a ledger: an instance's state, its history oldest first with sequence and author, a watch of its states, a declared index (issue 1966 T3)
This commit is contained in:
@@ -5,9 +5,12 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/buscalls"
|
||||
"git.novox.be/novox/mesh-sdk/go/membership"
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/nats-io/nats.go/jetstream"
|
||||
@@ -227,3 +230,114 @@ func (s *busSnapshots) Put(key string, value []byte, expect uint64) error {
|
||||
_, err := publishExpecting(s.write, s.prefix+"."+key, value, expect)
|
||||
return err
|
||||
}
|
||||
|
||||
// Watch hands deliver every instance's record under a key pattern as it is, then each change; a removed key is handed as
|
||||
// nil.
|
||||
func (s *busState) Watch(pattern string, deliver func(key string, value []byte, current bool) error) (func(), error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), StateTimeout)
|
||||
kv, err := s.kv(ctx)
|
||||
cancel()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w, err := kv.Watch(context.Background(), pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hand := func(e jetstream.KeyValueEntry, current bool) {
|
||||
var value []byte
|
||||
if e.Operation() == jetstream.KeyValuePut {
|
||||
value = e.Value()
|
||||
}
|
||||
if err := deliver(e.Key(), value, current); err != nil {
|
||||
s.c.Logf("[mesh-tools] a ledger watch of %s was not taken: %v", s.bucket, err)
|
||||
}
|
||||
}
|
||||
timer := time.NewTimer(StateTimeout)
|
||||
defer timer.Stop()
|
||||
for current := true; current; {
|
||||
select {
|
||||
case e, ok := <-w.Updates():
|
||||
if !ok {
|
||||
return nil, errors.New("the ledger's state watch ended before its current states were handed over")
|
||||
}
|
||||
if e == nil {
|
||||
current = false
|
||||
continue
|
||||
}
|
||||
hand(e, true)
|
||||
case <-timer.C:
|
||||
_ = w.Stop()
|
||||
return nil, fmt.Errorf("the ledger's state %s did not hand its current states in %s", s.bucket, StateTimeout)
|
||||
}
|
||||
}
|
||||
go func() {
|
||||
for e := range w.Updates() {
|
||||
if e != nil {
|
||||
hand(e, false)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return func() { _ = w.Stop() }, nil
|
||||
}
|
||||
|
||||
// LedgerIndexes are the buckets of a ledger binding's declared indexes, by index name, on the runner's own connection.
|
||||
func (c *Conn) LedgerIndexes(b membership.BusBinding) map[string]ledger.Index {
|
||||
out := map[string]ledger.Index{}
|
||||
for name, bucket := range b.Indexes {
|
||||
out[name] = &busState{c: c, bucket: bucket}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *busState) Entries(pattern string, limit int) ([]buscalls.IndexEntry, error) {
|
||||
if pattern == "" {
|
||||
pattern = ">"
|
||||
}
|
||||
keys, err := s.Keys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sort.Strings(keys)
|
||||
var out []buscalls.IndexEntry
|
||||
for _, k := range keys {
|
||||
if limit > 0 && len(out) >= limit {
|
||||
break
|
||||
}
|
||||
if !SubjectMatches(pattern, k) {
|
||||
continue
|
||||
}
|
||||
v, _, err := s.Get(k)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
if v != nil {
|
||||
out = append(out, buscalls.IndexEntry{Key: k, Value: valueOf(v)})
|
||||
}
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *busState) Put(key string, value []byte) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), StateTimeout)
|
||||
defer cancel()
|
||||
kv, err := s.kv(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = kv.Put(ctx, key, value)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *busState) Delete(key string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), StateTimeout)
|
||||
defer cancel()
|
||||
kv, err := s.kv(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kv.Delete(ctx, key); err != nil && !errors.Is(err, jetstream.ErrKeyNotFound) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user