O-2: C-S2: stateobjects.Ref, a body exactly {mesh-object: Ref} is a reference and anything else a value (milestone 47/G, issue 1966, ADR 0666 section 16)
Builds: design 47 G §57 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
@@ -26,7 +26,7 @@ var meshSDKPackages = []string{
|
||||
".", "announce", "announcetest", "buscalls", "buscompose", "busstate", "busretry", "calladdress", "catalogue",
|
||||
"declaration", "forgekey", "health", "internal/beside", "keys", "kvlimit", "membership", "motion",
|
||||
"objectlink", "outward", "pernode", "process",
|
||||
"sdkversion", "seal", "seatdef", "seatlist", "seatlist/seatlisttest", "testbus", "views", "views/viewstest",
|
||||
"sdkversion", "seal", "seatdef", "seatlist", "seatlist/seatlisttest", "stateobjects", "testbus", "views", "views/viewstest",
|
||||
}
|
||||
|
||||
// clientSeats are the seats whose logic is their client's in mesh-contracts (novox/hq ADR 0627 §1, §4): mesh-sdk names
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Package stateobjects keeps values of any size on the bus (novox/hq ADR 0666 §16, ADR 0595 §9): a value over the bus's
|
||||
// limit for one value, or a verb reply or an event over the limit for one message, is put in an object store and only its
|
||||
// reference travels. It is a small package of its own, imported only by the modules that use it: the module library (the
|
||||
// root package) and the process package do not import it, so their importers are not rebuilt when it changes. It names no
|
||||
// seat and no module, and imports no contracts module.
|
||||
package stateobjects
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// FormVersion is the version of the reference form; a reader refuses a reference of another.
|
||||
const FormVersion = 1
|
||||
|
||||
// refField is the one field of a body that is a reference.
|
||||
const refField = "mesh-object"
|
||||
|
||||
// Ref names an object in an object store: a body that is exactly `{"mesh-object": Ref}` is a reference, and anything
|
||||
// else is a value.
|
||||
type Ref struct {
|
||||
// Store is the object store's name as its reader asks for it: a bundle's local name, or the name a process opens.
|
||||
Store string `json:"store"`
|
||||
// Object is the object's name in that store.
|
||||
Object string `json:"object"`
|
||||
// Size is the object's size in bytes.
|
||||
Size int64 `json:"size"`
|
||||
// Digest is the hex SHA-256 of the object's bytes; a reader checks it after the read.
|
||||
Digest string `json:"sha256"`
|
||||
// Form is FormVersion.
|
||||
Form int `json:"form"`
|
||||
}
|
||||
|
||||
func (r Ref) valid() bool {
|
||||
if r.Store == "" || r.Object == "" || r.Size < 0 || r.Form != FormVersion || len(r.Digest) != 64 {
|
||||
return false
|
||||
}
|
||||
_, err := hex.DecodeString(r.Digest)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Wrap is the body that holds r.
|
||||
func Wrap(r Ref) []byte {
|
||||
raw, _ := json.Marshal(map[string]Ref{refField: r})
|
||||
return raw
|
||||
}
|
||||
|
||||
// ReadRef reads a body as a reference: ok is false for a value, including one that only looks like a reference (another
|
||||
// field beside it, a field it does not know, a digest that is no digest, another form).
|
||||
func ReadRef(body []byte) (Ref, bool) {
|
||||
var outer map[string]json.RawMessage
|
||||
if err := json.Unmarshal(body, &outer); err != nil || len(outer) != 1 {
|
||||
return Ref{}, false
|
||||
}
|
||||
raw, ok := outer[refField]
|
||||
if !ok {
|
||||
return Ref{}, false
|
||||
}
|
||||
dec := json.NewDecoder(bytes.NewReader(raw))
|
||||
dec.DisallowUnknownFields()
|
||||
var r Ref
|
||||
if err := dec.Decode(&r); err != nil || !r.valid() {
|
||||
return Ref{}, false
|
||||
}
|
||||
return r, true
|
||||
}
|
||||
|
||||
// errLooksLikeRef refuses a value that would be read back as a reference.
|
||||
var errLooksLikeRef = fmt.Errorf("the value is exactly a reference to an object (a body of the one field %q): it would be read as one", refField)
|
||||
@@ -0,0 +1,31 @@
|
||||
package stateobjects
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// ADR 0666 §16: a body is a reference when it is exactly `{"mesh-object": Ref}`; anything else is a value.
|
||||
func TestABodyIsAReferenceOnlyWhenItIsExactlyOne(t *testing.T) {
|
||||
good := Ref{Store: "views-objects", Object: "k." + strings.Repeat("a", 64), Size: 3 << 20, Digest: strings.Repeat("a", 64), Form: FormVersion}
|
||||
got, ok := ReadRef(Wrap(good))
|
||||
if !ok || got != good {
|
||||
t.Fatalf("round trip: %+v, %v", got, ok)
|
||||
}
|
||||
d := strings.Repeat("a", 64)
|
||||
rows := []struct{ name, body string }{
|
||||
{"a value", `{"a":1}`},
|
||||
{"a list", `[1]`},
|
||||
{"not JSON", `nope`},
|
||||
{"another field beside it", `{"mesh-object":{"store":"s","object":"o","size":1,"sha256":"` + d + `","form":1},"x":1}`},
|
||||
{"a field the reference does not know", `{"mesh-object":{"store":"s","object":"o","size":1,"sha256":"` + d + `","form":1,"x":1}}`},
|
||||
{"a digest that is no digest", `{"mesh-object":{"store":"s","object":"o","size":1,"sha256":"zz","form":1}}`},
|
||||
{"another form", `{"mesh-object":{"store":"s","object":"o","size":1,"sha256":"` + d + `","form":2}}`},
|
||||
{"no store", `{"mesh-object":{"object":"o","size":1,"sha256":"` + d + `","form":1}}`},
|
||||
}
|
||||
for _, r := range rows {
|
||||
if _, ok := ReadRef([]byte(r.body)); ok {
|
||||
t.Errorf("%s: read as a reference", r.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user