121 lines
3.0 KiB
Go
121 lines
3.0 KiB
Go
package rpc
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"gopkg.in/vmihailenco/msgpack.v4"
|
|
)
|
|
|
|
type decoderDataType string
|
|
|
|
const (
|
|
decoderDataTypeJSON decoderDataType = "json"
|
|
decoderDataTypeMsgpack decoderDataType = "msgpack"
|
|
)
|
|
|
|
type genericUnmarshaller func([]byte, interface{}) error
|
|
|
|
// deferredDecoder defers unmarshalling for specific types, it also supports
|
|
// re-marshalling the same thing and marshalling generig types
|
|
type deferredDecoder struct {
|
|
data []byte
|
|
dataType decoderDataType
|
|
out interface{}
|
|
unmarshaller genericUnmarshaller
|
|
}
|
|
|
|
// IsEmpty returns when this struct is empty. It is empty when there is no data and no out value
|
|
func (p *deferredDecoder) IsEmpty() bool {
|
|
return len(p.data) == 0 && p.out == nil
|
|
}
|
|
|
|
func (p *deferredDecoder) String() string {
|
|
data, err := p.MarshalJSON()
|
|
if err != nil {
|
|
return fmt.Sprintf("ERROR:%v", err)
|
|
}
|
|
return string(data)
|
|
}
|
|
|
|
// UnmarshalJSON unmashals json code
|
|
func (p *deferredDecoder) UnmarshalJSON(data []byte) error {
|
|
p.data = data
|
|
p.unmarshaller = json.Unmarshal
|
|
p.dataType = decoderDataTypeJSON
|
|
return nil
|
|
}
|
|
|
|
// MarshalJSON marshals json code
|
|
func (p *deferredDecoder) MarshalJSON() ([]byte, error) {
|
|
if p.out == nil {
|
|
if len(p.data) == 0 {
|
|
return []byte("null"), nil
|
|
}
|
|
switch p.dataType {
|
|
case decoderDataTypeJSON:
|
|
return p.data, nil
|
|
case decoderDataTypeMsgpack:
|
|
// we want to marshal JSON and have msgpack we
|
|
// unmarshall this into p.out and leave the
|
|
// marshaller at the end to marshal it
|
|
p.out = map[interface{}]interface{}{}
|
|
if err := p.Unmarshal(p.out); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return json.Marshal(p.out)
|
|
}
|
|
|
|
// MarshalMsgpack msgpack marshaler
|
|
func (p *deferredDecoder) MarshalMsgpack() ([]byte, error) {
|
|
if p.out == nil {
|
|
switch p.dataType {
|
|
case decoderDataTypeMsgpack:
|
|
return p.data, nil
|
|
case decoderDataTypeJSON:
|
|
// we want to marshal msgpack and have JSON we
|
|
// unmarshall this into p.out and leave the
|
|
// marshaller at the end to marshal it
|
|
p.out = map[interface{}]interface{}{}
|
|
if err := p.Unmarshal(p.out); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return msgpack.Marshal(p.out)
|
|
}
|
|
|
|
// UnmarshalMsgpack msgpack unmarshaler
|
|
func (p *deferredDecoder) UnmarshalMsgpack(data []byte) error {
|
|
p.data = data
|
|
p.unmarshaller = msgpack.Unmarshal
|
|
p.dataType = decoderDataTypeMsgpack
|
|
return nil
|
|
}
|
|
|
|
// Unmarshal unpacks parameters into the provided destination
|
|
func (p *deferredDecoder) Unmarshal(dst interface{}) error {
|
|
if p.unmarshaller == nil {
|
|
return ErrMsgNoData
|
|
}
|
|
return p.unmarshaller(p.data, dst)
|
|
}
|
|
|
|
// RetrieveResultData retrieves the data from the result object when it is an deferred decoder
|
|
func RetrieveResultData(msg *Msg) interface{} {
|
|
if dec, ok := msg.Result.(*deferredDecoder); ok {
|
|
return dec.out
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// RetrieveParamsData retrieves the data from the result object when it is an deferred decoder
|
|
func RetrieveParamsData(msg *Msg) interface{} {
|
|
if dec, ok := msg.Params.(*deferredDecoder); ok {
|
|
return dec.out
|
|
}
|
|
return nil
|
|
}
|