1package photocopy
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "time"
8
9 "cloud.google.com/go/bigquery"
10)
11
12type PLCEntry struct {
13 Did string `json:"did" bigquery:"did"`
14 Operation PLCOperationType `json:"operation" bigquery:"operation"`
15 Cid string `json:"cid" bigquery:"cid"`
16 Nullified bool `json:"nullified" bigquery:"nullified"`
17 CreatedAt time.Time `json:"createdAt" bigquery:"created_at"`
18}
19
20type PLCOperation struct {
21 Sig string `json:"sig" bigquery:"sig"`
22 Prev bigquery.NullString `json:"prev" bigquery:"prev"`
23 Type string `json:"type" bigquery:"type"`
24 Services map[string]PLCService `json:"services" bigquery:"-"`
25 ServicesJSON string `json:"-" bigquery:"services"`
26 AlsoKnownAs []string `json:"alsoKnownAs" bigquery:"also_known_as"`
27 RotationKeys []string `json:"rotationKeys" bigquery:"rotation_keys"`
28 VerificationMethods map[string]string `json:"verificationMethods" bigquery:"-"`
29 VerificationMethodsJSON string `json:"-" bigquery:"verification_methods"`
30}
31
32type PLCTombstone struct {
33 Sig string `json:"sig"`
34 Prev string `json:"prev"`
35 Type string `json:"type"`
36}
37
38type PLCService struct {
39 Type string `json:"type"`
40 Endpoint string `json:"endpoint"`
41}
42
43type LegacyPLCOperation struct {
44 Sig string `json:"sig"`
45 Prev string `json:"prev"`
46 Type string `json:"type"`
47 Handle string `json:"handle"`
48 Service string `json:"service"`
49 SigningKey string `json:"signingKey"`
50 RecoveryKey string `json:"recoveryKey"`
51}
52
53type PLCOperationType struct {
54 OperationType string `json:"-" bigquery:"operation_type"`
55 PLCOperation *PLCOperation `json:"-" bigquery:"plc_operation"`
56 PLCTombstone *PLCTombstone `json:"-" bigquery:"plc_tombstone"`
57 LegacyPLCOperation *LegacyPLCOperation `json:"-" bigquery:"legacy_plc_operation"`
58}
59
60func (o *PLCOperationType) UnmarshalJSON(data []byte) error {
61 type Base struct {
62 PLCOperation *PLCOperation
63 PLCTombstone *PLCTombstone
64 LegacyPLCOperation *LegacyPLCOperation
65 Type string `json:"type"`
66 }
67
68 var base Base
69 if err := json.Unmarshal(data, &base); err != nil {
70 return err
71 }
72
73 switch base.Type {
74 case "plc_operation":
75 var op PLCOperation
76 if err := json.Unmarshal(data, &op); err != nil {
77 return err
78 }
79 o.PLCOperation = &op
80 o.OperationType = "plc_operation"
81 case "plc_tombstone":
82 var op PLCTombstone
83 if err := json.Unmarshal(data, &op); err != nil {
84 return err
85 }
86 o.PLCTombstone = &op
87 o.OperationType = "plc_tombstone"
88 case "create":
89 var op LegacyPLCOperation
90 if err := json.Unmarshal(data, &op); err != nil {
91 return err
92 }
93 o.LegacyPLCOperation = &op
94 o.OperationType = "legacy_plc_operation"
95 default:
96 if base.PLCOperation != nil || base.PLCTombstone != nil || base.LegacyPLCOperation != nil {
97 o.PLCOperation = base.PLCOperation
98 o.PLCTombstone = base.PLCTombstone
99 o.LegacyPLCOperation = base.LegacyPLCOperation
100 } else {
101 return fmt.Errorf("invalid operation type %s", base.Type)
102 }
103 }
104
105 return nil
106}
107
108func (o *PLCOperationType) MarshalJSON() ([]byte, error) {
109 if o.PLCOperation != nil {
110 return json.Marshal(o.PLCOperation)
111 }
112 if o.PLCTombstone != nil {
113 return json.Marshal(o.PLCTombstone)
114 }
115 if o.LegacyPLCOperation != nil {
116 return json.Marshal(o.LegacyPLCOperation)
117 }
118 return nil, errors.New("no valid operation type found")
119}
120
121func (o *PLCOperationType) Value() (any, error) {
122 return json.Marshal(o)
123}
124
125func (o *PLCOperationType) Scan(value any) error {
126 bytes, ok := value.([]byte)
127 if !ok {
128 return errors.New("could not scan PLCOperationType")
129 }
130 return json.Unmarshal(bytes, o)
131}
132
133func (e *PLCEntry) prepareForBigQuery() (map[string]bigquery.Value, string, error) {
134 if e.Operation.PLCOperation != nil {
135 if e.Operation.PLCOperation.Services != nil {
136 b, err := json.Marshal(e.Operation.PLCOperation.Services)
137 if err != nil {
138 return nil, "", fmt.Errorf("error marshaling services: %w", err)
139 }
140 e.Operation.PLCOperation.ServicesJSON = string(b)
141 }
142 if e.Operation.PLCOperation.VerificationMethods != nil {
143 b, err := json.Marshal(e.Operation.PLCOperation.VerificationMethods)
144 if err != nil {
145 return nil, "", fmt.Errorf("error marshaling verification methods: %w", err)
146 }
147 e.Operation.PLCOperation.VerificationMethodsJSON = string(b)
148 }
149 }
150 return nil, "", nil
151}