Files
mesh-sdk/go/stateobjects/process.go
jschoubben 5fa64be894 Revert the revert of G's mesh-sdk merge (#191): G's sdk stands again over reader release 3
Main reverted G's half merge (#189, reverted by 8afc3eb in #191) and then took the reader release's S1-S5, which
copied G's code. G's form holds where they differ (process_bus.go, seats.go, state.go and their tests); the
release's kept names stay so main's callers keep building: SeatViewPrefix beside SeatReadPrefix, and QueueInvoke's
empty strings on not-ok (with its test TestQueueInvoke). The tree differs from G's head f30dee54 only by those and
the release's two tests (objects cap option, seat states and stream kinds).

Builds: design 47 G (the milestone's sdk part, as at f30dee54)

Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
2026-11-13 12:49:56 +01:00

127 lines
3.2 KiB
Go

package stateobjects
import (
"context"
"errors"
"time"
"github.com/nats-io/nats.go/jetstream"
"git.novox.be/novox/mesh-sdk/go/kvlimit"
)
// callTimeout bounds each call a process makes of its bus.
const callTimeout = 30 * time.Second
// OverBus is a state a process reaches through its own JetStream, with the object store beside it: a foundation part's
// bucket and its old `objects` section, or a bundle-less part's `<state>-objects`. store names the object store as a
// reader asks for it, written into every reference. The bucket's own limit for one value is the limit of the values.
func OverBus(kv jetstream.KeyValue, objects jetstream.ObjectStore, store string) Values {
limit, cancel := context.WithTimeout(context.Background(), callTimeout)
defer cancel()
return Values{KV: BusKV{KV: kv}, Objects: BusObjects{Store: objects}, Store: store, Limit: int(kvlimit.LimitOf(limit, kv))}
}
// BusKV is a bucket as a process reaches it.
type BusKV struct{ KV jetstream.KeyValue }
func ctx() (context.Context, context.CancelFunc) {
return context.WithTimeout(context.Background(), callTimeout)
}
func (b BusKV) Get(key string) (*Entry, error) {
c, cancel := ctx()
defer cancel()
e, err := b.KV.Get(c, key)
if errors.Is(err, jetstream.ErrKeyNotFound) {
return nil, nil
}
if err != nil {
return nil, err
}
if e.Operation() != jetstream.KeyValuePut {
return nil, nil
}
return &Entry{Value: e.Value(), Revision: e.Revision()}, nil
}
func (b BusKV) Create(key string, value []byte) error {
c, cancel := ctx()
defer cancel()
_, err := kvlimit.Create(c, b.KV, key, value)
if errors.Is(err, jetstream.ErrKeyExists) {
return ErrChanged
}
return err
}
func (b BusKV) Update(key string, value []byte, revision uint64) error {
c, cancel := ctx()
defer cancel()
_, err := kvlimit.Update(c, b.KV, key, value, revision)
if errors.Is(err, jetstream.ErrKeyRevisionMismatch) {
return ErrChanged
}
return err
}
func (b BusKV) Delete(key string) error {
c, cancel := ctx()
defer cancel()
return b.KV.Delete(c, key)
}
func (b BusKV) Keys() ([]string, error) {
c, cancel := ctx()
defer cancel()
keys, err := b.KV.Keys(c)
if errors.Is(err, jetstream.ErrNoKeysFound) {
return nil, nil
}
return keys, err
}
// BusObjects is an object store as a process reaches it; it takes any size in one put.
type BusObjects struct{ Store jetstream.ObjectStore }
func (BusObjects) MostBytes() int { return 0 }
func (b BusObjects) Put(name string, data []byte) error {
c, cancel := ctx()
defer cancel()
_, err := b.Store.PutBytes(c, name, data)
return err
}
func (b BusObjects) Get(name string) ([]byte, error) {
c, cancel := ctx()
defer cancel()
return b.Store.GetBytes(c, name)
}
func (b BusObjects) Delete(name string) error {
c, cancel := ctx()
defer cancel()
err := b.Store.Delete(c, name)
if errors.Is(err, jetstream.ErrObjectNotFound) {
return nil
}
return err
}
func (b BusObjects) List() ([]Object, error) {
c, cancel := ctx()
defer cancel()
l, err := b.Store.List(c)
if errors.Is(err, jetstream.ErrNoObjectsFound) {
return nil, nil
}
out := make([]Object, 0, len(l))
for _, o := range l {
if !o.Deleted {
out = append(out, Object{Name: o.Name, Size: int64(o.Size), Modified: o.ModTime})
}
}
return out, err
}