github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/specs/decode.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package specs 5 6 import ( 7 "bufio" 8 "bytes" 9 "encoding/json" 10 "fmt" 11 "io" 12 13 "github.com/juju/errors" 14 k8syaml "k8s.io/apimachinery/pkg/util/yaml" 15 ) 16 17 // YAMLOrJSONDecoder attempts to decode a stream of JSON documents or 18 // YAML documents by sniffing for a leading { character. 19 type YAMLOrJSONDecoder struct { 20 bufferSize int 21 r io.Reader 22 rawData []byte 23 24 strict bool 25 } 26 27 func newStrictYAMLOrJSONDecoder(r io.Reader, bufferSize int) *YAMLOrJSONDecoder { 28 return newYAMLOrJSONDecoder(r, bufferSize, true) 29 } 30 31 func newYAMLOrJSONDecoder(r io.Reader, bufferSize int, strict bool) *YAMLOrJSONDecoder { 32 return &YAMLOrJSONDecoder{ 33 r: r, 34 bufferSize: bufferSize, 35 strict: strict, 36 } 37 } 38 39 func (d *YAMLOrJSONDecoder) jsonify() (err error) { 40 buffer := bufio.NewReaderSize(d.r, d.bufferSize) 41 rawData, _ := buffer.Peek(d.bufferSize) 42 if rawData, err = k8syaml.ToJSON(rawData); err != nil { 43 return errors.Trace(err) 44 } 45 d.r = bytes.NewReader(rawData) 46 d.rawData = rawData 47 return nil 48 } 49 50 func (d *YAMLOrJSONDecoder) processError(err error, decoder *json.Decoder) error { 51 syntax, ok := err.(*json.SyntaxError) 52 if !ok { 53 return err 54 } 55 return k8syaml.JSONSyntaxError{ 56 Offset: syntax.Offset, 57 Err: fmt.Errorf(syntax.Error()), 58 } 59 } 60 61 // Decode unmarshals the next object from the underlying stream into the 62 // provide object, or returns an error. 63 func (d *YAMLOrJSONDecoder) Decode(into interface{}) error { 64 if err := d.jsonify(); err != nil { 65 return errors.Trace(err) 66 } 67 logger.Debugf("decoding stream as JSON") 68 decoder := json.NewDecoder(d.r) 69 decoder.UseNumber() 70 if d.strict { 71 decoder.DisallowUnknownFields() 72 } 73 74 for decoder.More() { 75 if err := decoder.Decode(into); err != nil { 76 return d.processError(err, decoder) 77 } 78 } 79 80 return nil 81 }