1 package ldcontext
2
3 import (
4 "github.com/launchdarkly/go-sdk-common/v3/ldattr"
5 "github.com/launchdarkly/go-sdk-common/v3/lderrors"
6 "github.com/launchdarkly/go-sdk-common/v3/ldvalue"
7
8 "github.com/launchdarkly/go-jsonstream/v3/jreader"
9 )
10
11
12 var internCommonAttributeNamesMap = makeInternCommonAttributeNamesMap()
13
14 func makeInternCommonAttributeNamesMap() map[string]string {
15 ret := make(map[string]string)
16 for _, a := range []string{"email", "firstName", "lastName", "country", "ip", "avatar"} {
17 ret[a] = a
18 }
19 return ret
20 }
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 func (c *Context) UnmarshalJSON(data []byte) error {
38 r := jreader.NewReader(data)
39 return ContextSerialization.UnmarshalFromJSONReader(&r, c)
40 }
41
42 func unmarshalFromJSONReader(r *jreader.Reader, c *Context, usingEventFormat bool) {
43
44
45 kind, hasKind, err := parseKindOnly(r)
46 if err != nil {
47 r.AddError(err)
48 return
49 }
50 switch {
51 case !hasKind:
52 err = unmarshalOldUserSchema(c, r, usingEventFormat)
53 case kind == MultiKind:
54 err = unmarshalMultiKind(c, r, usingEventFormat)
55 default:
56 err = unmarshalSingleKind(c, r, "", usingEventFormat)
57 }
58 if err != nil {
59 r.AddError(err)
60 }
61 }
62
63 func parseKindOnly(originalReader *jreader.Reader) (Kind, bool, error) {
64
65
66
67 r := *originalReader
68 for obj := r.Object(); obj.Next(); {
69 if string(obj.Name()) == ldattr.KindAttr {
70 kind := r.String()
71 if r.Error() == nil && kind == "" {
72 return "", false, lderrors.ErrContextKindEmpty{}
73 }
74 return Kind(kind), true, r.Error()
75
76
77 }
78
79
80
81
82 _ = r.SkipValue()
83 }
84 return "", false, r.Error()
85 }
86
87 func readOptString(r *jreader.Reader) ldvalue.OptionalString {
88 if s, nonNull := r.StringOrNull(); nonNull {
89 return ldvalue.NewOptionalString(s)
90 }
91 return ldvalue.OptionalString{}
92 }
93
94 func unmarshalSingleKind(c *Context, r *jreader.Reader, knownKind Kind, usingEventFormat bool) error {
95 var b Builder
96 if knownKind != "" {
97 b.Kind(knownKind)
98 }
99 hasKey := false
100 for obj := r.Object(); obj.Next(); {
101 switch string(obj.Name()) {
102 case ldattr.KindAttr:
103 b.Kind(Kind(r.String()))
104 case ldattr.KeyAttr:
105
106
107
108
109 if s, nonNull := r.StringOrNull(); nonNull {
110 b.Key(s)
111 hasKey = true
112 } else {
113 return lderrors.ErrContextKeyNull{}
114 }
115 case ldattr.NameAttr:
116 b.OptName(readOptString(r))
117 case ldattr.AnonymousAttr:
118 b.Anonymous(r.Bool())
119 case jsonPropMeta:
120 for metaObj := r.ObjectOrNull(); metaObj.Next(); {
121 switch string(metaObj.Name()) {
122 case jsonPropPrivate:
123 if usingEventFormat {
124 _ = r.SkipValue()
125 continue
126 }
127 readPrivateAttributes(r, &b, false)
128 case jsonPropRedacted:
129 if !usingEventFormat {
130 _ = r.SkipValue()
131 continue
132 }
133 readPrivateAttributes(r, &b, false)
134 default:
135
136
137 _ = r.SkipValue()
138 }
139 }
140 default:
141 var v ldvalue.Value
142 v.ReadFromJSONReader(r)
143 b.SetValue(internAttributeNameIfPossible(obj.Name()), v)
144 }
145 }
146 if r.Error() != nil {
147 return r.Error()
148 }
149 if !hasKey {
150 return lderrors.ErrContextKeyMissing{}
151 }
152 *c = b.Build()
153 return c.Err()
154 }
155
156 func unmarshalMultiKind(c *Context, r *jreader.Reader, usingEventFormat bool) error {
157 var b MultiBuilder
158 for obj := r.Object(); obj.Next(); {
159 name := string(obj.Name())
160 if name == ldattr.KindAttr {
161 _ = r.SkipValue()
162 continue
163 }
164 var subContext Context
165 if err := unmarshalSingleKind(&subContext, r, Kind(name), usingEventFormat); err != nil {
166 return err
167 }
168 b.Add(subContext)
169 }
170 *c = b.Build()
171 return c.Err()
172 }
173
174 func unmarshalOldUserSchema(c *Context, r *jreader.Reader, usingEventFormat bool) error {
175 var b Builder
176 b.setAllowEmptyKey(true)
177 var secondary ldvalue.OptionalString
178 hasKey := false
179 for obj := r.Object(); obj.Next(); {
180 switch string(obj.Name()) {
181 case ldattr.KeyAttr:
182 b.Key(r.String())
183 hasKey = true
184 case ldattr.NameAttr:
185 b.OptName(readOptString(r))
186 case jsonPropOldUserSecondary:
187 secondary = readOptString(r)
188 case ldattr.AnonymousAttr:
189 value, _ := r.BoolOrNull()
190 b.Anonymous(value)
191 case jsonPropOldUserCustom:
192 for customObj := r.ObjectOrNull(); customObj.Next(); {
193 name := string(customObj.Name())
194 var value ldvalue.Value
195 value.ReadFromJSONReader(r)
196 if isOldUserCustomAttributeNameAllowed(name) {
197 b.SetValue(name, value)
198 }
199 }
200 case jsonPropOldUserPrivate:
201 if usingEventFormat {
202 _ = r.SkipValue()
203 continue
204 }
205 readPrivateAttributes(r, &b, true)
206
207
208 case jsonPropOldUserRedacted:
209 if !usingEventFormat {
210 _ = r.SkipValue()
211 continue
212 }
213 readPrivateAttributes(r, &b, true)
214 case "firstName", "lastName", "email", "country", "avatar", "ip":
215 if s := readOptString(r); s.IsDefined() {
216 b.SetString(internAttributeNameIfPossible(obj.Name()), s.StringValue())
217 }
218 default:
219
220
221 _ = r.SkipValue()
222 }
223 }
224 if r.Error() != nil {
225 return r.Error()
226 }
227 if !hasKey {
228 return lderrors.ErrContextKeyMissing{}
229 }
230 *c = b.Build()
231 if secondary.IsDefined() {
232 c.secondary = secondary
233 }
234 return c.Err()
235 }
236
237 func isOldUserCustomAttributeNameAllowed(name string) bool {
238
239
240 switch name {
241 case ldattr.KindAttr, ldattr.KeyAttr, ldattr.NameAttr, ldattr.AnonymousAttr, jsonPropMeta:
242 return false
243 default:
244 return true
245 }
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262 func internAttributeNameIfPossible(nameBytes []byte) string {
263 if internedName, ok := internCommonAttributeNamesMap[string(nameBytes)]; ok {
264 return internedName
265 }
266 return string(nameBytes)
267 }
268
269 func unmarshalWithKindAndKeyOnly(r *jreader.Reader, c *Context) {
270 kind, hasKind, err := parseKindOnly(r)
271 if err != nil {
272 r.AddError(err)
273 return
274 }
275 switch {
276 case !hasKind:
277 err = unmarshalWithKindAndKeyOnlyOldUser(r, c)
278 case kind == MultiKind:
279 var mb MultiBuilder
280 for obj := r.Object(); obj.Next(); {
281 switch string(obj.Name()) {
282 case ldattr.KindAttr:
283 _ = r.SkipValue()
284 default:
285 kind := Kind(obj.Name())
286 var mc Context
287 if err = unmarshalWithKindAndKeyOnlySingleKind(r, &mc, kind); err != nil {
288 break
289 }
290 mb.Add(mc)
291 }
292 }
293 *c = mb.Build()
294 err = c.Err()
295 default:
296 err = unmarshalWithKindAndKeyOnlySingleKind(r, c, "")
297 }
298 if err != nil {
299 r.AddError(err)
300 }
301 }
302
303 func unmarshalWithKindAndKeyOnlySingleKind(r *jreader.Reader, c *Context, kind Kind) error {
304 var key string
305 hasKey := false
306 for obj := r.Object(); obj.Next(); {
307 switch string(obj.Name()) {
308 case ldattr.KindAttr:
309 kind = Kind(r.String())
310 case ldattr.KeyAttr:
311 key = r.String()
312 hasKey = true
313 default:
314 _ = r.SkipValue()
315 }
316 }
317 if !hasKey {
318 r.AddError(lderrors.ErrContextKeyMissing{})
319 return lderrors.ErrContextKeyMissing{}
320 }
321 *c = NewWithKind(kind, key)
322 return c.Err()
323 }
324
325 func unmarshalWithKindAndKeyOnlyOldUser(r *jreader.Reader, c *Context) error {
326 for obj := r.Object(); obj.Next(); {
327 switch string(obj.Name()) {
328 case ldattr.KeyAttr:
329 key := r.String()
330 var b Builder
331 *c = b.setAllowEmptyKey(true).Key(key).Build()
332 return c.Err()
333 default:
334 _ = r.SkipValue()
335 }
336 }
337 r.AddError(lderrors.ErrContextKeyMissing{})
338 return lderrors.ErrContextKeyMissing{}
339 }
340
341 func readPrivateAttributes(r *jreader.Reader, b *Builder, asLiterals bool) {
342 for privateArr := r.ArrayOrNull(); privateArr.Next(); {
343 b.PrivateRef(refOrLiteralRef(r.String(), asLiterals))
344 }
345 }
346
347 func refOrLiteralRef(s string, asLiteral bool) ldattr.Ref {
348 if asLiteral {
349 return ldattr.NewLiteralRef(s)
350 }
351 return ldattr.NewRef(s)
352 }
353
View as plain text