github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/p2p/p2putil/json/json.go (about) 1 package json 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "errors" 7 "io" 8 9 msgio "github.com/libp2p/go-msgio" 10 mc "github.com/qri-io/dag/dsync/p2putil/multicodec_old" 11 ) 12 13 var headerPath string 14 var header []byte 15 var headerMsgioPath string 16 var headerMsgio []byte 17 18 func init() { 19 headerPath = "/json" 20 headerMsgioPath = "/json/msgio" 21 header = mc.Header([]byte(headerPath)) 22 headerMsgio = mc.Header([]byte(headerMsgioPath)) 23 } 24 25 type codec struct { 26 mc bool 27 msgio bool 28 } 29 30 // Codec creates a json codec 31 func Codec(msgio bool) mc.Codec { 32 return &codec{mc: false, msgio: msgio} 33 } 34 35 // Multicodec creates a json codec 36 func Multicodec(msgio bool) mc.Multicodec { 37 return &codec{mc: true, msgio: msgio} 38 } 39 40 func (c *codec) Encoder(w io.Writer) mc.Encoder { 41 buf := bytes.NewBuffer(nil) 42 return &encoder{ 43 w: w, 44 c: c, 45 buf: buf, 46 enc: json.NewEncoder(buf), 47 } 48 } 49 50 func (c *codec) Decoder(r io.Reader) mc.Decoder { 51 return &decoder{ 52 r: r, 53 c: c, 54 } 55 } 56 57 func (c *codec) Header() []byte { 58 if c.msgio { 59 return headerMsgio 60 } 61 return header 62 } 63 64 type encoder struct { 65 w io.Writer 66 c *codec 67 enc *json.Encoder 68 buf *bytes.Buffer 69 } 70 71 type decoder struct { 72 r io.Reader 73 c *codec 74 } 75 76 func (c *encoder) Encode(v interface{}) error { 77 defer c.buf.Reset() 78 w := c.w 79 80 if c.c.mc { 81 // if multicodec, write the header first 82 if _, err := c.w.Write(c.c.Header()); err != nil { 83 return err 84 } 85 } 86 if c.c.msgio { 87 w = msgio.NewWriter(w) 88 } 89 90 // recast to deal with map[interface{}]interface{} case 91 vr, err := recast(v) 92 if err != nil { 93 return err 94 } 95 96 if err := c.enc.Encode(vr); err != nil { 97 return err 98 } 99 100 _, err = io.Copy(w, c.buf) 101 return err 102 } 103 104 func (c *decoder) Decode(v interface{}) error { 105 r := c.r 106 107 if c.c.mc { 108 // if multicodec, consume the header first 109 if err := mc.ConsumeHeader(c.r, c.c.Header()); err != nil { 110 return err 111 } 112 } 113 if c.c.msgio { 114 // need to make a new one per read. 115 var err error 116 r, err = msgio.LimitedReader(c.r) 117 if err != nil { 118 return err 119 } 120 } 121 122 return json.NewDecoder(r).Decode(v) 123 } 124 125 func recast(v interface{}) (cv interface{}, err error) { 126 switch v.(type) { 127 case map[interface{}]interface{}: 128 vmi := v.(map[interface{}]interface{}) 129 vms := make(map[string]interface{}, len(vmi)) 130 for k, v2 := range vmi { 131 ks, ok := k.(string) 132 if !ok { 133 return v, errors.New("multicodec type error") 134 } 135 136 rv2, err := recast(v2) 137 if err != nil { 138 return v, err 139 } 140 141 vms[ks] = rv2 142 } 143 return vms, nil 144 default: 145 return v, nil // hope for the best. 146 } 147 }