From d3cfb75bfd61b0499639a268a3f1fab91ba06857 Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 10:50:10 +0800 Subject: [PATCH 1/6] implement communication between dubbo-go cli and kitex srv --- pkg/codec.go | 196 +++++++++++++++++++++++- pkg/dubbo/header.go | 19 +-- pkg/dubbo/service.go | 50 +++++- tests/dubbo/go-client/conf/dubbogo.yaml | 3 +- tests/dubbo/go-server/cmd/server.go | 3 + tests/kitex/handler.go | 11 +- tests/kitex/main.go | 6 +- 7 files changed, 264 insertions(+), 24 deletions(-) diff --git a/pkg/codec.go b/pkg/codec.go index 8462b9cd..861d8ba6 100644 --- a/pkg/codec.go +++ b/pkg/codec.go @@ -21,10 +21,13 @@ package hessian2 import ( "context" + "errors" "fmt" hessian "github.com/apache/dubbo-go-hessian2" + "github.com/apache/dubbo-go-hessian2/java_exception" "github.com/cloudwego/kitex/pkg/remote" + "github.com/cloudwego/kitex/pkg/remote/codec" "github.com/kitex-contrib/codec-hessian2/pkg/dubbo" "github.com/kitex-contrib/codec-hessian2/pkg/iface" ) @@ -46,12 +49,29 @@ func (m *Hessian2Codec) Name() string { // Marshal encode method func (m *Hessian2Codec) Encode(ctx context.Context, message remote.Message, out remote.ByteBuffer) error { - payload, err := m.buildPayload(ctx, message) + var payload []byte + var err error + var status dubbo.StatusCode + msgType := message.MessageType() + switch msgType { + case remote.Call, remote.Oneway: + payload, err = m.encodeRequestPayload(ctx, message) + case remote.Exception: + payload, err = m.encodeExceptionPayload(ctx, message) + // use StatusOK by default, regardless of whether it is Reply or Exception + status = dubbo.StatusOK + case remote.Reply: + payload, err = m.encodeResponsePayload(ctx, message) + status = dubbo.StatusOK + default: + return fmt.Errorf("unsupported MessageType: %v", msgType) + } + if err != nil { return err } - header := m.buildDubboHeader(message, len(payload)) + header := m.buildDubboHeader(message, status, len(payload)) // write header if err := header.Encode(out); err != nil { @@ -65,7 +85,7 @@ func (m *Hessian2Codec) Encode(ctx context.Context, message remote.Message, out return nil } -func (m *Hessian2Codec) buildPayload(ctx context.Context, message remote.Message) (buf []byte, err error) { +func (m *Hessian2Codec) encodeRequestPayload(ctx context.Context, message remote.Message) (buf []byte, err error) { encoder := hessian.NewEncoder() service := &dubbo.Service{ @@ -94,13 +114,86 @@ func (m *Hessian2Codec) buildPayload(ctx context.Context, message remote.Message return encoder.Buffer(), nil } -func (m *Hessian2Codec) buildDubboHeader(message remote.Message, size int) *dubbo.DubboHeader { +func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remote.Message) (buf []byte, err error) { + encoder := hessian.NewEncoder() + + var payloadType int32 + if len(message.Tags()) != 0 { + payloadType = dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS + } else { + payloadType = dubbo.RESPONSE_VALUE + } + + if err := encoder.Encode(payloadType); err != nil { + return nil, err + } + + // encode data + data, ok := message.Data().(iface.Message) + if !ok { + return nil, fmt.Errorf("invalid data: not hessian2.MessageWriter") + } + + if err := data.Encode(encoder); err != nil { + return nil, err + } + + // encode attachments if needed + if payloadType == dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS { + if err := encoder.Encode(message.Tags()); err != nil { + return nil, err + } + } + + return encoder.Buffer(), nil +} + +func (m *Hessian2Codec) encodeExceptionPayload(ctx context.Context, message remote.Message) (buf []byte, err error) { + encoder := hessian.NewEncoder() + var payloadType int32 + if len(message.Tags()) != 0 { + payloadType = dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS + } else { + payloadType = dubbo.RESPONSE_WITH_EXCEPTION + } + + if err := encoder.Encode(payloadType); err != nil { + return nil, err + } + + // encode exception + data := message.Data() + errRaw, ok := data.(error) + if !ok { + return nil, fmt.Errorf("%v exception does not implement Error", data) + } + if exception, ok := data.(java_exception.Throwabler); ok { + if err := encoder.Encode(exception); err != nil { + return nil, err + } + } else { + if err := encoder.Encode(java_exception.NewException(errRaw.Error())); err != nil { + return nil, err + } + } + + if payloadType == dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS { + if err := encoder.Encode(message.Tags()); err != nil { + return nil, err + } + } + + return encoder.Buffer(), nil +} + +func (m *Hessian2Codec) buildDubboHeader(message remote.Message, status dubbo.StatusCode, size int) *dubbo.DubboHeader { msgType := message.MessageType() return &dubbo.DubboHeader{ IsRequest: msgType == remote.Call || msgType == remote.Oneway, IsEvent: false, IsOneWay: msgType == remote.Oneway, SerializationID: dubbo.SERIALIZATION_ID_HESSIAN, + Status: status, RequestID: uint64(message.RPCInfo().Invocation().SeqID()), DataLength: uint32(size), } @@ -151,20 +244,79 @@ func (m *Hessian2Codec) Decode(ctx context.Context, message remote.Message, in r if err := header.Decode(in); err != nil { return err } + if err := codec.SetOrCheckSeqID(int32(header.RequestID), message); err != nil { + return err + } // parse body part - body, err := in.Peek(int(header.DataLength)) + if header.IsRequest { + return m.decodeRequestBody(ctx, header, message, in) + } + return m.decodeResponseBody(ctx, header, message, in) +} + +func (m *Hessian2Codec) decodeRequestBody(ctx context.Context, header *dubbo.DubboHeader, message remote.Message, in remote.ByteBuffer) error { + length := int(header.DataLength) + if in.ReadableLen() < length { + return errors.New("invalid dubbo package with body length being less than header specified") + } + body, err := in.Next(length) if err != nil { return err } + + decoder := hessian.NewDecoder(body) + service := new(dubbo.Service) + if err := service.Decode(decoder); err != nil { + return err + } + + // decode payload + types, err := decoder.Decode() + if err != nil { + return err + } + // todo: using reflection to process types + fmt.Println(types) + if err := codec.NewDataIfNeeded(service.Method, message); err != nil { + return err + } + arg, ok := message.Data().(iface.Message) + if !ok { + return fmt.Errorf("invalid data: not hessian2.MessageReader") + } + if err := arg.Decode(decoder); err != nil { + return err + } + if err := codec.SetOrCheckMethodName(service.Method, message); err != nil { + return err + } + + if err := processAttachments(decoder, message); err != nil { + return err + } + + return nil +} + +func (m *Hessian2Codec) decodeResponseBody(ctx context.Context, header *dubbo.DubboHeader, message remote.Message, in remote.ByteBuffer) error { + length := int(header.DataLength) + if in.ReadableLen() < length { + return errors.New("invalid dubbo package with body length being less than header specified") + } + body, err := in.Next(length) + if err != nil { + return err + } + decoder := hessian.NewDecoder(body) payloadType, err := decoder.Decode() if err != nil { return err } switch payloadType { - // todo: processing other payload types with attachments - case dubbo.RESPONSE_VALUE: + // todo: processing RESPONSE_WITH_EXC + case dubbo.RESPONSE_VALUE, dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS: msg, ok := message.Data().(iface.Message) if !ok { return fmt.Errorf("invalid data %v: not hessian2.MessageReader", msg) @@ -172,11 +324,21 @@ func (m *Hessian2Codec) Decode(ctx context.Context, message remote.Message, in r if err := msg.Decode(decoder); err != nil { return err } - case dubbo.RESPONSE_WITH_EXCEPTION: + if payloadType == dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS { + if err := processAttachments(decoder, message); err != nil { + return err + } + } + case dubbo.RESPONSE_WITH_EXCEPTION, dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: exception, err := decoder.Decode() if err != nil { return err } + if payloadType == dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS { + if err := processAttachments(decoder, message); err != nil { + return err + } + } if exceptionErr, ok := exception.(error); ok { return exceptionErr } @@ -186,3 +348,21 @@ func (m *Hessian2Codec) Decode(ctx context.Context, message remote.Message, in r } return nil } + +func processAttachments(decoder iface.Decoder, message remote.Message) error { + // decode attachments + attachmentsRaw, err := decoder.Decode() + if err != nil { + return err + } + if attachments, ok := attachmentsRaw.(map[interface{}]interface{}); ok { + for keyRaw, val := range attachments { + if key, ok := keyRaw.(string); ok { + message.Tags()[key] = val + } + } + return nil + } + + return fmt.Errorf("unsupported attachments: %v", attachmentsRaw) +} diff --git a/pkg/dubbo/header.go b/pkg/dubbo/header.go index b58579a7..18796ae2 100644 --- a/pkg/dubbo/header.go +++ b/pkg/dubbo/header.go @@ -36,9 +36,9 @@ const ( MAGIC_HIGH = 0xda MAGIC_LOW = 0xbb - IS_REQUEST = 1 - IS_RESPONSE = 0 - REQUEST_BIT_SHIT = 7 + IS_REQUEST = 1 + IS_RESPONSE = 0 + REQUEST_BIT_SHIFT = 7 IS_ONEWAY = 0 IS_PINGPONG = 1 @@ -78,7 +78,7 @@ type DubboHeader struct { func (h *DubboHeader) RequestResponseByte() byte { if h.IsRequest { - return IS_REQUEST << REQUEST_BIT_SHIT + return IS_REQUEST << REQUEST_BIT_SHIFT } return 0 } @@ -117,10 +117,11 @@ func (h *DubboHeader) DecodeFromByteSlice(buf []byte) error { if buf[0] != MAGIC_HIGH || buf[1] != MAGIC_LOW { return ErrInvalidHeader } - h.IsRequest = isRequest(buf[3]) - h.IsOneWay = isOneWay(buf[3]) - h.IsEvent = isEvent(buf[3]) - h.SerializationID = getSerializationID(buf[3]) + h.IsRequest = isRequest(buf[2]) + h.IsOneWay = isOneWay(buf[2]) + h.IsEvent = isEvent(buf[2]) + h.SerializationID = getSerializationID(buf[2]) + // todo: process status h.RequestID = binary.BigEndian.Uint64(buf[4:12]) h.DataLength = binary.BigEndian.Uint32(buf[12:]) return nil @@ -143,7 +144,7 @@ func BitTest(b byte, shift int, expected byte) bool { } func isRequest(b byte) bool { - return BitTest(b, REQUEST_BIT_SHIT, IS_REQUEST) + return BitTest(b, REQUEST_BIT_SHIFT, IS_REQUEST) } func isOneWay(b byte) bool { diff --git a/pkg/dubbo/service.go b/pkg/dubbo/service.go index 9cefb30a..385934b1 100644 --- a/pkg/dubbo/service.go +++ b/pkg/dubbo/service.go @@ -19,7 +19,11 @@ package dubbo -import "time" +import ( + "time" + + "github.com/kitex-contrib/codec-hessian2/pkg/iface" +) const DEFAULT_DUBBO_PROTOCOL_VERSION = "2.0.2" @@ -31,3 +35,47 @@ type Service struct { Timeout time.Duration Group string } + +func (svc *Service) Decode(decoder iface.Decoder) error { + protoVerRaw, err := decoder.Decode() + if err != nil { + return err + } + protoVer, ok := protoVerRaw.(string) + if !ok { + return nil + } + svc.ProtocolVersion = protoVer + + pathRaw, err := decoder.Decode() + if err != nil { + return err + } + path, ok := pathRaw.(string) + if !ok { + return nil + } + svc.Path = path + + versionRaw, err := decoder.Decode() + if err != nil { + return err + } + version, ok := versionRaw.(string) + if !ok { + return nil + } + svc.Version = version + + methodRaw, err := decoder.Decode() + if err != nil { + return err + } + method, ok := methodRaw.(string) + if !ok { + return err + } + svc.Method = method + + return nil +} diff --git a/tests/dubbo/go-client/conf/dubbogo.yaml b/tests/dubbo/go-client/conf/dubbogo.yaml index 6a297cd9..4c69f819 100644 --- a/tests/dubbo/go-client/conf/dubbogo.yaml +++ b/tests/dubbo/go-client/conf/dubbogo.yaml @@ -7,4 +7,5 @@ dubbo: references: UserProvider: protocol: dubbo # dubbo protocol with hessian2 codec - interface: org.apache.dubbo.UserProvider # should be consistent with Java class + interface: TestService # should be consistent with Java class + url: "dubbo://127.0.0.1:20000" diff --git a/tests/dubbo/go-server/cmd/server.go b/tests/dubbo/go-server/cmd/server.go index baa3658b..52678204 100644 --- a/tests/dubbo/go-server/cmd/server.go +++ b/tests/dubbo/go-server/cmd/server.go @@ -44,6 +44,9 @@ func (u *UserProvider) GetUser(ctx context.Context, req int32) (*api.User, error } func (u *UserProvider) EchoInt(ctx context.Context, req int32) (int32, error) { + // for exception test + // return 0, errors.New("EchoInt failed without reason") + return req, nil } diff --git a/tests/kitex/handler.go b/tests/kitex/handler.go index 0d86a96c..bcfab473 100644 --- a/tests/kitex/handler.go +++ b/tests/kitex/handler.go @@ -11,12 +11,15 @@ type TestServiceImpl struct{} // EchoInt implements the TestServiceImpl interface. func (s *TestServiceImpl) EchoInt(ctx context.Context, req int32) (resp int32, err error) { - // TODO: Your code here... - return + // for exception test + // return 0, errors.New("EchoInt failed without reason") + + return req, nil } // Echo implements the TestServiceImpl interface. func (s *TestServiceImpl) Echo(ctx context.Context, req *echo.EchoRequest) (resp *echo.EchoResponse, err error) { - // TODO: Your code here... - return + return &echo.EchoResponse{ + Int32: req.Int32, + }, nil } diff --git a/tests/kitex/main.go b/tests/kitex/main.go index 52760ca7..076a1e0a 100644 --- a/tests/kitex/main.go +++ b/tests/kitex/main.go @@ -2,12 +2,16 @@ package main import ( "log" + "net" + + "github.com/cloudwego/kitex/server" echo "github.com/kitex-contrib/codec-hessian2/tests/kitex/kitex_gen/echo/testservice" ) func main() { - svr := echo.NewServer(new(TestServiceImpl)) + addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:20000") + svr := echo.NewServer(new(TestServiceImpl), server.WithServiceAddr(addr)) err := svr.Run() if err != nil { From 5f7c1289c4c33da80d701a4206d95b131e112dff Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 11:18:13 +0800 Subject: [PATCH 2/6] remove some comments --- pkg/codec.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/codec.go b/pkg/codec.go index 861d8ba6..596160a1 100644 --- a/pkg/codec.go +++ b/pkg/codec.go @@ -315,7 +315,6 @@ func (m *Hessian2Codec) decodeResponseBody(ctx context.Context, header *dubbo.Du return err } switch payloadType { - // todo: processing RESPONSE_WITH_EXC case dubbo.RESPONSE_VALUE, dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS: msg, ok := message.Data().(iface.Message) if !ok { From fa03c4c498f04d3fd8750d687bcf684516d7118b Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 16:23:35 +0800 Subject: [PATCH 3/6] encapsulate some statements --- pkg/codec.go | 31 +++++---------- pkg/dubbo/payload.go | 62 ++++++++++++++++++++++++++--- pkg/dubbo/service.go | 42 +++++++------------ tests/dubbo/go-client/cmd/client.go | 6 +++ tests/dubbo/go-server/cmd/server.go | 5 ++- tests/kitex/client/client.go | 6 +++ tests/kitex/handler.go | 5 ++- 7 files changed, 100 insertions(+), 57 deletions(-) diff --git a/pkg/codec.go b/pkg/codec.go index 596160a1..59d260d5 100644 --- a/pkg/codec.go +++ b/pkg/codec.go @@ -116,13 +116,7 @@ func (m *Hessian2Codec) encodeRequestPayload(ctx context.Context, message remote func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remote.Message) (buf []byte, err error) { encoder := hessian.NewEncoder() - - var payloadType int32 - if len(message.Tags()) != 0 { - payloadType = dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS - } else { - payloadType = dubbo.RESPONSE_VALUE - } + payloadType := dubbo.GetAttachmentsPayloadType(len(message.Tags()) != 0, dubbo.RESPONSE_VALUE) if err := encoder.Encode(payloadType); err != nil { return nil, err @@ -139,7 +133,7 @@ func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remot } // encode attachments if needed - if payloadType == dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS { + if dubbo.IsAttachmentsPayloadType(payloadType) { if err := encoder.Encode(message.Tags()); err != nil { return nil, err } @@ -150,12 +144,7 @@ func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remot func (m *Hessian2Codec) encodeExceptionPayload(ctx context.Context, message remote.Message) (buf []byte, err error) { encoder := hessian.NewEncoder() - var payloadType int32 - if len(message.Tags()) != 0 { - payloadType = dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS - } else { - payloadType = dubbo.RESPONSE_WITH_EXCEPTION - } + payloadType := dubbo.GetAttachmentsPayloadType(len(message.Tags()) != 0, dubbo.RESPONSE_WITH_EXCEPTION) if err := encoder.Encode(payloadType); err != nil { return nil, err @@ -177,7 +166,7 @@ func (m *Hessian2Codec) encodeExceptionPayload(ctx context.Context, message remo } } - if payloadType == dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS { + if dubbo.IsAttachmentsPayloadType(payloadType) { if err := encoder.Encode(message.Tags()); err != nil { return nil, err } @@ -272,12 +261,10 @@ func (m *Hessian2Codec) decodeRequestBody(ctx context.Context, header *dubbo.Dub } // decode payload - types, err := decoder.Decode() - if err != nil { + // there is no need to make use of types + if _, err = decoder.Decode(); err != nil { return err } - // todo: using reflection to process types - fmt.Println(types) if err := codec.NewDataIfNeeded(service.Method, message); err != nil { return err } @@ -310,7 +297,7 @@ func (m *Hessian2Codec) decodeResponseBody(ctx context.Context, header *dubbo.Du } decoder := hessian.NewDecoder(body) - payloadType, err := decoder.Decode() + payloadType, err := dubbo.DecodePayloadType(decoder) if err != nil { return err } @@ -323,7 +310,7 @@ func (m *Hessian2Codec) decodeResponseBody(ctx context.Context, header *dubbo.Du if err := msg.Decode(decoder); err != nil { return err } - if payloadType == dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS { + if dubbo.IsAttachmentsPayloadType(payloadType) { if err := processAttachments(decoder, message); err != nil { return err } @@ -333,7 +320,7 @@ func (m *Hessian2Codec) decodeResponseBody(ctx context.Context, header *dubbo.Du if err != nil { return err } - if payloadType == dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS { + if dubbo.IsAttachmentsPayloadType(payloadType) { if err := processAttachments(decoder, message); err != nil { return err } diff --git a/pkg/dubbo/payload.go b/pkg/dubbo/payload.go index 84d0585f..f4a79d1d 100644 --- a/pkg/dubbo/payload.go +++ b/pkg/dubbo/payload.go @@ -19,12 +19,62 @@ package dubbo +import ( + "fmt" + "github.com/kitex-contrib/codec-hessian2/pkg/iface" +) + +type PayloadType int32 + // Response payload type enum const ( - RESPONSE_WITH_EXCEPTION int32 = 0 - RESPONSE_VALUE int32 = 1 - RESPONSE_NULL_VALUE int32 = 2 - RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS int32 = 3 - RESPONSE_VALUE_WITH_ATTACHMENTS int32 = 4 - RESPONSE_NULL_VALUE_WITH_ATTACHMENTS int32 = 5 + RESPONSE_WITH_EXCEPTION PayloadType = iota + RESPONSE_VALUE + RESPONSE_NULL_VALUE + RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS + RESPONSE_VALUE_WITH_ATTACHMENTS + RESPONSE_NULL_VALUE_WITH_ATTACHMENTS +) + +var ( + attachmentsPair = map[PayloadType]PayloadType{ + RESPONSE_WITH_EXCEPTION: RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS, + RESPONSE_VALUE: RESPONSE_VALUE_WITH_ATTACHMENTS, + RESPONSE_NULL_VALUE: RESPONSE_NULL_VALUE_WITH_ATTACHMENTS, + } + attachmentsSet = map[PayloadType]struct{}{ + RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: {}, + RESPONSE_VALUE_WITH_ATTACHMENTS: {}, + RESPONSE_NULL_VALUE_WITH_ATTACHMENTS: {}, + } ) + +// GetAttachmentsPayloadType returns base PayloadType or base with attachments PayloadType based on expression. +// If base PayloadType does not have responding attachments PayloadType, returns itself. +func GetAttachmentsPayloadType(expression bool, base PayloadType) PayloadType { + if expression { + if pair, ok := attachmentsPair[base]; ok { + return pair + } + } + + return base +} + +// IsAttachmentsPayloadType determines whether typ is an attachments PayloadType +func IsAttachmentsPayloadType(typ PayloadType) bool { + _, ok := attachmentsSet[typ] + return ok +} + +func DecodePayloadType(decoder iface.Decoder) (PayloadType, error) { + payloadTypeRaw, err := decoder.Decode() + if err != nil { + return 0, err + } + payloadTypeInt32, ok := payloadTypeRaw.(int32) + if !ok { + return 0, fmt.Errorf("dubbo PayloadType decoded failed, got: %v", payloadTypeRaw) + } + return PayloadType(payloadTypeInt32), nil +} diff --git a/pkg/dubbo/service.go b/pkg/dubbo/service.go index 385934b1..03c9e518 100644 --- a/pkg/dubbo/service.go +++ b/pkg/dubbo/service.go @@ -20,6 +20,7 @@ package dubbo import ( + "fmt" "time" "github.com/kitex-contrib/codec-hessian2/pkg/iface" @@ -37,45 +38,32 @@ type Service struct { } func (svc *Service) Decode(decoder iface.Decoder) error { - protoVerRaw, err := decoder.Decode() - if err != nil { + if err := decodeString(decoder, &svc.ProtocolVersion, "ProtocolVersion"); err != nil { return err } - protoVer, ok := protoVerRaw.(string) - if !ok { - return nil - } - svc.ProtocolVersion = protoVer - - pathRaw, err := decoder.Decode() - if err != nil { + if err := decodeString(decoder, &svc.Path, "Path"); err != nil { return err } - path, ok := pathRaw.(string) - if !ok { - return nil - } - svc.Path = path - - versionRaw, err := decoder.Decode() - if err != nil { + if err := decodeString(decoder, &svc.Version, "Version"); err != nil { return err } - version, ok := versionRaw.(string) - if !ok { - return nil + if err := decodeString(decoder, &svc.Method, "Method"); err != nil { + return err } - svc.Version = version - methodRaw, err := decoder.Decode() + return nil +} + +// decodeString decodes dubbo Service string field +func decodeString(decoder iface.Decoder, target *string, targetName string) error { + strRaw, err := decoder.Decode() if err != nil { return err } - method, ok := methodRaw.(string) + str, ok := strRaw.(string) if !ok { - return err + return fmt.Errorf("decode dubbo Service field %s failed, got %v", targetName, strRaw) } - svc.Method = method - + *target = str return nil } diff --git a/tests/dubbo/go-client/cmd/client.go b/tests/dubbo/go-client/cmd/client.go index d6a0958b..f35f3ab3 100644 --- a/tests/dubbo/go-client/cmd/client.go +++ b/tests/dubbo/go-client/cmd/client.go @@ -48,4 +48,10 @@ func main() { panic(err) } logger.Infof("response result: %+v", resp) + + _, err = api.UserProviderClient.EchoInt(context.TODO(), 400) + if err == nil { + panic("want err but got nothing") + } + logger.Infof("got err: %+v", err) } diff --git a/tests/dubbo/go-server/cmd/server.go b/tests/dubbo/go-server/cmd/server.go index 52678204..3562e70a 100644 --- a/tests/dubbo/go-server/cmd/server.go +++ b/tests/dubbo/go-server/cmd/server.go @@ -19,6 +19,7 @@ package main import ( "context" + "errors" "strconv" "time" @@ -45,7 +46,9 @@ func (u *UserProvider) GetUser(ctx context.Context, req int32) (*api.User, error func (u *UserProvider) EchoInt(ctx context.Context, req int32) (int32, error) { // for exception test - // return 0, errors.New("EchoInt failed without reason") + if req == 400 { + return 0, errors.New("EchoInt failed without reason") + } return req, nil } diff --git a/tests/kitex/client/client.go b/tests/kitex/client/client.go index 626296b7..a3b610c5 100644 --- a/tests/kitex/client/client.go +++ b/tests/kitex/client/client.go @@ -19,4 +19,10 @@ func main() { panic(err) } klog.Infof("resp: %v", resp) + + _, err = cli.EchoInt(context.Background(), 400) + if err == nil { + panic("want err but got nothing") + } + klog.Infof("got err: %v", err) } diff --git a/tests/kitex/handler.go b/tests/kitex/handler.go index bcfab473..b3100663 100644 --- a/tests/kitex/handler.go +++ b/tests/kitex/handler.go @@ -2,6 +2,7 @@ package main import ( "context" + "errors" echo "github.com/kitex-contrib/codec-hessian2/tests/kitex/kitex_gen/echo" ) @@ -12,7 +13,9 @@ type TestServiceImpl struct{} // EchoInt implements the TestServiceImpl interface. func (s *TestServiceImpl) EchoInt(ctx context.Context, req int32) (resp int32, err error) { // for exception test - // return 0, errors.New("EchoInt failed without reason") + if req == 400 { + return 0, errors.New("EchoInt failed without reason") + } return req, nil } From ed572578a0c2a527e38042d8f74f6acce97c4a70 Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 16:35:55 +0800 Subject: [PATCH 4/6] fix go.sum --- go.sum | 7 +++++++ pkg/dubbo/payload.go | 1 + 2 files changed, 8 insertions(+) diff --git a/go.sum b/go.sum index b06c4f41..5f302565 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,7 @@ github.com/bytedance/gopkg v0.0.0-20230531144706-a12972768317 h1:SReMVmTCeJ5Nf0h github.com/bytedance/gopkg v0.0.0-20230531144706-a12972768317/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ= github.com/bytedance/mockey v1.2.0/go.mod h1:+Jm/fzWZAuhEDrPXVjDf/jLM2BlLXJkwk94zf2JZ3X4= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.8 h1:Kj4AYbZSeENfyXicsYppYKO0K2YWab+i2UTSY7Ukz9Q= github.com/bytedance/sonic v1.8.8/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= @@ -79,6 +80,7 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/iasm v0.0.0-20220818063314-28c361dae733/go.mod h1:wOQ0nsbeOLa2awv8bUYFW/EHXbjQMlZ10fAlXDB2sz8= github.com/chenzhuoyu/iasm v0.0.0-20230222070914-0b1b64b0e762/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= @@ -93,6 +95,7 @@ github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86c github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/configmanager v0.2.0 h1:niVpVg+wQ+npNqnH3dup96SMbR02Pk+tNErubYCJqKo= github.com/cloudwego/configmanager v0.2.0/go.mod h1:FLIQTjxsZRGjnmDhTttWQTy6f6DghPTatfBVOs2gQLk= github.com/cloudwego/dynamicgo v0.1.0/go.mod h1:Mdsz0XGsIImi15vxhZaHZpspNChEmBMIiWkUfD6JDKg= github.com/cloudwego/fastpb v0.0.3/go.mod h1:/V13XFTq2TUkxj2qWReV8MwfPC4NnPcy6FsrojnsSG0= @@ -110,6 +113,7 @@ github.com/cloudwego/netpoll v0.4.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY5 github.com/cloudwego/thriftgo v0.1.2/go.mod h1:LzeafuLSiHA9JTiWC8TIMIq64iadeObgRUhmVG1OC/w= github.com/cloudwego/thriftgo v0.2.4/go.mod h1:8i9AF5uDdWHGqzUhXDlubCjx4MEfKvWXGQlMWyR0tM4= github.com/cloudwego/thriftgo v0.2.7/go.mod h1:8i9AF5uDdWHGqzUhXDlubCjx4MEfKvWXGQlMWyR0tM4= +github.com/cloudwego/thriftgo v0.2.11 h1:uwFyTMBwmBJKpwxRdBvn46aHEVJJSgxkHo93RN0r3fw= github.com/cloudwego/thriftgo v0.2.11/go.mod h1:dAyXHEmKXo0LfMCrblVEY3mUZsdeuA5+i0vF5f09j7E= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -300,6 +304,7 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -436,6 +441,7 @@ github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcy github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20200427203606-3cfed13b9966/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/v2pro/plz v0.0.0-20221028024117-e5f9aec5b631/go.mod h1:3gacX+hQo+xvl0vtLqCMufzxuNCwt4geAVOMt2LQYfE= github.com/v2pro/quokka v0.0.0-20171201153428-382cb39c6ee6/go.mod h1:0VP5W9AFNVWU8C1QLNeVg8TvzoEkIHWZ4vxtxEVFWUY= @@ -479,6 +485,7 @@ go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20220722155209-00200b7164a7/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.2.0 h1:W1sUEHXiJTfjaFJ5SLo0N6lZn+0eO5gWD1MFeTGqQEY= golang.org/x/arch v0.2.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= diff --git a/pkg/dubbo/payload.go b/pkg/dubbo/payload.go index f4a79d1d..48c01d82 100644 --- a/pkg/dubbo/payload.go +++ b/pkg/dubbo/payload.go @@ -21,6 +21,7 @@ package dubbo import ( "fmt" + "github.com/kitex-contrib/codec-hessian2/pkg/iface" ) From 23720b4cf73280c655f899ccee4f5cc5817b3275 Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 16:38:36 +0800 Subject: [PATCH 5/6] fix test --- pkg/dubbo/header_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/dubbo/header_test.go b/pkg/dubbo/header_test.go index 7b12b9e1..953e707f 100644 --- a/pkg/dubbo/header_test.go +++ b/pkg/dubbo/header_test.go @@ -38,7 +38,7 @@ func TestDubboHeader_RequestResponseByte(t *testing.T) { fields: fields{ IsRequest: true, }, - want: IS_REQUEST << REQUEST_BIT_SHIT, + want: IS_REQUEST << REQUEST_BIT_SHIFT, }, { name: "response", @@ -89,7 +89,7 @@ func TestDubboHeader_EncodeToByteSlice(t *testing.T) { want: []byte{ MAGIC_HIGH, MAGIC_LOW, - (IS_REQUEST << REQUEST_BIT_SHIT) | (IS_PINGPONG << ONEWAY_BIT_SHIFT) | (IS_EVENT << EVENT_BIT_SHIFT) | SERIALIZATION_ID_HESSIAN, + (IS_REQUEST << REQUEST_BIT_SHIFT) | (IS_PINGPONG << ONEWAY_BIT_SHIFT) | (IS_EVENT << EVENT_BIT_SHIFT) | SERIALIZATION_ID_HESSIAN, byte(StatusOK), 0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21, 0x12, 0x34, 0x43, 0x21, From 27b03f26a4413361b1f63314bc94ad2460b9a52d Mon Sep 17 00:00:00 2001 From: yuxuanwang <464621663@qq.com> Date: Mon, 7 Aug 2023 17:26:29 +0800 Subject: [PATCH 6/6] remove dubbo PayloadType encapsulation --- pkg/codec.go | 14 ++++++++++++-- pkg/dubbo/payload.go | 27 ++++----------------------- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/pkg/codec.go b/pkg/codec.go index 59d260d5..5a537686 100644 --- a/pkg/codec.go +++ b/pkg/codec.go @@ -116,7 +116,12 @@ func (m *Hessian2Codec) encodeRequestPayload(ctx context.Context, message remote func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remote.Message) (buf []byte, err error) { encoder := hessian.NewEncoder() - payloadType := dubbo.GetAttachmentsPayloadType(len(message.Tags()) != 0, dubbo.RESPONSE_VALUE) + var payloadType dubbo.PayloadType + if len(message.Tags()) != 0 { + payloadType = dubbo.RESPONSE_VALUE_WITH_ATTACHMENTS + } else { + payloadType = dubbo.RESPONSE_VALUE + } if err := encoder.Encode(payloadType); err != nil { return nil, err @@ -144,7 +149,12 @@ func (m *Hessian2Codec) encodeResponsePayload(ctx context.Context, message remot func (m *Hessian2Codec) encodeExceptionPayload(ctx context.Context, message remote.Message) (buf []byte, err error) { encoder := hessian.NewEncoder() - payloadType := dubbo.GetAttachmentsPayloadType(len(message.Tags()) != 0, dubbo.RESPONSE_WITH_EXCEPTION) + var payloadType dubbo.PayloadType + if len(message.Tags()) != 0 { + payloadType = dubbo.RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS + } else { + payloadType = dubbo.RESPONSE_WITH_EXCEPTION + } if err := encoder.Encode(payloadType); err != nil { return nil, err diff --git a/pkg/dubbo/payload.go b/pkg/dubbo/payload.go index 48c01d82..8c1d7ef4 100644 --- a/pkg/dubbo/payload.go +++ b/pkg/dubbo/payload.go @@ -37,29 +37,10 @@ const ( RESPONSE_NULL_VALUE_WITH_ATTACHMENTS ) -var ( - attachmentsPair = map[PayloadType]PayloadType{ - RESPONSE_WITH_EXCEPTION: RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS, - RESPONSE_VALUE: RESPONSE_VALUE_WITH_ATTACHMENTS, - RESPONSE_NULL_VALUE: RESPONSE_NULL_VALUE_WITH_ATTACHMENTS, - } - attachmentsSet = map[PayloadType]struct{}{ - RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: {}, - RESPONSE_VALUE_WITH_ATTACHMENTS: {}, - RESPONSE_NULL_VALUE_WITH_ATTACHMENTS: {}, - } -) - -// GetAttachmentsPayloadType returns base PayloadType or base with attachments PayloadType based on expression. -// If base PayloadType does not have responding attachments PayloadType, returns itself. -func GetAttachmentsPayloadType(expression bool, base PayloadType) PayloadType { - if expression { - if pair, ok := attachmentsPair[base]; ok { - return pair - } - } - - return base +var attachmentsSet = map[PayloadType]struct{}{ + RESPONSE_WITH_EXCEPTION_WITH_ATTACHMENTS: {}, + RESPONSE_VALUE_WITH_ATTACHMENTS: {}, + RESPONSE_NULL_VALUE_WITH_ATTACHMENTS: {}, } // IsAttachmentsPayloadType determines whether typ is an attachments PayloadType