From 510f7b0465faf3895e327ed2c56b71b1b23e9881 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 1 Aug 2026 15:25:13 +0000 Subject: [PATCH] feat: add optional affinity field to /blob/add arguments Per RFC fil-one/RFC#15 (dynamic affinity routing), adds an optional `affinity` field to `AddArguments` that accepts a list of storage-node DIDs. When present, it constrains routing to the specified nodes. Regenerates cbor_gen.go and json_gen.go accordingly. --- commands/blob/cbor_gen.go | 78 ++++++++++++++++++++++++++++++++++- commands/blob/json_gen.go | 87 ++++++++++++++++++++++++++++++++++++++- commands/blob/types.go | 3 +- 3 files changed, 164 insertions(+), 4 deletions(-) diff --git a/commands/blob/cbor_gen.go b/commands/blob/cbor_gen.go index b870181..302bf26 100644 --- a/commands/blob/cbor_gen.go +++ b/commands/blob/cbor_gen.go @@ -10,6 +10,7 @@ import ( "math" "sort" + did "github.com/fil-forge/ucantone/did" promise "github.com/fil-forge/ucantone/ucan/promise" cid "github.com/ipfs/go-cid" cbg "github.com/whyrusleeping/cbor-gen" @@ -963,8 +964,13 @@ func (t *AddArguments) MarshalCBOR(w io.Writer) error { } cw := cbg.NewCborWriter(w) + fieldCount := 2 - if _, err := cw.Write([]byte{161}); err != nil { + if t.Affinity == nil { + fieldCount-- + } + + if _, err := cw.Write(cbg.CborEncodeMajorType(cbg.MajMap, uint64(fieldCount))); err != nil { return err } @@ -983,6 +989,35 @@ func (t *AddArguments) MarshalCBOR(w io.Writer) error { if err := t.Blob.MarshalCBOR(cw); err != nil { return err } + + // t.Affinity ([]did.DID) (slice) + if t.Affinity != nil { + + if len("affinity") > 8192 { + return xerrors.Errorf("Value in field \"affinity\" was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len("affinity"))); err != nil { + return err + } + if _, err := cw.WriteString(string("affinity")); err != nil { + return err + } + + if len(t.Affinity) > 8192 { + return xerrors.Errorf("Slice value in field t.Affinity was too long") + } + + if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Affinity))); err != nil { + return err + } + for _, v := range t.Affinity { + if err := v.MarshalCBOR(cw); err != nil { + return err + } + + } + } return nil } @@ -1011,7 +1046,7 @@ func (t *AddArguments) UnmarshalCBOR(r io.Reader) (err error) { n := extra - nameBuf := make([]byte, 4) + nameBuf := make([]byte, 8) for i := uint64(0); i < n; i++ { nameLen, ok, err := cbg.ReadFullStringIntoBuf(cr, nameBuf, 8192) if err != nil { @@ -1037,6 +1072,45 @@ func (t *AddArguments) UnmarshalCBOR(r io.Reader) (err error) { } } + // t.Affinity ([]did.DID) (slice) + case "affinity": + + maj, extra, err = cr.ReadHeader() + if err != nil { + return err + } + + if extra > 8192 { + return fmt.Errorf("t.Affinity: array too large (%d)", extra) + } + + if maj != cbg.MajArray { + return fmt.Errorf("expected cbor array") + } + + if extra > 0 { + t.Affinity = make([]did.DID, extra) + } + + for i := 0; i < int(extra); i++ { + { + var maj byte + var extra uint64 + var err error + _ = maj + _ = extra + _ = err + + { + + if err := t.Affinity[i].UnmarshalCBOR(cr); err != nil { + return xerrors.Errorf("unmarshaling t.Affinity[i]: %w", err) + } + + } + + } + } default: // Field doesn't exist on this type, so ignore it diff --git a/commands/blob/json_gen.go b/commands/blob/json_gen.go index bdffafb..eaccd19 100644 --- a/commands/blob/json_gen.go +++ b/commands/blob/json_gen.go @@ -12,6 +12,7 @@ import ( "sort" jsg "github.com/alanshaw/dag-json-gen" + did "github.com/fil-forge/ucantone/did" promise "github.com/fil-forge/ucantone/ucan/promise" cid "github.com/ipfs/go-cid" ) @@ -979,6 +980,47 @@ func (t *AddArguments) MarshalDagJSON(w io.Writer) error { if err := jw.WriteObjectOpen(); err != nil { return err } + written := 0 + + // t.Affinity ([]did.DID) (slice) + if t.Affinity != nil { + if len("affinity") > 8192 { + return fmt.Errorf("string in field \"affinity\" was too long") + } + if err := jw.WriteString(string("affinity")); err != nil { + return fmt.Errorf("writing string for field \"affinity\": %w", err) + } + if err := jw.WriteObjectColon(); err != nil { + return err + } + if len(t.Affinity) > 8192 { + return fmt.Errorf("slice value in field t.Affinity was too long") + } + + if err := jw.WriteArrayOpen(); err != nil { + return fmt.Errorf("writing array open for field t.Affinity: %w", err) + } + for i, v := range t.Affinity { + if i > 0 { + if err := jw.WriteComma(); err != nil { + return fmt.Errorf("writing comma for field t.Affinity: %w", err) + } + } + if err := v.MarshalDagJSON(jw); err != nil { + return fmt.Errorf("marshaling field v: %w", err) + } + } + if err := jw.WriteArrayClose(); err != nil { + return fmt.Errorf("writing array close for field t.Affinity: %w", err) + } + + written++ + } + if written > 0 { + if err := jw.WriteComma(); err != nil { + return err + } + } // t.Blob (blob.Blob) (struct) if len("blob") > 8192 { @@ -993,6 +1035,7 @@ func (t *AddArguments) MarshalDagJSON(w io.Writer) error { if err := t.Blob.MarshalDagJSON(jw); err != nil { return fmt.Errorf("marshaling field t.Blob: %w", err) } + written++ if err := jw.WriteObjectClose(); err != nil { return err } @@ -1032,7 +1075,49 @@ func (t *AddArguments) UnmarshalDagJSON(r io.Reader) (err error) { } switch name { - // t.Blob (blob.Blob) (struct) + // t.Affinity ([]did.DID) (slice) + case "affinity": + { + + if err := jr.ReadArrayOpen(); err != nil { + return fmt.Errorf("reading array open for field t.Affinity: %w", err) + } + + close, err := jr.PeekArrayClose() + if err != nil { + return fmt.Errorf("peeking array close for field t.Affinity: %w", err) + } + if close { + if err := jr.ReadArrayClose(); err != nil { + return fmt.Errorf("reading array close for field t.Affinity: %w", err) + } + + } else { + for i := 0; i < 8192; i++ { + item := make([]did.DID, 1) + + if err := item[0].UnmarshalDagJSON(jr); err != nil { + return fmt.Errorf("unmarshaling item[0]: %w", err) + } + + t.Affinity = append(t.Affinity, item[0]) + + close, err := jr.ReadArrayCloseOrComma() + if err != nil { + return fmt.Errorf("reading array close or comma for field t.Affinity: %w", err) + } + if close { + break + } + if i == 8192-1 { + return fmt.Errorf("reading array for field t.Affinity: slice too large") + } + } + } + + } + + // t.Blob (blob.Blob) (struct) case "blob": if err := t.Blob.UnmarshalDagJSON(jr); err != nil { diff --git a/commands/blob/types.go b/commands/blob/types.go index 27cb5ca..1f00842 100644 --- a/commands/blob/types.go +++ b/commands/blob/types.go @@ -14,7 +14,8 @@ type Blob struct { } type AddArguments struct { - Blob Blob `cborgen:"blob" dagjsongen:"blob"` + Blob Blob `cborgen:"blob" dagjsongen:"blob"` + Affinity []did.DID `cborgen:"affinity,omitempty" dagjsongen:"affinity,omitempty"` } type AddOK struct {