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 }