Integrate BACKBEAT SDK and resolve KACHING license validation

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>
This commit is contained in:
anthonyrawlins
2025-09-06 07:56:26 +10:00
parent 543ab216f9
commit 9bdcbe0447
4730 changed files with 1480093 additions and 1916 deletions

44
vendor/github.com/polydawn/refmt/cbor/cborCommon.go generated vendored Normal file
View File

@@ -0,0 +1,44 @@
package cbor
// "Major types" enum, as per https://tools.ietf.org/html/rfc7049#section-2.1 .
//
// These numbers are the bottom of the range for that major type when encoded;
// that is, ints can be between `cborMajorUint` (inclusive) and `cborMajorNegInt` (exclusive).
// Zero out the 0x1f bitrange of a byte to see which major type it is (those bits are
// used for packing either length info or other specific enumerated meanings).
const (
cborMajorUint byte = 0x00
cborMajorNegInt = 0x20
cborMajorBytes = 0x40
cborMajorString = 0x60
cborMajorArray = 0x80
cborMajorMap = 0xa0
cborMajorTag = 0xc0
cborMajorSimple = 0xe0 // Floating point, "simple" types like bool, etc, are above.
)
// Enumeration of some values with single fixed-byte representations.
// All of these are in the "simple" space.
// See https://tools.ietf.org/html/rfc7049#section-2.3 for tables.
// The prefix indicating a float is also packed into the simple space.
const (
cborSigilFalse byte = 0xf4
cborSigilTrue = 0xf5
cborSigilNil = 0xf6
cborSigilUndefined = 0xf7
cborSigilFloat16 = 0xf9
cborSigilFloat32 = 0xfA
cborSigilFloat64 = 0xfB
)
// The highest value in the range for bytes, text, arrays, and maps all indicate
// an "indefinite length" / "streaming" entry coming up. These have a different parse path.
// The special 'break' value from the "simple" space (all bits on)
// indicates termination of stream for all four kinds major types in this mode.
const (
cborSigilIndefiniteBytes byte = 0x5f
cborSigilIndefiniteString = 0x7f
cborSigilIndefiniteArray = 0x9f
cborSigilIndefiniteMap = 0xbf
cborSigilBreak = 0xff
)

309
vendor/github.com/polydawn/refmt/cbor/cborDecoder.go generated vendored Normal file
View File

@@ -0,0 +1,309 @@
package cbor
import (
"fmt"
"io"
"github.com/polydawn/refmt/shared"
. "github.com/polydawn/refmt/tok"
)
type Decoder struct {
cfg DecodeOptions
r shared.SlickReader
stack []decoderPhase // When empty, and step returns done, all done.
phase decoderPhase // Shortcut to end of stack.
left []int // Statekeeping space for definite-len map and array.
}
type decoderPhase uint8
const (
decoderPhase_acceptValue decoderPhase = iota
decoderPhase_acceptArrValueOrBreak
decoderPhase_acceptMapIndefKey
decoderPhase_acceptMapIndefValueOrBreak
decoderPhase_acceptArrValue
decoderPhase_acceptMapKey
decoderPhase_acceptMapValue
)
func NewDecoder(cfg DecodeOptions, r io.Reader) (d *Decoder) {
d = &Decoder{
cfg: cfg,
r: shared.NewReader(r),
stack: make([]decoderPhase, 0, 10),
left: make([]int, 0, 10),
}
d.phase = decoderPhase_acceptValue
return
}
func (d *Decoder) Reset() {
d.stack = d.stack[0:0]
d.phase = decoderPhase_acceptValue
d.left = d.left[0:0]
}
type decoderStep func(tokenSlot *Token) (done bool, err error)
func (d *Decoder) Step(tokenSlot *Token) (done bool, err error) {
switch d.phase {
case decoderPhase_acceptValue:
done, err = d.step_acceptValue(tokenSlot)
case decoderPhase_acceptArrValueOrBreak:
done, err = d.step_acceptArrValueOrBreak(tokenSlot)
case decoderPhase_acceptMapIndefKey:
done, err = d.step_acceptMapIndefKey(tokenSlot)
case decoderPhase_acceptMapIndefValueOrBreak:
done, err = d.step_acceptMapIndefValueOrBreak(tokenSlot)
case decoderPhase_acceptArrValue:
done, err = d.step_acceptArrValue(tokenSlot)
case decoderPhase_acceptMapKey:
done, err = d.step_acceptMapKey(tokenSlot)
case decoderPhase_acceptMapValue:
done, err = d.step_acceptMapValue(tokenSlot)
}
// If the step errored: out, entirely.
if err != nil {
return true, err
}
// If the step wasn't done, return same status.
if !done {
return false, nil
}
// If it WAS done, pop next, or if stack empty, we're entirely done.
nSteps := len(d.stack) - 1
if nSteps <= 0 {
return true, nil // that's all folks
}
d.phase = d.stack[nSteps]
d.stack = d.stack[0:nSteps]
return false, nil
}
func (d *Decoder) pushPhase(newPhase decoderPhase) {
d.stack = append(d.stack, d.phase)
d.phase = newPhase
}
// The original step, where any value is accepted, and no terminators for composites are valid.
// ONLY used in the original step; all other steps handle leaf nodes internally.
func (d *Decoder) step_acceptValue(tokenSlot *Token) (done bool, err error) {
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
tokenSlot.Tagged = false
return d.stepHelper_acceptValue(majorByte, tokenSlot)
}
// Step in midst of decoding an indefinite-length array.
func (d *Decoder) step_acceptArrValueOrBreak(tokenSlot *Token) (done bool, err error) {
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
tokenSlot.Tagged = false
switch majorByte {
case cborSigilBreak:
tokenSlot.Type = TArrClose
return true, nil
default:
_, err := d.stepHelper_acceptValue(majorByte, tokenSlot)
return false, err
}
}
// Step in midst of decoding an indefinite-length map, key expected up next, or end.
func (d *Decoder) step_acceptMapIndefKey(tokenSlot *Token) (done bool, err error) {
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
tokenSlot.Tagged = false
switch majorByte {
case cborSigilBreak:
tokenSlot.Type = TMapClose
return true, nil
default:
d.phase = decoderPhase_acceptMapIndefValueOrBreak
_, err := d.stepHelper_acceptValue(majorByte, tokenSlot) // FIXME surely not *any* value? not composites, at least?
return false, err
}
}
// Step in midst of decoding an indefinite-length map, value expected up next.
func (d *Decoder) step_acceptMapIndefValueOrBreak(tokenSlot *Token) (done bool, err error) {
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
tokenSlot.Tagged = false
switch majorByte {
case cborSigilBreak:
return true, fmt.Errorf("unexpected break; expected value in indefinite-length map")
default:
d.phase = decoderPhase_acceptMapIndefKey
_, err = d.stepHelper_acceptValue(majorByte, tokenSlot)
return false, err
}
}
// Step in midst of decoding a definite-length array.
func (d *Decoder) step_acceptArrValue(tokenSlot *Token) (done bool, err error) {
// Yield close token, pop state, and return done flag if expecting no more entries.
ll := len(d.left) - 1
if d.left[ll] == 0 {
d.left = d.left[0:ll]
tokenSlot.Type = TArrClose
return true, nil
}
d.left[ll]--
// Read next value.
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
tokenSlot.Tagged = false
_, err = d.stepHelper_acceptValue(majorByte, tokenSlot)
return false, err
}
// Step in midst of decoding an definite-length map, key expected up next.
func (d *Decoder) step_acceptMapKey(tokenSlot *Token) (done bool, err error) {
// Yield close token, pop state, and return done flag if expecting no more entries.
ll := len(d.left) - 1
if d.left[ll] == 0 {
d.left = d.left[0:ll]
tokenSlot.Type = TMapClose
return true, nil
}
d.left[ll]--
// Read next key.
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
d.phase = decoderPhase_acceptMapValue
tokenSlot.Tagged = false
_, err = d.stepHelper_acceptValue(majorByte, tokenSlot) // FIXME surely not *any* value? not composites, at least?
return false, err
}
// Step in midst of decoding an definite-length map, value expected up next.
func (d *Decoder) step_acceptMapValue(tokenSlot *Token) (done bool, err error) {
// Read next value.
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
d.phase = decoderPhase_acceptMapKey
tokenSlot.Tagged = false
_, err = d.stepHelper_acceptValue(majorByte, tokenSlot)
return false, err
}
func (d *Decoder) stepHelper_acceptValue(majorByte byte, tokenSlot *Token) (done bool, err error) {
switch majorByte {
case cborSigilNil:
tokenSlot.Type = TNull
return true, nil
case cborSigilUndefined:
if d.cfg.CoerceUndefToNull {
tokenSlot.Type = TNull
return true, nil
}
return true, fmt.Errorf("encountered cbor 'undefined' byte (%x) during decoding", cborSigilUndefined)
case cborSigilFalse:
tokenSlot.Type = TBool
tokenSlot.Bool = false
return true, nil
case cborSigilTrue:
tokenSlot.Type = TBool
tokenSlot.Bool = true
return true, nil
case cborSigilFloat16, cborSigilFloat32, cborSigilFloat64:
tokenSlot.Type = TFloat64
tokenSlot.Float64, err = d.decodeFloat(majorByte)
return true, err
case cborSigilIndefiniteBytes:
tokenSlot.Type = TBytes
tokenSlot.Bytes, err = d.decodeBytesIndefinite(nil)
return true, err
case cborSigilIndefiniteString:
tokenSlot.Type = TString
tokenSlot.Str, err = d.decodeStringIndefinite()
return true, err
case cborSigilIndefiniteArray:
tokenSlot.Type = TArrOpen
tokenSlot.Length = -1
d.pushPhase(decoderPhase_acceptArrValueOrBreak)
return false, nil
case cborSigilIndefiniteMap:
tokenSlot.Type = TMapOpen
tokenSlot.Length = -1
d.pushPhase(decoderPhase_acceptMapIndefKey)
return false, nil
default:
switch {
case majorByte >= cborMajorUint && majorByte < cborMajorNegInt:
tokenSlot.Type = TUint
tokenSlot.Uint, err = d.decodeUint(majorByte)
return true, err
case majorByte >= cborMajorNegInt && majorByte < cborMajorBytes:
tokenSlot.Type = TInt
tokenSlot.Int, err = d.decodeNegInt(majorByte)
return true, err
case majorByte >= cborMajorBytes && majorByte < cborMajorString:
tokenSlot.Type = TBytes
tokenSlot.Bytes, err = d.decodeBytes(majorByte)
return true, err
case majorByte >= cborMajorString && majorByte < cborMajorArray:
tokenSlot.Type = TString
tokenSlot.Str, err = d.decodeString(majorByte)
return true, err
case majorByte >= cborMajorArray && majorByte < cborMajorMap:
var n int
n, err = d.decodeLen(majorByte)
tokenSlot.Type = TArrOpen
tokenSlot.Length = n
d.left = append(d.left, n)
d.pushPhase(decoderPhase_acceptArrValue)
return false, err
case majorByte >= cborMajorMap && majorByte < cborMajorTag:
var n int
n, err = d.decodeLen(majorByte)
tokenSlot.Type = TMapOpen
tokenSlot.Length = n
d.left = append(d.left, n)
d.pushPhase(decoderPhase_acceptMapKey)
return false, err
case majorByte >= cborMajorTag && majorByte < cborMajorSimple:
// CBOR tags are, frankly, bonkers, and should not be used.
// They break isomorphism to basic standards like JSON.
// We'll parse basic integer tag values -- SINGLE layer only.
// We will NOT parse the full gamut of recursive tags: doing so
// would mean allowing an unbounded number of allocs *during
// *processing of a single token*, which is _not reasonable_.
if tokenSlot.Tagged {
return true, fmt.Errorf("unsupported multiple tags on a single data item")
}
tokenSlot.Tagged = true
tokenSlot.Tag, err = d.decodeLen(majorByte)
if err != nil {
return true, err
}
// Okay, we slurped a tag.
// Read next value.
majorByte, err := d.r.Readn1()
if err != nil {
return true, err
}
return d.stepHelper_acceptValue(majorByte, tokenSlot)
default:
return true, fmt.Errorf("Invalid majorByte: 0x%x", majorByte)
}
}
}

View File

@@ -0,0 +1,235 @@
package cbor
import (
"encoding/binary"
"errors"
"fmt"
"math"
)
const (
maxUint = ^uint(0)
maxInt = int(maxUint >> 1)
)
func (d *Decoder) decodeFloat(majorByte byte) (f float64, err error) {
var bs []byte
switch majorByte {
case cborSigilFloat16:
bs, err = d.r.Readnzc(2)
f = float64(math.Float32frombits(halfFloatToFloatBits(binary.BigEndian.Uint16(bs))))
case cborSigilFloat32:
bs, err = d.r.Readnzc(4)
f = float64(math.Float32frombits(binary.BigEndian.Uint32(bs)))
case cborSigilFloat64:
bs, err = d.r.Readnzc(8)
f = math.Float64frombits(binary.BigEndian.Uint64(bs))
}
return
}
// Decode an unsigned int.
// Must continue to hand down the majorByte because some of its bits are either
// packed with the value outright, or tell us how many more bytes the value fills.
func (d *Decoder) decodeUint(majorByte byte) (ui uint64, err error) {
v := majorByte & 0x1f
if v <= 0x17 {
ui = uint64(v)
} else {
if v == 0x18 {
var b byte
b, err = d.r.Readn1()
ui = uint64(b)
} else if v == 0x19 {
var bs []byte
bs, err = d.r.Readnzc(2)
ui = uint64(binary.BigEndian.Uint16(bs))
} else if v == 0x1a {
var bs []byte
bs, err = d.r.Readnzc(4)
ui = uint64(binary.BigEndian.Uint32(bs))
} else if v == 0x1b {
var bs []byte
bs, err = d.r.Readnzc(8)
ui = uint64(binary.BigEndian.Uint64(bs))
} else {
err = fmt.Errorf("decodeUint: Invalid descriptor: %v", majorByte)
return
}
}
return
}
// Decode a *negative* integer.
// Note that CBOR has a very funny-shaped hole here: there is unsigned positive int,
// and there is explicitly negative signed int... and there is no signed, positive int.
// *We have no 'decodeInt' function because that **doesn't exist** in CBOR.*
// So! Hopefully our consumer doesn't mind having to cast uints to ints fairly frequently.
func (d *Decoder) decodeNegInt(majorByte byte) (i int64, err error) {
// The packed bits in the majorByte and the following bytes if any are layed out
// the exact same as a uint; only the major type bits are different.
ui, err := d.decodeUint(majorByte)
if err != nil {
return 0, err
}
pos := ui + 1
if pos > uint64(-math.MinInt64) {
return -1, errors.New("cbor: negative integer out of rage of int64 type")
}
return -int64(pos), nil
}
// Decode expecting a positive integer.
// None of our token-yielding functions call this directly;
// it's used inside the library when we expect to read e.g. a length header.
// Does not check that your majorByte indicates an integer type at all;
// in context, it often doesn't, e.g. when decoding the length of a string.
func (d *Decoder) decodeLen(majorByte byte) (i int, err error) {
ui, err := d.decodeUint(majorByte)
if err != nil {
return 0, err
}
if ui > uint64(maxInt) {
return 0, errors.New("cbor: positive integer is out of length")
}
return int(ui), nil
}
// Decoding indefinite-length byte strings in cbor is actually decoding a sequence of
// definite-length byte strings until you encounter a break.
// Caller: use `bs[:0]` if you have something to reuse, or nil
func (d *Decoder) decodeBytesIndefinite(bs []byte) (bsOut []byte, err error) {
return d.decodeBytesOrStringIndefinite(bs, cborMajorBytes)
}
func (d *Decoder) decodeStringIndefinite() (s string, err error) {
bs, err := d.decodeBytesOrStringIndefinite(nil, cborMajorString)
if err != nil {
return "", err
}
return string(bs), nil
}
func (d *Decoder) decodeBytesOrStringIndefinite(bs []byte, majorWanted byte) (bsOut []byte, err error) {
if bs == nil {
bs = make([]byte, 0, 16)
}
var n int
for {
// Read first byte; check for break, or hunk, or invalid.
// (It's not necessary to have the first majorByte as a param to this function, because
// indefinite length sequences have a separate sigil which doesn't pack any len info.)
majorByte, err := d.r.Readn1()
if err != nil {
return bs, err
}
if majorByte == cborSigilBreak {
return bs, nil
} else if major := majorByte | 0x1f - 0x1f; major != majorWanted {
return bs, fmt.Errorf("cbor: expect bytes or string major type in indefinite string/bytes; got: %v, byte: %v", major, majorByte)
}
// Read length header for this hunk, and ensure we have at least that much cap.
n, err = d.decodeLen(majorByte)
if err != nil {
return bs, err
}
oldLen := len(bs)
newLen := oldLen + n
if n > 33554432 {
return nil, fmt.Errorf("cbor: decoding rejected oversized indefinite string/bytes field: %d is too large", n)
}
if newLen > cap(bs) {
bs2 := make([]byte, newLen, 2*cap(bs)+n)
copy(bs2, bs)
bs = bs2
} else {
bs = bs[:newLen]
}
// Read that hunk.
d.r.Readb(bs[oldLen:newLen])
}
}
// Decode a single length-prefixed hunk of bytes.
//
// There are a number of ways this may try to conserve allocations:
//
// - If you say zerocopy=true, and the underlying reader system already has an
// appropriate byte slice available, then a slice from that will be returned.
//
// - If you provide a byte slice, we will attempt to use it.
// The byte slice is truncated and used for its capacity only -- not appended.
// The final returned slice may be a different one if the provided slice did not
// have sufficient capacity.
//
// - If you say zerocopy=true, and the underlying read system doesn't have an
// efficient way to yield a slice of its internal buffer, and you provided no
// destination slice, then we will use a recycleable piece of memory in the Decoder
// state and return a slice viewing into it. For small values this will
// likely save an alloc.
//
// The above rules are resolved in this order; e.g. your byte slice is disregarded
// if zerocopy=true and the underlying reader can do something even more efficient,
// though there is also no harm to providing the slice argument.
// Generally, set zerocopy if you know you're not going to publicly yield the results,
// and the implementation will do its best to be as efficient as possible.
//
// Zerocopy is appropriate when planning to turn the bytes into a string, for example,
// since in that path we know the slice will be treated immutably, not publicly
// exposed, and also any other copy to another intermediate is definitely useless.
func (d *Decoder) decodeBytes(majorByte byte) (bs []byte, err error) {
n, err := d.decodeLen(majorByte)
if err != nil {
return nil, err
}
if n > 33554432 {
return nil, fmt.Errorf("cbor: decoding rejected oversized byte field: %d is too large", n)
}
return d.r.Readn(n)
}
// Decode a single length-prefixed string.
func (d *Decoder) decodeString(majorByte byte) (s string, err error) {
n, err := d.decodeLen(majorByte)
if err != nil {
return "", err
}
if n > 33554432 {
return "", fmt.Errorf("cbor: decoding rejected oversized string field: %d is too large", n)
}
bs, err := d.r.Readnzc(n)
return string(bs), err
}
// culled from OGRE (Object-Oriented Graphics Rendering Engine)
// function: halfToFloatI (http://stderr.org/doc/ogre-doc/api/OgreBitwise_8h-source.html)
func halfFloatToFloatBits(yy uint16) (d uint32) {
y := uint32(yy)
s := (y >> 15) & 0x01
e := (y >> 10) & 0x1f
m := y & 0x03ff
if e == 0 {
if m == 0 { // plu or minus 0
return s << 31
} else { // Denormalized number -- renormalize it
for (m & 0x00000400) == 0 {
m <<= 1
e -= 1
}
e += 1
const zz uint32 = 0x0400
m &= ^zz
}
} else if e == 31 {
if m == 0 { // Inf
return (s << 31) | 0x7f800000
} else { // NaN
return (s << 31) | 0x7f800000 | (m << 13)
}
}
e = e + (127 - 15)
m = m << 13
return (s << 31) | (e << 23) | m
}

276
vendor/github.com/polydawn/refmt/cbor/cborEncoder.go generated vendored Normal file
View File

@@ -0,0 +1,276 @@
package cbor
import (
"io"
. "github.com/polydawn/refmt/tok"
)
type Encoder struct {
w quickWriter
stack []encoderPhase // When empty, and step returns done, all done.
current encoderPhase // Shortcut to end of stack.
// Note unlike decoder, we need no statekeeping space for definite-len map and array.
spareBytes []byte
}
func NewEncoder(w io.Writer) (d *Encoder) {
d = &Encoder{
w: newQuickWriterStream(w),
stack: make([]encoderPhase, 0, 10),
current: phase_anyExpectValue,
spareBytes: make([]byte, 8),
}
return
}
func (d *Encoder) Reset() {
d.stack = d.stack[0:0]
d.current = phase_anyExpectValue
}
type encoderPhase byte
// There's about twice as many phases that the cbor encoder can be in compared to the json encoder
// because the presense of indefinite vs definite length maps and arrays effectively adds a dimension to those.
const (
phase_anyExpectValue encoderPhase = iota
phase_mapDefExpectKeyOrEnd // must not yield break at end
phase_mapDefExpectValue // only necessary to flip back to DefExpectKey
phase_mapIndefExpectKeyOrEnd // must yield break at end
phase_mapIndefExpectValue // only necessary to flip back to IndefExpectKey
phase_arrDefExpectValueOrEnd // must not yield break at end
phase_arrIndefExpectValueOrEnd // must yield break at end
)
func (d *Encoder) pushPhase(p encoderPhase) {
d.current = p
d.stack = append(d.stack, d.current)
}
// Pop a phase from the stack; return 'true' if stack now empty.
func (d *Encoder) popPhase() bool {
n := len(d.stack) - 1
if n == 0 {
return true
}
if n < 0 { // the state machines are supposed to have already errored better
panic("cborEncoder stack overpopped")
}
d.current = d.stack[n-1]
d.stack = d.stack[0:n]
return false
}
func (d *Encoder) Step(tokenSlot *Token) (done bool, err error) {
/*
Though it reads somewhat backwards from how a human would probably intuit
cause and effect, switching on the token type we got first,
*then* switching for whether it is acceptable for our current phase... is by
far the shorter volume of code to write.
*/
phase := d.current
switch tokenSlot.Type {
case TMapOpen:
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
if tokenSlot.Length >= 0 {
d.pushPhase(phase_mapDefExpectKeyOrEnd)
d.emitMajorPlusLen(cborMajorMap, uint64(tokenSlot.Length))
} else {
d.pushPhase(phase_mapIndefExpectKeyOrEnd)
d.w.writen1(cborSigilIndefiniteMap)
}
return false, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TMapClose:
switch phase {
case phase_mapDefExpectKeyOrEnd:
return d.popPhase(), nil
case phase_mapIndefExpectKeyOrEnd:
d.w.writen1(cborSigilBreak)
return d.popPhase(), d.w.checkErr()
case phase_anyExpectValue, phase_mapDefExpectValue, phase_mapIndefExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForValue}
default:
panic("unreachable phase")
}
case TArrOpen:
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
if tokenSlot.Length >= 0 {
d.pushPhase(phase_arrDefExpectValueOrEnd)
d.emitMajorPlusLen(cborMajorArray, uint64(tokenSlot.Length))
} else {
d.pushPhase(phase_arrIndefExpectValueOrEnd)
d.w.writen1(cborSigilIndefiniteArray)
}
return false, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TArrClose:
switch phase {
case phase_arrDefExpectValueOrEnd:
return d.popPhase(), nil
case phase_arrIndefExpectValueOrEnd:
d.w.writen1(cborSigilBreak)
return d.popPhase(), d.w.checkErr()
case phase_anyExpectValue, phase_mapDefExpectValue, phase_mapIndefExpectValue:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForValue}
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TNull: // terminal value; not accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.w.writen1(cborSigilNil)
return phase == phase_anyExpectValue, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TString: // terminal value; YES, accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
goto emitStr
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
d.current += 1
goto emitStr
default:
panic("unreachable phase")
}
emitStr:
{
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeString(tokenSlot.Str)
return phase == phase_anyExpectValue, d.w.checkErr()
}
case TBytes: // terminal value; not accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeBytes(tokenSlot.Bytes)
return phase == phase_anyExpectValue, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TBool: // terminal value; not accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeBool(tokenSlot.Bool)
return phase == phase_anyExpectValue, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
case TInt: // terminal value; YES, accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
goto emitInt
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
d.current += 1
goto emitInt
default:
panic("unreachable phase")
}
emitInt:
{
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeInt64(tokenSlot.Int)
return phase == phase_anyExpectValue, d.w.checkErr()
}
case TUint: // terminal value; YES, accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
goto emitUint
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
d.current += 1
goto emitUint
default:
panic("unreachable phase")
}
emitUint:
{
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeUint64(tokenSlot.Uint)
return phase == phase_anyExpectValue, d.w.checkErr()
}
case TFloat64: // terminal value; not accepted as map key.
switch phase {
case phase_mapDefExpectValue, phase_mapIndefExpectValue:
d.current -= 1
fallthrough
case phase_anyExpectValue, phase_arrDefExpectValueOrEnd, phase_arrIndefExpectValueOrEnd:
if tokenSlot.Tagged {
d.emitMajorPlusLen(cborMajorTag, uint64(tokenSlot.Tag))
}
d.encodeFloat64(tokenSlot.Float64)
return phase == phase_anyExpectValue, d.w.checkErr()
case phase_mapDefExpectKeyOrEnd, phase_mapIndefExpectKeyOrEnd:
return true, &ErrInvalidTokenStream{Got: *tokenSlot, Acceptable: tokenTypesForKey}
default:
panic("unreachable phase")
}
default:
panic("unhandled token type")
}
}

View File

@@ -0,0 +1,77 @@
package cbor
import (
"encoding/binary"
"math"
)
func (d *Encoder) emitLen(majorByte byte, length int) {
d.emitMajorPlusLen(majorByte, uint64(length))
}
func (d *Encoder) emitMajorPlusLen(majorByte byte, v uint64) {
if v <= 0x17 {
d.w.writen1(majorByte + byte(v))
} else if v <= math.MaxUint8 {
d.w.writen2(majorByte+0x18, uint8(v))
} else if v <= math.MaxUint16 {
d.w.writen1(majorByte + 0x19)
d.spareBytes = d.spareBytes[:2]
binary.BigEndian.PutUint16(d.spareBytes, uint16(v))
d.w.writeb(d.spareBytes)
} else if v <= math.MaxUint32 {
d.w.writen1(majorByte + 0x1a)
d.spareBytes = d.spareBytes[:4]
binary.BigEndian.PutUint32(d.spareBytes, uint32(v))
d.w.writeb(d.spareBytes)
} else { // if v <= math.MaxUint64 {
d.w.writen1(majorByte + 0x1b)
d.spareBytes = d.spareBytes[:8]
binary.BigEndian.PutUint64(d.spareBytes, v)
d.w.writeb(d.spareBytes)
}
}
func (d *Encoder) encodeNull() {
d.w.writen1(cborSigilNil)
}
func (d *Encoder) encodeString(s string) {
d.emitMajorPlusLen(cborMajorString, uint64(len(s)))
d.w.writestr(s)
}
func (d *Encoder) encodeBytes(bs []byte) {
d.emitMajorPlusLen(cborMajorBytes, uint64(len(bs)))
d.w.writeb(bs)
}
func (d *Encoder) encodeBool(b bool) {
if b {
d.w.writen1(cborSigilTrue)
} else {
d.w.writen1(cborSigilFalse)
}
}
func (d *Encoder) encodeInt64(v int64) {
if v >= 0 {
d.emitMajorPlusLen(cborMajorUint, uint64(v))
} else {
d.emitMajorPlusLen(cborMajorNegInt, uint64(-1-v))
}
}
func (d *Encoder) encodeUint64(v uint64) {
d.emitMajorPlusLen(cborMajorUint, v)
}
func (d *Encoder) encodeFloat64(v float64) {
// Can we pack it into 32? No idea: float precision is fraught with peril.
// See https://play.golang.org/p/u9sN6x0kk6
// So we *only* emit the full 64-bit style. The CBOR spec permits this.
d.w.writen1(cborSigilFloat64)
d.spareBytes = d.spareBytes[:8]
binary.BigEndian.PutUint64(d.spareBytes, math.Float64bits(v))
d.w.writeb(d.spareBytes)
}

106
vendor/github.com/polydawn/refmt/cbor/cborHelpers.go generated vendored Normal file
View File

@@ -0,0 +1,106 @@
package cbor
import (
"bytes"
"io"
"github.com/polydawn/refmt/obj"
"github.com/polydawn/refmt/obj/atlas"
"github.com/polydawn/refmt/shared"
)
// All of the methods in this file are exported,
// and their names and type declarations are intended to be
// identical to the naming and types of the golang stdlib
// 'encoding/json' packages, with ONE EXCEPTION:
// what stdlib calls "NewEncoder", we call "NewMarshaller";
// what stdlib calls "NewDecoder", we call "NewUnmarshaller";
// and similarly the types and methods are "Marshaller.Marshal"
// and "Unmarshaller.Unmarshal".
// You should be able to migrate with a sed script!
//
// (In refmt, the encoder/decoder systems are for token streams;
// if you're talking about object mapping, we consistently
// refer to that as marshalling/unmarshalling.)
//
// Most methods also have an "Atlased" variant,
// which lets you specify advanced type mapping instructions.
func Marshal(v interface{}) ([]byte, error) {
var buf bytes.Buffer
if err := NewMarshaller(&buf).Marshal(v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
func MarshalAtlased(v interface{}, atl atlas.Atlas) ([]byte, error) {
var buf bytes.Buffer
if err := NewMarshallerAtlased(&buf, atl).Marshal(v); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
type Marshaller struct {
marshaller *obj.Marshaller
encoder *Encoder
pump shared.TokenPump
}
func (x *Marshaller) Marshal(v interface{}) error {
x.marshaller.Bind(v)
x.encoder.Reset()
return x.pump.Run()
}
func NewMarshaller(wr io.Writer) *Marshaller {
return NewMarshallerAtlased(wr, atlas.MustBuild())
}
func NewMarshallerAtlased(wr io.Writer, atl atlas.Atlas) *Marshaller {
x := &Marshaller{
marshaller: obj.NewMarshaller(atl),
encoder: NewEncoder(wr),
}
x.pump = shared.TokenPump{
x.marshaller,
x.encoder,
}
return x
}
func Unmarshal(cfg DecodeOptions, data []byte, v interface{}) error {
return NewUnmarshaller(cfg, bytes.NewBuffer(data)).Unmarshal(v)
}
func UnmarshalAtlased(cfg DecodeOptions, data []byte, v interface{}, atl atlas.Atlas) error {
return NewUnmarshallerAtlased(cfg, bytes.NewBuffer(data), atl).Unmarshal(v)
}
type Unmarshaller struct {
unmarshaller *obj.Unmarshaller
decoder *Decoder
pump shared.TokenPump
}
func (x *Unmarshaller) Unmarshal(v interface{}) error {
x.unmarshaller.Bind(v)
x.decoder.Reset()
return x.pump.Run()
}
func NewUnmarshaller(cfg DecodeOptions, r io.Reader) *Unmarshaller {
return NewUnmarshallerAtlased(cfg, r, atlas.MustBuild())
}
func NewUnmarshallerAtlased(cfg DecodeOptions, r io.Reader, atl atlas.Atlas) *Unmarshaller {
x := &Unmarshaller{
unmarshaller: obj.NewUnmarshaller(atl),
decoder: NewDecoder(cfg, r),
}
x.pump = shared.TokenPump{
x.decoder,
x.unmarshaller,
}
return x
}

20
vendor/github.com/polydawn/refmt/cbor/cborOptions.go generated vendored Normal file
View File

@@ -0,0 +1,20 @@
package cbor
type EncodeOptions struct {
// there aren't a ton of options for cbor, but we still need this
// for use as a sigil for the top-level refmt methods to demux on.
}
// marker method -- you may use this type to instruct `refmt.Marshal`
// what kind of encoder to use.
func (EncodeOptions) IsEncodeOptions() {}
type DecodeOptions struct {
CoerceUndefToNull bool
// future: options to validate canonical serial order
}
// marker method -- you may use this type to instruct `refmt.Marshal`
// what kind of encoder to use.
func (DecodeOptions) IsDecodeOptions() {}

27
vendor/github.com/polydawn/refmt/cbor/doc.go generated vendored Normal file
View File

@@ -0,0 +1,27 @@
/*
Package implementing the CBOR -- Concise Binary Object Notation
-- http://cbor.io/ -- spec.
CBOR is more or less freely interchangable with json: it's schemaless,
and composed of similar map and array types.
However, CBOR is binary, length delimited -- and thus very fast to parse,
and can store binary data without expansion problems -- and also distinguishes
types like integer, string, float, and bytes all clearly from each other.
The `cbor.Marshal` and `cbor.Unmarshal` functions are the quickest way
to convert your Go objects to and from serial CBOR.
The `cbor.NewMarshaller` and `cbor.NewUmarshaller` functions give a little
more control. If performance is important, prefer these; recycling
the marshaller instances will significantly cut down on memory allocations
and improve performance.
The `*Atlased` variants of constructors allow you set up marshalling with
an `refmt/obj/atlas.Atlas`, unlocking all of refmt's advanced features
and custom object mapping powertools.
The `cbor.Encoder` and `cbor.Decoder` types implement the low-level functionality
of converting serial CBOR byte streams into refmt Token streams.
Users don't usually need to use these directly.
*/
package cbor

107
vendor/github.com/polydawn/refmt/cbor/encodeWriter.go generated vendored Normal file
View File

@@ -0,0 +1,107 @@
package cbor
import (
"fmt"
"io"
)
var (
_ quickWriter = &quickWriterStream{}
)
// quickWriter is implements several methods that are specificly useful to the performance
// needs of our encoders, and abstracts writing to a byte array or to an io.Writer.
type quickWriter interface {
writeb([]byte)
writestr(string)
writen1(byte)
writen2(byte, byte)
checkErr() error
clearErr()
}
// Interface used to detect if efficient string writing is supported.
// Same as in stdlib 'io' pkg; also not exported there, so we declare it again ourselves.
type stringWriter interface {
WriteString(s string) (n int, err error)
}
// quickWriterStream is a quickWriter that routes bytes to an io.Writer.
// While this implementation does use some internal buffers, it's still advisable
// to use a buffered writer to avoid small operations for any external IO like disk or network.
type quickWriterStream struct {
w io.Writer
ws stringWriter // nil if not available
scratch [2]byte
scratch1 []byte
scratch2 []byte
err error
}
func newQuickWriterStream(w io.Writer) *quickWriterStream {
z := &quickWriterStream{w: w}
if ws, ok := w.(stringWriter); ok {
z.ws = ws
}
z.scratch1 = z.scratch[:1]
z.scratch2 = z.scratch[:2]
return z
}
func (z *quickWriterStream) writeb(bs []byte) {
n, err := z.w.Write(bs)
if err != nil && z.err == nil {
z.err = err
}
if n < len(bs) && z.err == nil {
z.err = fmt.Errorf("underwrite")
}
}
func (z *quickWriterStream) writestr(s string) {
var n int
var err error
if z.ws != nil {
n, err = z.ws.WriteString(s)
} else {
n, err = z.w.Write([]byte(s)) // Notice: alloc!
}
if err != nil && z.err == nil {
z.err = err
}
if n < len(s) && z.err == nil {
z.err = fmt.Errorf("underwrite")
}
}
func (z *quickWriterStream) writen1(b byte) {
z.scratch1[0] = b
n, err := z.w.Write(z.scratch1)
if err != nil && z.err == nil {
z.err = err
}
if n < 1 && z.err == nil {
z.err = fmt.Errorf("underwrite")
}
}
func (z *quickWriterStream) writen2(b1 byte, b2 byte) {
z.scratch2[0] = b1
z.scratch2[1] = b2
n, err := z.w.Write(z.scratch2)
if err != nil && z.err == nil {
z.err = err
}
if n < 2 && z.err == nil {
z.err = fmt.Errorf("underwrite")
}
}
func (z *quickWriterStream) checkErr() error {
return z.err
}
func (z *quickWriterStream) clearErr() {
z.err = nil
}

22
vendor/github.com/polydawn/refmt/cbor/errors.go generated vendored Normal file
View File

@@ -0,0 +1,22 @@
package cbor
import (
"fmt"
. "github.com/polydawn/refmt/tok"
)
// Error raised by Encoder when invalid tokens or invalid ordering, e.g. a MapClose with no matching open.
// Should never be seen by the user in practice unless generating their own token streams.
type ErrInvalidTokenStream struct {
Got Token
Acceptable []TokenType
}
func (e *ErrInvalidTokenStream) Error() string {
return fmt.Sprintf("ErrInvalidTokenStream: unexpected %v, expected %v", e.Got, e.Acceptable)
// More comprehensible strings might include "start of value", "start of key or end of map", "start of value or end of array".
}
var tokenTypesForKey = []TokenType{TString, TInt, TUint}
var tokenTypesForValue = []TokenType{TMapOpen, TArrOpen, TNull, TString, TBytes, TInt, TUint, TFloat64}