1package data
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7
8 "github.com/ipfs/go-cid"
9 cbg "github.com/whyrusleeping/cbor-gen"
10)
11
12// Represents the "cid-link" type from the atproto data model.
13//
14// Implementation is a simple wrapper around the github.com/ipfs/go-cid "cid.Cid" type.
15type CIDLink cid.Cid
16
17type jsonLink struct {
18 Link string `json:"$link"`
19}
20
21// Unwraps the inner cid.Cid type (github.com/ipfs/go-cid)
22func (ll CIDLink) CID() cid.Cid {
23 return cid.Cid(ll)
24}
25
26// Returns string representation.
27//
28// If the CID is "undefined", returns an empty string (note that this is different from how cid.Cid works).
29func (ll CIDLink) String() string {
30 if ll.IsDefined() {
31 return cid.Cid(ll).String()
32 }
33 return ""
34}
35
36// Convenience helper, returns false if CID is "undefined" (golang zero value)
37func (ll CIDLink) IsDefined() bool {
38 return cid.Cid(ll).Defined()
39}
40
41func (ll CIDLink) MarshalJSON() ([]byte, error) {
42 if !ll.IsDefined() {
43 return nil, fmt.Errorf("tried to marshal nil or undefined cid-link")
44 }
45 jl := jsonLink{
46 Link: ll.String(),
47 }
48 return json.Marshal(jl)
49}
50
51func (ll *CIDLink) UnmarshalJSON(raw []byte) error {
52 var jl jsonLink
53 if err := json.Unmarshal(raw, &jl); err != nil {
54 return fmt.Errorf("parsing cid-link JSON: %v", err)
55 }
56
57 c, err := cid.Decode(jl.Link)
58 if err != nil {
59 return fmt.Errorf("parsing cid-link CID: %v", err)
60 }
61 *ll = CIDLink(c)
62 return nil
63}
64
65func (ll *CIDLink) MarshalCBOR(w io.Writer) error {
66 if ll == nil {
67 _, err := w.Write(cbg.CborNull)
68 return err
69 }
70 if !ll.IsDefined() {
71 return fmt.Errorf("tried to marshal nil or undefined cid-link")
72 }
73 cw := cbg.NewCborWriter(w)
74 if err := cbg.WriteCid(cw, cid.Cid(*ll)); err != nil {
75 return fmt.Errorf("failed to write cid-link as CBOR: %w", err)
76 }
77 return nil
78}
79
80func (ll *CIDLink) UnmarshalCBOR(r io.Reader) error {
81 cr := cbg.NewCborReader(r)
82 c, err := cbg.ReadCid(cr)
83 if err != nil {
84 return fmt.Errorf("failed to read cid-link from CBOR: %w", err)
85 }
86 *ll = CIDLink(c)
87 return nil
88}