Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
475 lines
16 KiB
Go
475 lines
16 KiB
Go
package basicnode
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/ipld/go-ipld-prime/datamodel"
|
|
"github.com/ipld/go-ipld-prime/node/mixins"
|
|
)
|
|
|
|
var (
|
|
_ datamodel.Node = &plainMap{}
|
|
_ datamodel.NodePrototype = Prototype__Map{}
|
|
_ datamodel.NodeBuilder = &plainMap__Builder{}
|
|
_ datamodel.NodeAssembler = &plainMap__Assembler{}
|
|
)
|
|
|
|
// plainMap is a concrete type that provides a map-kind datamodel.Node.
|
|
// It can contain any kind of value.
|
|
// plainMap is also embedded in the 'any' struct and usable from there.
|
|
type plainMap struct {
|
|
m map[string]datamodel.Node // string key -- even if a runtime schema wrapper is using us for storage, we must have a comparable type here, and string is all we know.
|
|
t []plainMap__Entry // table for fast iteration, order keeping, and yielding pointers to enable alloc/conv amortization.
|
|
}
|
|
|
|
type plainMap__Entry struct {
|
|
k plainString // address of this used when we return keys as nodes, such as in iterators. Need in one place to amortize shifts to heap when ptr'ing for iface.
|
|
v datamodel.Node // identical to map values. keeping them here simplifies iteration. (in codegen'd maps, this position is also part of amortization, but in this implementation, that's less useful.)
|
|
// note on alternate implementations: 'v' could also use the 'any' type, and thus amortize value allocations. the memory size trade would be large however, so we don't, here.
|
|
}
|
|
|
|
// -- Node interface methods -->
|
|
|
|
func (plainMap) Kind() datamodel.Kind {
|
|
return datamodel.Kind_Map
|
|
}
|
|
func (n *plainMap) LookupByString(key string) (datamodel.Node, error) {
|
|
v, exists := n.m[key]
|
|
if !exists {
|
|
return nil, datamodel.ErrNotExists{Segment: datamodel.PathSegmentOfString(key)}
|
|
}
|
|
return v, nil
|
|
}
|
|
func (n *plainMap) LookupByNode(key datamodel.Node) (datamodel.Node, error) {
|
|
ks, err := key.AsString()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return n.LookupByString(ks)
|
|
}
|
|
func (plainMap) LookupByIndex(idx int64) (datamodel.Node, error) {
|
|
return mixins.Map{TypeName: "map"}.LookupByIndex(0)
|
|
}
|
|
func (n *plainMap) LookupBySegment(seg datamodel.PathSegment) (datamodel.Node, error) {
|
|
return n.LookupByString(seg.String())
|
|
}
|
|
func (n *plainMap) MapIterator() datamodel.MapIterator {
|
|
return &plainMap_MapIterator{n, 0}
|
|
}
|
|
func (plainMap) ListIterator() datamodel.ListIterator {
|
|
return nil
|
|
}
|
|
func (n *plainMap) Length() int64 {
|
|
return int64(len(n.t))
|
|
}
|
|
func (plainMap) IsAbsent() bool {
|
|
return false
|
|
}
|
|
func (plainMap) IsNull() bool {
|
|
return false
|
|
}
|
|
func (plainMap) AsBool() (bool, error) {
|
|
return mixins.Map{TypeName: "map"}.AsBool()
|
|
}
|
|
func (plainMap) AsInt() (int64, error) {
|
|
return mixins.Map{TypeName: "map"}.AsInt()
|
|
}
|
|
func (plainMap) AsFloat() (float64, error) {
|
|
return mixins.Map{TypeName: "map"}.AsFloat()
|
|
}
|
|
func (plainMap) AsString() (string, error) {
|
|
return mixins.Map{TypeName: "map"}.AsString()
|
|
}
|
|
func (plainMap) AsBytes() ([]byte, error) {
|
|
return mixins.Map{TypeName: "map"}.AsBytes()
|
|
}
|
|
func (plainMap) AsLink() (datamodel.Link, error) {
|
|
return mixins.Map{TypeName: "map"}.AsLink()
|
|
}
|
|
func (plainMap) Prototype() datamodel.NodePrototype {
|
|
return Prototype.Map
|
|
}
|
|
|
|
type plainMap_MapIterator struct {
|
|
n *plainMap
|
|
idx int
|
|
}
|
|
|
|
func (itr *plainMap_MapIterator) Next() (k datamodel.Node, v datamodel.Node, _ error) {
|
|
if itr.Done() {
|
|
return nil, nil, datamodel.ErrIteratorOverread{}
|
|
}
|
|
k = &itr.n.t[itr.idx].k
|
|
v = itr.n.t[itr.idx].v
|
|
itr.idx++
|
|
return
|
|
}
|
|
func (itr *plainMap_MapIterator) Done() bool {
|
|
return itr.idx >= len(itr.n.t)
|
|
}
|
|
|
|
// -- NodePrototype -->
|
|
|
|
type Prototype__Map struct{}
|
|
|
|
func (Prototype__Map) NewBuilder() datamodel.NodeBuilder {
|
|
return &plainMap__Builder{plainMap__Assembler{w: &plainMap{}}}
|
|
}
|
|
|
|
// -- NodeBuilder -->
|
|
|
|
type plainMap__Builder struct {
|
|
plainMap__Assembler
|
|
}
|
|
|
|
func (nb *plainMap__Builder) Build() datamodel.Node {
|
|
if nb.state != maState_finished {
|
|
panic("invalid state: assembler must be 'finished' before Build can be called!")
|
|
}
|
|
return nb.w
|
|
}
|
|
func (nb *plainMap__Builder) Reset() {
|
|
*nb = plainMap__Builder{}
|
|
nb.w = &plainMap{}
|
|
}
|
|
|
|
// -- NodeAssembler -->
|
|
|
|
type plainMap__Assembler struct {
|
|
w *plainMap
|
|
|
|
ka plainMap__KeyAssembler
|
|
va plainMap__ValueAssembler
|
|
|
|
state maState
|
|
}
|
|
type plainMap__KeyAssembler struct {
|
|
ma *plainMap__Assembler
|
|
}
|
|
type plainMap__ValueAssembler struct {
|
|
ma *plainMap__Assembler
|
|
}
|
|
|
|
// maState is an enum of the state machine for a map assembler.
|
|
// (this might be something to export reusably, but it's also very much an impl detail that need not be seen, so, dubious.)
|
|
type maState uint8
|
|
|
|
const (
|
|
maState_initial maState = iota // also the 'expect key or finish' state
|
|
maState_midKey // waiting for a 'finished' state in the KeyAssembler.
|
|
maState_expectValue // 'AssembleValue' is the only valid next step
|
|
maState_midValue // waiting for a 'finished' state in the ValueAssembler.
|
|
maState_finished // 'w' will also be nil, but this is a politer statement
|
|
)
|
|
|
|
func (na *plainMap__Assembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
|
|
if sizeHint < 0 {
|
|
sizeHint = 0
|
|
}
|
|
// Allocate storage space.
|
|
na.w.t = make([]plainMap__Entry, 0, sizeHint)
|
|
na.w.m = make(map[string]datamodel.Node, sizeHint)
|
|
// That's it; return self as the MapAssembler. We already have all the right methods on this structure.
|
|
return na, nil
|
|
}
|
|
func (plainMap__Assembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
|
|
return mixins.MapAssembler{TypeName: "map"}.BeginList(0)
|
|
}
|
|
func (plainMap__Assembler) AssignNull() error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignNull()
|
|
}
|
|
func (plainMap__Assembler) AssignBool(bool) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignBool(false)
|
|
}
|
|
func (plainMap__Assembler) AssignInt(int64) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignInt(0)
|
|
}
|
|
func (plainMap__Assembler) AssignFloat(float64) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignFloat(0)
|
|
}
|
|
func (plainMap__Assembler) AssignString(string) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignString("")
|
|
}
|
|
func (plainMap__Assembler) AssignBytes([]byte) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignBytes(nil)
|
|
}
|
|
func (plainMap__Assembler) AssignLink(datamodel.Link) error {
|
|
return mixins.MapAssembler{TypeName: "map"}.AssignLink(nil)
|
|
}
|
|
func (na *plainMap__Assembler) AssignNode(v datamodel.Node) error {
|
|
// Sanity check assembler state.
|
|
// Update of state to 'finished' comes later; where exactly depends on if shortcuts apply.
|
|
if na.state != maState_initial {
|
|
panic("misuse")
|
|
}
|
|
// Copy the content.
|
|
if v2, ok := v.(*plainMap); ok { // if our own type: shortcut.
|
|
// Copy the structure by value.
|
|
// This means we'll have pointers into the same internal maps and slices;
|
|
// this is okay, because the Node type promises it's immutable, and we are going to instantly finish ourselves to also maintain that.
|
|
// FIXME: the shortcut behaves differently than the long way: it discards any existing progress. Doesn't violate immut, but is odd.
|
|
*na.w = *v2
|
|
na.state = maState_finished
|
|
return nil
|
|
}
|
|
// If the above shortcut didn't work, resort to a generic copy.
|
|
// We call AssignNode for all the child values, giving them a chance to hit shortcuts even if we didn't.
|
|
if v.Kind() != datamodel.Kind_Map {
|
|
return datamodel.ErrWrongKind{TypeName: "map", MethodName: "AssignNode", AppropriateKind: datamodel.KindSet_JustMap, ActualKind: v.Kind()}
|
|
}
|
|
itr := v.MapIterator()
|
|
for !itr.Done() {
|
|
k, v, err := itr.Next()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := na.AssembleKey().AssignNode(k); err != nil {
|
|
return err
|
|
}
|
|
if err := na.AssembleValue().AssignNode(v); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return na.Finish()
|
|
}
|
|
func (plainMap__Assembler) Prototype() datamodel.NodePrototype {
|
|
return Prototype.Map
|
|
}
|
|
|
|
// -- MapAssembler -->
|
|
|
|
// AssembleEntry is part of conforming to MapAssembler, which we do on
|
|
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
|
|
func (ma *plainMap__Assembler) AssembleEntry(k string) (datamodel.NodeAssembler, error) {
|
|
// Sanity check assembler state.
|
|
// Update of state comes after possible key rejection.
|
|
if ma.state != maState_initial {
|
|
panic("misuse")
|
|
}
|
|
// Check for dup keys; error if so.
|
|
_, exists := ma.w.m[k]
|
|
if exists {
|
|
return nil, datamodel.ErrRepeatedMapKey{Key: plainString(k)}
|
|
}
|
|
ma.state = maState_midValue
|
|
ma.w.t = append(ma.w.t, plainMap__Entry{k: plainString(k)})
|
|
// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
|
|
ma.va.ma = ma
|
|
return &ma.va, nil
|
|
}
|
|
|
|
// AssembleKey is part of conforming to MapAssembler, which we do on
|
|
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
|
|
func (ma *plainMap__Assembler) AssembleKey() datamodel.NodeAssembler {
|
|
// Sanity check, then update, assembler state.
|
|
if ma.state != maState_initial {
|
|
panic("misuse")
|
|
}
|
|
ma.state = maState_midKey
|
|
// Make key assembler valid by giving it pointer back to whole 'ma'; yield it.
|
|
ma.ka.ma = ma
|
|
return &ma.ka
|
|
}
|
|
|
|
// AssembleValue is part of conforming to MapAssembler, which we do on
|
|
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
|
|
func (ma *plainMap__Assembler) AssembleValue() datamodel.NodeAssembler {
|
|
// Sanity check, then update, assembler state.
|
|
if ma.state != maState_expectValue {
|
|
panic("misuse")
|
|
}
|
|
ma.state = maState_midValue
|
|
// Make value assembler valid by giving it pointer back to whole 'ma'; yield it.
|
|
ma.va.ma = ma
|
|
return &ma.va
|
|
}
|
|
|
|
// Finish is part of conforming to MapAssembler, which we do on
|
|
// plainMap__Assembler so that BeginMap can just return a retyped pointer rather than new object.
|
|
func (ma *plainMap__Assembler) Finish() error {
|
|
// Sanity check, then update, assembler state.
|
|
if ma.state != maState_initial {
|
|
panic("misuse")
|
|
}
|
|
ma.state = maState_finished
|
|
// validators could run and report errors promptly, if this type had any.
|
|
return nil
|
|
}
|
|
func (plainMap__Assembler) KeyPrototype() datamodel.NodePrototype {
|
|
return Prototype__String{}
|
|
}
|
|
func (plainMap__Assembler) ValuePrototype(_ string) datamodel.NodePrototype {
|
|
return Prototype.Any
|
|
}
|
|
|
|
// -- MapAssembler.KeyAssembler -->
|
|
|
|
func (plainMap__KeyAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
|
|
return mixins.StringAssembler{TypeName: "string"}.BeginMap(0)
|
|
}
|
|
func (plainMap__KeyAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
|
|
return mixins.StringAssembler{TypeName: "string"}.BeginList(0)
|
|
}
|
|
func (plainMap__KeyAssembler) AssignNull() error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignNull()
|
|
}
|
|
func (plainMap__KeyAssembler) AssignBool(bool) error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignBool(false)
|
|
}
|
|
func (plainMap__KeyAssembler) AssignInt(int64) error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignInt(0)
|
|
}
|
|
func (plainMap__KeyAssembler) AssignFloat(float64) error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignFloat(0)
|
|
}
|
|
func (mka *plainMap__KeyAssembler) AssignString(v string) error {
|
|
// Check for dup keys; error if so.
|
|
// (And, backtrack state to accepting keys again so we don't get eternally wedged here.)
|
|
_, exists := mka.ma.w.m[v]
|
|
if exists {
|
|
mka.ma.state = maState_initial
|
|
mka.ma = nil // invalidate self to prevent further incorrect use.
|
|
return datamodel.ErrRepeatedMapKey{Key: plainString(v)}
|
|
}
|
|
// Assign the key into the end of the entry table;
|
|
// we'll be doing map insertions after we get the value in hand.
|
|
// (There's no need to delegate to another assembler for the key type,
|
|
// because we're just at Data Model level here, which only regards plain strings.)
|
|
mka.ma.w.t = append(mka.ma.w.t, plainMap__Entry{})
|
|
mka.ma.w.t[len(mka.ma.w.t)-1].k = plainString(v)
|
|
// Update parent assembler state: clear to proceed.
|
|
mka.ma.state = maState_expectValue
|
|
mka.ma = nil // invalidate self to prevent further incorrect use.
|
|
return nil
|
|
}
|
|
func (plainMap__KeyAssembler) AssignBytes([]byte) error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignBytes(nil)
|
|
}
|
|
func (plainMap__KeyAssembler) AssignLink(datamodel.Link) error {
|
|
return mixins.StringAssembler{TypeName: "string"}.AssignLink(nil)
|
|
}
|
|
func (mka *plainMap__KeyAssembler) AssignNode(v datamodel.Node) error {
|
|
vs, err := v.AsString()
|
|
if err != nil {
|
|
return fmt.Errorf("cannot assign non-string node into map key assembler") // FIXME:errors: this doesn't quite fit in ErrWrongKind cleanly; new error type?
|
|
}
|
|
return mka.AssignString(vs)
|
|
}
|
|
func (plainMap__KeyAssembler) Prototype() datamodel.NodePrototype {
|
|
return Prototype__String{}
|
|
}
|
|
|
|
// -- MapAssembler.ValueAssembler -->
|
|
|
|
func (mva *plainMap__ValueAssembler) BeginMap(sizeHint int64) (datamodel.MapAssembler, error) {
|
|
ma := plainMap__ValueAssemblerMap{}
|
|
ma.ca.w = &plainMap{}
|
|
ma.p = mva.ma
|
|
_, err := ma.ca.BeginMap(sizeHint)
|
|
return &ma, err
|
|
}
|
|
func (mva *plainMap__ValueAssembler) BeginList(sizeHint int64) (datamodel.ListAssembler, error) {
|
|
la := plainMap__ValueAssemblerList{}
|
|
la.ca.w = &plainList{}
|
|
la.p = mva.ma
|
|
_, err := la.ca.BeginList(sizeHint)
|
|
return &la, err
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignNull() error {
|
|
return mva.AssignNode(datamodel.Null)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignBool(v bool) error {
|
|
vb := plainBool(v)
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignInt(v int64) error {
|
|
vb := plainInt(v)
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignFloat(v float64) error {
|
|
vb := plainFloat(v)
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignString(v string) error {
|
|
vb := plainString(v)
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignBytes(v []byte) error {
|
|
vb := plainBytes(v)
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignLink(v datamodel.Link) error {
|
|
vb := plainLink{v}
|
|
return mva.AssignNode(&vb)
|
|
}
|
|
func (mva *plainMap__ValueAssembler) AssignNode(v datamodel.Node) error {
|
|
l := len(mva.ma.w.t) - 1
|
|
mva.ma.w.t[l].v = v
|
|
mva.ma.w.m[string(mva.ma.w.t[l].k)] = v
|
|
mva.ma.state = maState_initial
|
|
mva.ma = nil // invalidate self to prevent further incorrect use.
|
|
return nil
|
|
}
|
|
func (plainMap__ValueAssembler) Prototype() datamodel.NodePrototype {
|
|
return Prototype.Any
|
|
}
|
|
|
|
type plainMap__ValueAssemblerMap struct {
|
|
ca plainMap__Assembler
|
|
p *plainMap__Assembler // pointer back to parent, for final insert and state bump
|
|
}
|
|
|
|
// we briefly state only the methods we need to delegate here.
|
|
// just embedding plainMap__Assembler also behaves correctly,
|
|
// but causes a lot of unnecessary autogenerated functions in the final binary.
|
|
|
|
func (ma *plainMap__ValueAssemblerMap) AssembleEntry(k string) (datamodel.NodeAssembler, error) {
|
|
return ma.ca.AssembleEntry(k)
|
|
}
|
|
func (ma *plainMap__ValueAssemblerMap) AssembleKey() datamodel.NodeAssembler {
|
|
return ma.ca.AssembleKey()
|
|
}
|
|
func (ma *plainMap__ValueAssemblerMap) AssembleValue() datamodel.NodeAssembler {
|
|
return ma.ca.AssembleValue()
|
|
}
|
|
func (plainMap__ValueAssemblerMap) KeyPrototype() datamodel.NodePrototype {
|
|
return Prototype__String{}
|
|
}
|
|
func (plainMap__ValueAssemblerMap) ValuePrototype(_ string) datamodel.NodePrototype {
|
|
return Prototype.Any
|
|
}
|
|
|
|
func (ma *plainMap__ValueAssemblerMap) Finish() error {
|
|
if err := ma.ca.Finish(); err != nil {
|
|
return err
|
|
}
|
|
w := ma.ca.w
|
|
ma.ca.w = nil
|
|
return ma.p.va.AssignNode(w)
|
|
}
|
|
|
|
type plainMap__ValueAssemblerList struct {
|
|
ca plainList__Assembler
|
|
p *plainMap__Assembler // pointer back to parent, for final insert and state bump
|
|
}
|
|
|
|
// we briefly state only the methods we need to delegate here.
|
|
// just embedding plainList__Assembler also behaves correctly,
|
|
// but causes a lot of unnecessary autogenerated functions in the final binary.
|
|
|
|
func (la *plainMap__ValueAssemblerList) AssembleValue() datamodel.NodeAssembler {
|
|
return la.ca.AssembleValue()
|
|
}
|
|
func (plainMap__ValueAssemblerList) ValuePrototype(_ int64) datamodel.NodePrototype {
|
|
return Prototype.Any
|
|
}
|
|
|
|
func (la *plainMap__ValueAssemblerList) Finish() error {
|
|
if err := la.ca.Finish(); err != nil {
|
|
return err
|
|
}
|
|
w := la.ca.w
|
|
la.ca.w = nil
|
|
return la.p.va.AssignNode(w)
|
|
}
|