1package photocopy
2
3import (
4 "encoding/json"
5 "fmt"
6 "time"
7)
8
9type PLCEntry struct {
10 Did string `json:"did"`
11 Operation PLCOperationType `json:"operation"`
12 Cid string `json:"cid"`
13 Nullified bool `json:"nullified"`
14 CreatedAt time.Time `json:"createdAt"`
15}
16
17type PLCOperation struct {
18 Sig string `json:"sig" `
19 Prev *string `json:"prev"`
20 Type string `json:"type"`
21 Services map[string]PLCService `json:"services"`
22 AlsoKnownAs []string `json:"alsoKnownAs"`
23 RotationKeys []string `json:"rotationKeys"`
24 VerificationMethods map[string]string `json:"verificationMethods"`
25}
26
27type PLCTombstone struct {
28 Sig string `json:"sig"`
29 Prev string `json:"prev"`
30 Type string `json:"type"`
31}
32
33type PLCService struct {
34 Type string `json:"type"`
35 Endpoint string `json:"endpoint"`
36}
37
38type LegacyPLCOperation struct {
39 Sig string `json:"sig"`
40 Prev string `json:"prev"`
41 Type string `json:"type"`
42 Handle string `json:"handle"`
43 Service string `json:"service"`
44 SigningKey string `json:"signingKey"`
45 RecoveryKey string `json:"recoveryKey"`
46}
47
48type PLCOperationType struct {
49 OperationType string
50 PLCOperation *PLCOperation
51 PLCTombstone *PLCTombstone
52 LegacyPLCOperation *LegacyPLCOperation
53}
54
55type ClickhousePLCEntry struct {
56 Did string `ch:"did"`
57 Cid string `ch:"cid"`
58 Nullified bool `ch:"nullified"`
59 CreatedAt time.Time `ch:"created_at"`
60 PlcOpSig string `ch:"plc_op_sig"`
61 PlcOpPrev *string `ch:"plc_op_prev"`
62 PlcOpType string `ch:"plc_op_type"`
63 PlcOpServices string `ch:"plc_op_services"`
64 PlcOpAlsoKnownAs []string `ch:"plc_op_also_known_as"`
65 PlcOpRotationKeys []string `ch:"plc_op_rotation_keys"`
66 PlcOpVerificationMethods string `ch:"plc_op_verification_methods"`
67 PlcTombSig string `ch:"plc_tomb_sig"`
68 PlcTombPrev string `ch:"plc_tomb_prev"`
69 PlcTombType string `ch:"plc_tomb_type"`
70 LegacyOpSig string `ch:"legacy_op_sig"`
71 LegacyOpPrev string `ch:"legacy_op_prev"`
72 LegacyOpType string `ch:"legacy_op_type"`
73 LegacyOpHandle string `ch:"legacy_op_handle"`
74 LegacyOpService string `ch:"legacy_op_service"`
75 LegacyOpSigningKey string `ch:"legacy_op_signing_key"`
76 LegacyOpRecoveryKey string `ch:"legacy_op_recovery_key"`
77}
78
79func (o *PLCOperationType) UnmarshalJSON(data []byte) error {
80 type Base struct {
81 PLCOperation *PLCOperation
82 PLCTombstone *PLCTombstone
83 LegacyPLCOperation *LegacyPLCOperation
84 Type string `json:"type"`
85 }
86
87 var base Base
88 if err := json.Unmarshal(data, &base); err != nil {
89 return err
90 }
91
92 switch base.Type {
93 case "plc_operation":
94 var op PLCOperation
95 if err := json.Unmarshal(data, &op); err != nil {
96 return err
97 }
98 o.PLCOperation = &op
99 o.OperationType = "plc_operation"
100 case "plc_tombstone":
101 var op PLCTombstone
102 if err := json.Unmarshal(data, &op); err != nil {
103 return err
104 }
105 o.PLCTombstone = &op
106 o.OperationType = "plc_tombstone"
107 case "create":
108 var op LegacyPLCOperation
109 if err := json.Unmarshal(data, &op); err != nil {
110 return err
111 }
112 o.LegacyPLCOperation = &op
113 o.OperationType = "legacy_plc_operation"
114 default:
115 if base.PLCOperation != nil || base.PLCTombstone != nil || base.LegacyPLCOperation != nil {
116 o.PLCOperation = base.PLCOperation
117 o.PLCTombstone = base.PLCTombstone
118 o.LegacyPLCOperation = base.LegacyPLCOperation
119 } else {
120 return fmt.Errorf("invalid operation type %s", base.Type)
121 }
122 }
123
124 return nil
125}
126
127func (e *PLCEntry) prepareForClickhouse() (*ClickhousePLCEntry, error) {
128 che := &ClickhousePLCEntry{
129 Did: e.Did,
130 Cid: e.Cid,
131 Nullified: e.Nullified,
132 CreatedAt: e.CreatedAt,
133 }
134 if e.Operation.PLCOperation != nil {
135 pop := e.Operation.PLCOperation
136 che.PlcOpSig = pop.Sig
137 che.PlcOpPrev = pop.Prev
138 che.PlcOpType = pop.Type
139 che.PlcOpAlsoKnownAs = pop.AlsoKnownAs
140 che.PlcOpRotationKeys = pop.RotationKeys
141 if e.Operation.PLCOperation.Services != nil {
142 b, err := json.Marshal(e.Operation.PLCOperation.Services)
143 if err != nil {
144 return nil, fmt.Errorf("error marshaling services: %w", err)
145 }
146 che.PlcOpServices = string(b)
147 }
148 if e.Operation.PLCOperation.VerificationMethods != nil {
149 b, err := json.Marshal(e.Operation.PLCOperation.VerificationMethods)
150 if err != nil {
151 return nil, fmt.Errorf("error marshaling verification methods: %w", err)
152 }
153 che.PlcOpVerificationMethods = string(b)
154 }
155 return che, nil
156 } else if e.Operation.PLCTombstone != nil {
157 che.PlcTombSig = e.Operation.PLCTombstone.Sig
158 che.PlcTombPrev = e.Operation.PLCTombstone.Prev
159 che.PlcTombType = e.Operation.PLCTombstone.Type
160 return che, nil
161 } else if e.Operation.LegacyPLCOperation != nil {
162 lop := e.Operation.LegacyPLCOperation
163 che.LegacyOpSig = lop.Sig
164 che.LegacyOpPrev = lop.Prev
165 che.LegacyOpType = lop.Type
166 che.LegacyOpService = lop.Service
167 che.LegacyOpHandle = lop.Handle
168 che.LegacyOpSigningKey = lop.SigningKey
169 che.LegacyOpRecoveryKey = lop.RecoveryKey
170 }
171
172 return nil, fmt.Errorf("no valid plc operation type")
173}