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  }