blob: 7463fbb2890c7d1eba9e77e494a91826821370d9 [file] [log] [blame]
// Copyright (c) 2016 ~ 2019, Alex Stocks.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package hessian
import (
"encoding/binary"
"reflect"
)
import (
jerrors "github.com/juju/errors"
)
// hessian decode respone
func UnpackResponseHeaer(buf []byte, header *DubboHeader) error {
// length := len(buf)
// // hessianCodec.ReadHeader has check the header length
// if length < HEADER_LENGTH {
// return ErrHeaderNotEnough
// }
if buf[0] != byte(MAGIC_HIGH) && buf[1] != byte(MAGIC_LOW) {
return ErrIllegalPackage
}
// Header{serialization id(5 bit), event, two way, req/response}
if header.SerialID = buf[2] & SERIAL_MASK; header.SerialID == byte(0x00) {
return jerrors.Errorf("serialization ID:%v", header.SerialID)
}
flag := buf[2] & FLAG_EVENT
if flag != byte(0x00) {
header.Type |= Heartbeat
}
flag = buf[2] & FLAG_TWOWAY
if flag != byte(0x00) {
header.Type |= Response
}
flag = buf[2] & FLAG_REQUEST
if flag != byte(0x00) {
return jerrors.Errorf("response flag:%v", flag)
}
// Header{status}
var err error
if buf[3] != Response_OK {
err = ErrJavaException
// return jerrors.Errorf("Response not OK, java exception:%s", string(buf[18:length-1]))
}
// Header{req id}
header.ID = int64(binary.BigEndian.Uint64(buf[4:]))
// Header{body len}
header.BodyLen = int(binary.BigEndian.Uint32(buf[12:]))
if header.BodyLen < 0 {
return ErrIllegalPackage
}
return err
}
// hessian decode response body
func UnpackResponseBody(buf []byte, body interface{}) error {
// body
decoder := NewDecoder(buf[:])
rspType, err := decoder.Decode()
if err != nil {
return jerrors.Trace(err)
}
switch rspType {
case RESPONSE_WITH_EXCEPTION:
expt, err := decoder.Decode()
if err != nil {
return jerrors.Trace(err)
}
return jerrors.Errorf("got exception: %+v", expt)
case RESPONSE_VALUE:
rsp, err := decoder.Decode()
if err != nil {
return jerrors.Trace(err)
}
return jerrors.Trace(ReflectResponse(rsp, body))
case RESPONSE_NULL_VALUE:
return jerrors.New("Received null")
}
return nil
}
func cpSlice(in, out interface{}) error {
inSlice := reflect.ValueOf(in)
if inSlice.IsNil() {
return jerrors.New("@in is nil")
}
outSlice := reflect.ValueOf(out)
for outSlice.Kind() == reflect.Ptr {
outSlice = outSlice.Elem()
}
outSlice.Set(reflect.MakeSlice(outSlice.Type(), inSlice.Len(), inSlice.Len()))
//outElemKind := outSlice.Type().Elem().Kind()
for i := 0; i < outSlice.Len(); i++ {
inSliceValue := inSlice.Index(i)
if outSlice.Index(i).Kind() == reflect.Struct {
//if inSliceValue.Kind() == reflect.Ptr && inSliceValue.Kind() != outElemKind {
// inSliceValue = inSliceValue.Elem()
//}
inSliceValue = inSliceValue.Interface().(reflect.Value)
} else {
inSliceValue = reflect.ValueOf(inSliceValue)
}
if !inSliceValue.Type().AssignableTo(outSlice.Index(i).Type()) {
return jerrors.Errorf("in element type %s can not assign to out element type %s",
inSliceValue.Type().Name(), outSlice.Type().Name())
}
outSlice.Index(i).Set(inSliceValue)
}
return nil
}
func cpMap(in, out interface{}) error {
inMapValue := reflect.ValueOf(in)
if inMapValue.IsNil() {
return jerrors.New("@in is nil")
}
if !inMapValue.CanInterface() {
return jerrors.New("@in's Interface can not be used.")
}
inMap := inMapValue.Interface().(map[interface{}]interface{})
outMap := reflect.ValueOf(out)
for outMap.Kind() == reflect.Ptr {
outMap = outMap.Elem()
}
outMap.Set(reflect.MakeMap(outMap.Type()))
outKeyType := outMap.Type().Key()
outKeyKind := outKeyType.Kind()
outValueType := outMap.Type().Elem()
outValueKind := outValueType.Kind()
var inKey, inValue reflect.Value
for k := range inMap {
if outKeyKind != reflect.Struct {
inKey = reflect.ValueOf(k)
} else {
inKey = k.(reflect.Value)
}
if outValueKind != reflect.Struct {
inValue = reflect.ValueOf(inMap[k])
} else {
inValue = inMap[k].(reflect.Value)
}
if !inKey.Type().AssignableTo(outKeyType) {
return jerrors.Errorf("in Key:{type:%s, value:%#v} can not assign to out Key:{type:%s} ",
inKey.Type().Name(), inKey, outKeyType.Name())
}
if !inValue.Type().AssignableTo(outValueType) {
return jerrors.Errorf("in Value:{type:%s, value:%#v} can not assign to out value:{type:%s}",
inValue.Type().Name(), inValue, outValueType.Name())
}
outMap.SetMapIndex(inKey, inValue)
}
return nil
}
// reflect return value
func ReflectResponse(in interface{}, out interface{}) error {
if in == nil {
return jerrors.Errorf("@in is nil")
}
if out == nil {
return jerrors.Errorf("@out is nil")
}
if reflect.TypeOf(out).Kind() != reflect.Ptr {
return jerrors.Errorf("@out should be a pointer")
}
if inV, ok := in.(reflect.Value); ok {
in = inV.Interface()
}
inType := reflect.TypeOf(in)
switch inType.Kind() {
case reflect.Bool:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(bool)))
case reflect.Int8:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(int8)))
case reflect.Int16:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(int16)))
case reflect.Int32:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(int32)))
case reflect.Int64:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(int64)))
case reflect.Float32:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(float32)))
case reflect.Float64:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(float64)))
case reflect.String:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(string)))
case reflect.Ptr:
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(in.(reflect.Value).Elem().Interface()))
case reflect.Struct:
reflect.ValueOf(out).Elem().Set(in.(reflect.Value)) // reflect.ValueOf(in.(reflect.Value)))
case reflect.Slice, reflect.Array:
return cpSlice(in, out)
case reflect.Map:
return cpMap(in, out)
}
return nil
}