github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/jsonhelpers/json_helpers.go (about) 1 package jsonhelpers 2 3 import ( 4 "errors" 5 "fmt" 6 7 keybase1 "github.com/keybase/client/go/protocol/keybase1" 8 jsonw "github.com/keybase/go-jsonw" 9 ) 10 11 // JSONStringSimple converts a simple json object into a string. Simple 12 // objects are those that are not arrays or objects. Non-simple objects result 13 // in an error. 14 func JSONStringSimple(object *jsonw.Wrapper) (string, error) { 15 x, err := object.GetInt() 16 if err == nil { 17 return fmt.Sprintf("%d", x), nil 18 } 19 y, err := object.GetString() 20 if err == nil { 21 return y, nil 22 } 23 z, err := object.GetBool() 24 if err == nil { 25 if z { 26 return "true", nil 27 } 28 return "false", nil 29 } 30 31 return "", fmt.Errorf("Non-simple object: %v", object) 32 } 33 34 // pyindex converts an index into a real index like python. 35 // Returns an index to use and whether the index is safe to use. 36 func pyindex(index, len int) (int, bool) { 37 if len <= 0 { 38 return 0, false 39 } 40 // wrap from the end 41 if index < 0 { 42 index = len + index 43 } 44 if index < 0 || index >= len { 45 return 0, false 46 } 47 return index, true 48 } 49 50 // Return the elements of an array. 51 func jsonUnpackArray(w *jsonw.Wrapper) ([]*jsonw.Wrapper, error) { 52 w, err := w.ToArray() 53 if err != nil { 54 return nil, err 55 } 56 length, err := w.Len() 57 if err != nil { 58 return nil, err 59 } 60 res := make([]*jsonw.Wrapper, length) 61 for i := 0; i < length; i++ { 62 res[i] = w.AtIndex(i) 63 } 64 return res, nil 65 } 66 67 // Return the elements of an array or values of a map. 68 func JSONGetChildren(w *jsonw.Wrapper) ([]*jsonw.Wrapper, error) { 69 dict, err := w.ToDictionary() 70 isDict := err == nil 71 array, err := w.ToArray() 72 isArray := err == nil 73 74 switch { 75 case isDict: 76 keys, err := dict.Keys() 77 if err != nil { 78 return nil, err 79 } 80 var res = make([]*jsonw.Wrapper, len(keys)) 81 for i, key := range keys { 82 res[i] = dict.AtKey(key) 83 } 84 return res, nil 85 case isArray: 86 return jsonUnpackArray(array) 87 default: 88 return nil, errors.New("got children of non-container") 89 } 90 } 91 92 // Most failures here log instead of returning an error. If an error occurs, 93 // ([], nil) will be returned. This is because a selector may descend into 94 // many subtrees and fail in all but one. 95 func AtSelectorPath(selectedObject *jsonw.Wrapper, selectors []keybase1.SelectorEntry, 96 logger func(format string, arg ...interface{}), mkErr func(selector keybase1.SelectorEntry) error) ([]*jsonw.Wrapper, error) { 97 // The terminating condition is when we've consumed all the selectors. 98 if len(selectors) == 0 { 99 return []*jsonw.Wrapper{selectedObject}, nil 100 } 101 102 selector := selectors[0] 103 nextselectors := selectors[1:] 104 105 switch { 106 case selector.IsIndex: 107 object, err := selectedObject.ToArray() 108 if err != nil { 109 logger("JSON select by index from non-array: %v (%v) (%v)", err, selector.Index, object) 110 return nil, nil 111 } 112 length, err := object.Len() 113 if err != nil { 114 return nil, nil 115 } 116 117 index, ok := pyindex(selector.Index, length) 118 if !ok || index < 0 { 119 return nil, nil 120 } 121 nextobject := object.AtIndex(index) 122 return AtSelectorPath(nextobject, nextselectors, logger, mkErr) 123 case selector.IsKey: 124 object, err := selectedObject.ToDictionary() 125 if err != nil { 126 logger("JSON select by key from non-map: %v (%v) (%v)", err, selector.Key, object) 127 return nil, nil 128 } 129 130 nextobject := object.AtKey(selector.Key) 131 return AtSelectorPath(nextobject, nextselectors, logger, mkErr) 132 case selector.IsAll: 133 children, err := JSONGetChildren(selectedObject) 134 if err != nil { 135 logger("JSON select could not get children: %v (%v)", err, selectedObject) 136 return nil, nil 137 } 138 var results []*jsonw.Wrapper 139 for _, child := range children { 140 innerresults, perr := AtSelectorPath(child, nextselectors, logger, mkErr) 141 if perr != nil { 142 return nil, perr 143 } 144 results = append(results, innerresults...) 145 } 146 return results, nil 147 default: 148 return nil, mkErr(selector) 149 } 150 }