Commit e3cfbea1 authored by AlexStocks's avatar AlexStocks

Add: protobuf

parent 3ba63bda
...@@ -115,7 +115,6 @@ type Connection interface { ...@@ -115,7 +115,6 @@ type Connection interface {
var ( var (
ErrSessionClosed = errors.New("session Already Closed") ErrSessionClosed = errors.New("session Already Closed")
ErrSessionBlocked = errors.New("session Full Blocked") ErrSessionBlocked = errors.New("session Full Blocked")
ErrMsgTooLong = errors.New("Message Too Long")
ErrNullPeerAddr = errors.New("peer address is nil") ErrNullPeerAddr = errors.New("peer address is nil")
) )
......
...@@ -57,9 +57,9 @@ func (c *Client) Call(typ CodecType, addr, service, method string, args interfac ...@@ -57,9 +57,9 @@ func (c *Client) Call(typ CodecType, addr, service, method string, args interfac
b := &GettyRPCRequest{} b := &GettyRPCRequest{}
b.header.Service = service b.header.Service = service
b.header.Method = method b.header.Method = method
b.header.CallType = gettyTwoWay b.header.CallType = CT_TwoWay
if reply == nil { if reply == nil {
b.header.CallType = gettyTwoWayNoReply b.header.CallType = CT_TwoWayNoReply
} }
b.body = args b.body = args
......
...@@ -11,7 +11,6 @@ import ( ...@@ -11,7 +11,6 @@ import (
import ( import (
log "github.com/AlexStocks/log4go" log "github.com/AlexStocks/log4go"
proto "github.com/gogo/protobuf/proto" proto "github.com/gogo/protobuf/proto"
pb "github.com/golang/protobuf/proto"
"github.com/json-iterator/go" "github.com/json-iterator/go"
jerrors "github.com/juju/errors" jerrors "github.com/juju/errors"
) )
...@@ -43,18 +42,6 @@ func (c gettyCommand) String() string { ...@@ -43,18 +42,6 @@ func (c gettyCommand) String() string {
} }
//////////////////////////////////////////// ////////////////////////////////////////////
// getty call type
////////////////////////////////////////////
type gettyCallType uint32
const (
gettyOneWay gettyCallType = 0x01
gettyTwoWay = 0x02
gettyTwoWayNoReply = 0x03
)
////////////////////////////////////////////
// getty error code // getty error code
//////////////////////////////////////////// ////////////////////////////////////////////
...@@ -117,58 +104,64 @@ func GetCodecType(codecType string) CodecType { ...@@ -117,58 +104,64 @@ func GetCodecType(codecType string) CodecType {
return CodecUnknown return CodecUnknown
} }
// Codec defines the interface that decode/encode body.
type Codec interface { type Codec interface {
Encode(i interface{}) ([]byte, error) Encode(interface{}) ([]byte, error)
Decode(data []byte, i interface{}) error Decode([]byte, interface{}) error
} }
// JSONCodec uses json marshaler and unmarshaler.
type JSONCodec struct{} type JSONCodec struct{}
var ( var (
jsonstd = jsoniter.ConfigCompatibleWithStandardLibrary jsonstd = jsoniter.ConfigCompatibleWithStandardLibrary
) )
// Encode encodes an object into slice of bytes.
func (c JSONCodec) Encode(i interface{}) ([]byte, error) { func (c JSONCodec) Encode(i interface{}) ([]byte, error) {
// return json.Marshal(i) // return json.Marshal(i)
return jsonstd.Marshal(i) return jsonstd.Marshal(i)
} }
// Decode decodes an object from slice of bytes.
func (c JSONCodec) Decode(data []byte, i interface{}) error { func (c JSONCodec) Decode(data []byte, i interface{}) error {
// return json.Unmarshal(data, i) // return json.Unmarshal(data, i)
return jsonstd.Unmarshal(data, i) return jsonstd.Unmarshal(data, i)
} }
// PBCodec uses protobuf marshaler and unmarshaler.
type PBCodec struct{} type PBCodec struct{}
// Encode encodes an object into slice of bytes. // Encode takes the protocol buffer
func (c PBCodec) Encode(i interface{}) ([]byte, error) { // and encodes it into the wire format, returning the data.
if m, ok := i.(proto.Marshaler); ok { func (c PBCodec) Encode(msg interface{}) ([]byte, error) {
return m.Marshal() // Can the object marshal itself?
if pb, ok := msg.(proto.Marshaler); ok {
pbBuf, err := pb.Marshal()
return pbBuf, jerrors.Trace(err)
} }
if m, ok := i.(pb.Message); ok { if pb, ok := msg.(proto.Message); ok {
return pb.Marshal(m) p := proto.NewBuffer(nil)
err := p.Marshal(pb)
return p.Bytes(), jerrors.Trace(err)
} }
return nil, fmt.Errorf("%T is not a proto.Marshaler", i) return nil, fmt.Errorf("protobuf can not marshal %T", msg)
} }
// Decode decodes an object from slice of bytes. // Decode parses the protocol buffer representation in buf and
func (c PBCodec) Decode(data []byte, i interface{}) error { // writes the decoded result to pb. If the struct underlying pb does not match
if m, ok := i.(proto.Unmarshaler); ok { // the data in buf, the results can be unpredictable.
return m.Unmarshal(data) //
// UnmarshalMerge merges into existing data in pb.
// Most code should use Unmarshal instead.
func (c PBCodec) Decode(buf []byte, msg interface{}) error {
// If the object can unmarshal itself, let it.
if u, ok := msg.(proto.Unmarshaler); ok {
return jerrors.Trace(u.Unmarshal(buf))
} }
if m, ok := i.(pb.Message); ok { if pb, ok := msg.(proto.Message); ok {
return pb.Unmarshal(data, m) return jerrors.Trace(proto.NewBuffer(nil).Unmarshal(pb))
} }
return fmt.Errorf("%T is not a proto.Unmarshaler", i) return fmt.Errorf("protobuf can not unmarshal %T", msg)
} }
//////////////////////////////////////////// ////////////////////////////////////////////
...@@ -182,11 +175,10 @@ const ( ...@@ -182,11 +175,10 @@ const (
) )
var ( var (
ErrNotEnoughStream = jerrors.New("packet stream is not enough") ErrNotEnoughStream = jerrors.New("packet stream is not enough")
ErrTooLargePackage = jerrors.New("package length is exceed the getty package's legal maximum length.") ErrTooLargePackage = jerrors.New("package length is exceed the getty package's legal maximum length.")
ErrInvalidPackage = jerrors.New("invalid rpc package") ErrInvalidPackage = jerrors.New("invalid rpc package")
ErrNotFoundServiceOrMethod = jerrors.New("server invalid service or method") ErrIllegalMagic = jerrors.New("package magic is not right.")
ErrIllegalMagic = jerrors.New("package magic is not right.")
) )
var ( var (
...@@ -301,12 +293,12 @@ func (p *GettyPackage) Unmarshal(buf *bytes.Buffer) (int, error) { ...@@ -301,12 +293,12 @@ func (p *GettyPackage) Unmarshal(buf *bytes.Buffer) (int, error) {
type GettyRPCHeaderLenType uint16 type GettyRPCHeaderLenType uint16
// easyjson:json // // easyjson:json
type GettyRPCRequestHeader struct { // type GettyRPCRequestHeader struct {
Service string // Service string
Method string // Method string
CallType gettyCallType // CallType gettyCallType
} // }
type GettyRPCRequest struct { type GettyRPCRequest struct {
header GettyRPCRequestHeader header GettyRPCRequestHeader
...@@ -331,7 +323,7 @@ func (req *GettyRPCRequest) Marshal(sz CodecType, buf *bytes.Buffer) (int, error ...@@ -331,7 +323,7 @@ func (req *GettyRPCRequest) Marshal(sz CodecType, buf *bytes.Buffer) (int, error
if codec == nil { if codec == nil {
return 0, jerrors.Errorf("can not find codec for %s", sz) return 0, jerrors.Errorf("can not find codec for %s", sz)
} }
headerData, err := codec.Encode(req.header) headerData, err := codec.Encode(&req.header)
if err != nil { if err != nil {
return 0, jerrors.Trace(err) return 0, jerrors.Trace(err)
} }
...@@ -410,9 +402,9 @@ func (req *GettyRPCRequest) GetHeader() interface{} { ...@@ -410,9 +402,9 @@ func (req *GettyRPCRequest) GetHeader() interface{} {
// GettyRPCResponse // GettyRPCResponse
//////////////////////////////////////////// ////////////////////////////////////////////
type GettyRPCResponseHeader struct { // type GettyRPCResponseHeader struct {
Error string // Error string
} // }
type GettyRPCResponse struct { type GettyRPCResponse struct {
header GettyRPCResponseHeader header GettyRPCResponseHeader
...@@ -434,7 +426,7 @@ func (resp *GettyRPCResponse) Marshal(sz CodecType, buf *bytes.Buffer) (int, err ...@@ -434,7 +426,7 @@ func (resp *GettyRPCResponse) Marshal(sz CodecType, buf *bytes.Buffer) (int, err
if codec == nil { if codec == nil {
return 0, jerrors.Errorf("can not find codec for %d", sz) return 0, jerrors.Errorf("can not find codec for %d", sz)
} }
headerData, err := codec.Encode(resp.header) headerData, err := codec.Encode(&resp.header)
if err != nil { if err != nil {
return 0, jerrors.Trace(err) return 0, jerrors.Trace(err)
} }
......
// Code generated by protoc-gen-gogo. DO NOT EDIT. // Code generated by protoc-gen-gogo. DO NOT EDIT.
// source: getty.proto // source: codec.proto
/* /*
Package prc is a generated protocol buffer package. Package rpc is a generated protocol buffer package.
It is generated from these files: It is generated from these files:
getty.proto codec.proto
It has these top-level messages: It has these top-level messages:
GettyRPCRequestHeader GettyRPCRequestHeader
GettyRPCResponseHeader
*/ */
package rpc package rpc
...@@ -73,21 +74,30 @@ func (x *CallType) UnmarshalJSON(data []byte) error { ...@@ -73,21 +74,30 @@ func (x *CallType) UnmarshalJSON(data []byte) error {
*x = CallType(value) *x = CallType(value)
return nil return nil
} }
func (CallType) EnumDescriptor() ([]byte, []int) { return fileDescriptorGetty, []int{0} } func (CallType) EnumDescriptor() ([]byte, []int) { return fileDescriptorCodec, []int{0} }
type GettyRPCRequestHeader struct { type GettyRPCRequestHeader struct {
Service string `protobuf:"bytes,1,opt,name=Service" json:"Service"` Service string `protobuf:"bytes,1,opt,name=Service" json:"Service"`
Method string `protobuf:"bytes,2,opt,name=Method" json:"Method"` Method string `protobuf:"bytes,2,opt,name=Method" json:"Method"`
CallType CallType `protobuf:"varint,3,opt,name=CallType,enum=prc.CallType" json:"CallType"` CallType CallType `protobuf:"varint,3,opt,name=CallType,enum=rpc.CallType" json:"CallType"`
} }
func (m *GettyRPCRequestHeader) Reset() { *m = GettyRPCRequestHeader{} } func (m *GettyRPCRequestHeader) Reset() { *m = GettyRPCRequestHeader{} }
func (*GettyRPCRequestHeader) ProtoMessage() {} func (*GettyRPCRequestHeader) ProtoMessage() {}
func (*GettyRPCRequestHeader) Descriptor() ([]byte, []int) { return fileDescriptorGetty, []int{0} } func (*GettyRPCRequestHeader) Descriptor() ([]byte, []int) { return fileDescriptorCodec, []int{0} }
type GettyRPCResponseHeader struct {
Error string `protobuf:"bytes,1,opt,name=Error" json:"Error"`
}
func (m *GettyRPCResponseHeader) Reset() { *m = GettyRPCResponseHeader{} }
func (*GettyRPCResponseHeader) ProtoMessage() {}
func (*GettyRPCResponseHeader) Descriptor() ([]byte, []int) { return fileDescriptorCodec, []int{1} }
func init() { func init() {
proto.RegisterType((*GettyRPCRequestHeader)(nil), "prc.GettyRPCRequestHeader") proto.RegisterType((*GettyRPCRequestHeader)(nil), "rpc.GettyRPCRequestHeader")
proto.RegisterEnum("prc.CallType", CallType_name, CallType_value) proto.RegisterType((*GettyRPCResponseHeader)(nil), "rpc.GettyRPCResponseHeader")
proto.RegisterEnum("rpc.CallType", CallType_name, CallType_value)
} }
func (x CallType) String() string { func (x CallType) String() string {
s, ok := CallType_name[int32(x)] s, ok := CallType_name[int32(x)]
...@@ -168,19 +178,89 @@ func (this *GettyRPCRequestHeader) Equal(that interface{}) bool { ...@@ -168,19 +178,89 @@ func (this *GettyRPCRequestHeader) Equal(that interface{}) bool {
} }
return true return true
} }
func (this *GettyRPCResponseHeader) VerboseEqual(that interface{}) error {
if that == nil {
if this == nil {
return nil
}
return fmt.Errorf("that == nil && this != nil")
}
that1, ok := that.(*GettyRPCResponseHeader)
if !ok {
that2, ok := that.(GettyRPCResponseHeader)
if ok {
that1 = &that2
} else {
return fmt.Errorf("that is not of type *GettyRPCResponseHeader")
}
}
if that1 == nil {
if this == nil {
return nil
}
return fmt.Errorf("that is type *GettyRPCResponseHeader but is nil && this != nil")
} else if this == nil {
return fmt.Errorf("that is type *GettyRPCResponseHeader but is not nil && this == nil")
}
if this.Error != that1.Error {
return fmt.Errorf("Error this(%v) Not Equal that(%v)", this.Error, that1.Error)
}
return nil
}
func (this *GettyRPCResponseHeader) Equal(that interface{}) bool {
if that == nil {
if this == nil {
return true
}
return false
}
that1, ok := that.(*GettyRPCResponseHeader)
if !ok {
that2, ok := that.(GettyRPCResponseHeader)
if ok {
that1 = &that2
} else {
return false
}
}
if that1 == nil {
if this == nil {
return true
}
return false
} else if this == nil {
return false
}
if this.Error != that1.Error {
return false
}
return true
}
func (this *GettyRPCRequestHeader) GoString() string { func (this *GettyRPCRequestHeader) GoString() string {
if this == nil { if this == nil {
return "nil" return "nil"
} }
s := make([]string, 0, 7) s := make([]string, 0, 7)
s = append(s, "&prc.GettyRPCRequestHeader{") s = append(s, "&rpc.GettyRPCRequestHeader{")
s = append(s, "Service: "+fmt.Sprintf("%#v", this.Service)+",\n") s = append(s, "Service: "+fmt.Sprintf("%#v", this.Service)+",\n")
s = append(s, "Method: "+fmt.Sprintf("%#v", this.Method)+",\n") s = append(s, "Method: "+fmt.Sprintf("%#v", this.Method)+",\n")
s = append(s, "CallType: "+fmt.Sprintf("%#v", this.CallType)+",\n") s = append(s, "CallType: "+fmt.Sprintf("%#v", this.CallType)+",\n")
s = append(s, "}") s = append(s, "}")
return strings.Join(s, "") return strings.Join(s, "")
} }
func valueToGoStringGetty(v interface{}, typ string) string { func (this *GettyRPCResponseHeader) GoString() string {
if this == nil {
return "nil"
}
s := make([]string, 0, 5)
s = append(s, "&rpc.GettyRPCResponseHeader{")
s = append(s, "Error: "+fmt.Sprintf("%#v", this.Error)+",\n")
s = append(s, "}")
return strings.Join(s, "")
}
func valueToGoStringCodec(v interface{}, typ string) string {
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if rv.IsNil() { if rv.IsNil() {
return "nil" return "nil"
...@@ -205,19 +285,41 @@ func (m *GettyRPCRequestHeader) MarshalTo(dAtA []byte) (int, error) { ...@@ -205,19 +285,41 @@ func (m *GettyRPCRequestHeader) MarshalTo(dAtA []byte) (int, error) {
_ = l _ = l
dAtA[i] = 0xa dAtA[i] = 0xa
i++ i++
i = encodeVarintGetty(dAtA, i, uint64(len(m.Service))) i = encodeVarintCodec(dAtA, i, uint64(len(m.Service)))
i += copy(dAtA[i:], m.Service) i += copy(dAtA[i:], m.Service)
dAtA[i] = 0x12 dAtA[i] = 0x12
i++ i++
i = encodeVarintGetty(dAtA, i, uint64(len(m.Method))) i = encodeVarintCodec(dAtA, i, uint64(len(m.Method)))
i += copy(dAtA[i:], m.Method) i += copy(dAtA[i:], m.Method)
dAtA[i] = 0x18 dAtA[i] = 0x18
i++ i++
i = encodeVarintGetty(dAtA, i, uint64(m.CallType)) i = encodeVarintCodec(dAtA, i, uint64(m.CallType))
return i, nil return i, nil
} }
func encodeFixed64Getty(dAtA []byte, offset int, v uint64) int { func (m *GettyRPCResponseHeader) Marshal() (dAtA []byte, err error) {
size := m.Size()
dAtA = make([]byte, size)
n, err := m.MarshalTo(dAtA)
if err != nil {
return nil, err
}
return dAtA[:n], nil
}
func (m *GettyRPCResponseHeader) MarshalTo(dAtA []byte) (int, error) {
var i int
_ = i
var l int
_ = l
dAtA[i] = 0xa
i++
i = encodeVarintCodec(dAtA, i, uint64(len(m.Error)))
i += copy(dAtA[i:], m.Error)
return i, nil
}
func encodeFixed64Codec(dAtA []byte, offset int, v uint64) int {
dAtA[offset] = uint8(v) dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8) dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16) dAtA[offset+2] = uint8(v >> 16)
...@@ -228,14 +330,14 @@ func encodeFixed64Getty(dAtA []byte, offset int, v uint64) int { ...@@ -228,14 +330,14 @@ func encodeFixed64Getty(dAtA []byte, offset int, v uint64) int {
dAtA[offset+7] = uint8(v >> 56) dAtA[offset+7] = uint8(v >> 56)
return offset + 8 return offset + 8
} }
func encodeFixed32Getty(dAtA []byte, offset int, v uint32) int { func encodeFixed32Codec(dAtA []byte, offset int, v uint32) int {
dAtA[offset] = uint8(v) dAtA[offset] = uint8(v)
dAtA[offset+1] = uint8(v >> 8) dAtA[offset+1] = uint8(v >> 8)
dAtA[offset+2] = uint8(v >> 16) dAtA[offset+2] = uint8(v >> 16)
dAtA[offset+3] = uint8(v >> 24) dAtA[offset+3] = uint8(v >> 24)
return offset + 4 return offset + 4
} }
func encodeVarintGetty(dAtA []byte, offset int, v uint64) int { func encodeVarintCodec(dAtA []byte, offset int, v uint64) int {
for v >= 1<<7 { for v >= 1<<7 {
dAtA[offset] = uint8(v&0x7f | 0x80) dAtA[offset] = uint8(v&0x7f | 0x80)
v >>= 7 v >>= 7
...@@ -248,14 +350,22 @@ func (m *GettyRPCRequestHeader) Size() (n int) { ...@@ -248,14 +350,22 @@ func (m *GettyRPCRequestHeader) Size() (n int) {
var l int var l int
_ = l _ = l
l = len(m.Service) l = len(m.Service)
n += 1 + l + sovGetty(uint64(l)) n += 1 + l + sovCodec(uint64(l))
l = len(m.Method) l = len(m.Method)
n += 1 + l + sovGetty(uint64(l)) n += 1 + l + sovCodec(uint64(l))
n += 1 + sovGetty(uint64(m.CallType)) n += 1 + sovCodec(uint64(m.CallType))
return n return n
} }
func sovGetty(x uint64) (n int) { func (m *GettyRPCResponseHeader) Size() (n int) {
var l int
_ = l
l = len(m.Error)
n += 1 + l + sovCodec(uint64(l))
return n
}
func sovCodec(x uint64) (n int) {
for { for {
n++ n++
x >>= 7 x >>= 7
...@@ -265,8 +375,8 @@ func sovGetty(x uint64) (n int) { ...@@ -265,8 +375,8 @@ func sovGetty(x uint64) (n int) {
} }
return n return n
} }
func sozGetty(x uint64) (n int) { func sozCodec(x uint64) (n int) {
return sovGetty(uint64((x << 1) ^ uint64((int64(x) >> 63)))) return sovCodec(uint64((x << 1) ^ uint64((int64(x) >> 63))))
} }
func (this *GettyRPCRequestHeader) String() string { func (this *GettyRPCRequestHeader) String() string {
if this == nil { if this == nil {
...@@ -280,7 +390,17 @@ func (this *GettyRPCRequestHeader) String() string { ...@@ -280,7 +390,17 @@ func (this *GettyRPCRequestHeader) String() string {
}, "") }, "")
return s return s
} }
func valueToStringGetty(v interface{}) string { func (this *GettyRPCResponseHeader) String() string {
if this == nil {
return "nil"
}
s := strings.Join([]string{`&GettyRPCResponseHeader{`,
`Error:` + fmt.Sprintf("%v", this.Error) + `,`,
`}`,
}, "")
return s
}
func valueToStringCodec(v interface{}) string {
rv := reflect.ValueOf(v) rv := reflect.ValueOf(v)
if rv.IsNil() { if rv.IsNil() {
return "nil" return "nil"
...@@ -296,7 +416,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -296,7 +416,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowGetty return ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
...@@ -324,7 +444,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -324,7 +444,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
var stringLen uint64 var stringLen uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowGetty return ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
...@@ -338,7 +458,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -338,7 +458,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
} }
intStringLen := int(stringLen) intStringLen := int(stringLen)
if intStringLen < 0 { if intStringLen < 0 {
return ErrInvalidLengthGetty return ErrInvalidLengthCodec
} }
postIndex := iNdEx + intStringLen postIndex := iNdEx + intStringLen
if postIndex > l { if postIndex > l {
...@@ -353,7 +473,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -353,7 +473,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
var stringLen uint64 var stringLen uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowGetty return ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
...@@ -367,7 +487,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -367,7 +487,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
} }
intStringLen := int(stringLen) intStringLen := int(stringLen)
if intStringLen < 0 { if intStringLen < 0 {
return ErrInvalidLengthGetty return ErrInvalidLengthCodec
} }
postIndex := iNdEx + intStringLen postIndex := iNdEx + intStringLen
if postIndex > l { if postIndex > l {
...@@ -382,7 +502,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -382,7 +502,7 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
m.CallType = 0 m.CallType = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowGetty return ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
...@@ -396,12 +516,91 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -396,12 +516,91 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
} }
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipGetty(dAtA[iNdEx:]) skippy, err := skipCodec(dAtA[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthCodec
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *GettyRPCResponseHeader) Unmarshal(dAtA []byte) error {
l := len(dAtA)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCodec
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: GettyRPCResponseHeader: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: GettyRPCResponseHeader: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowCodec
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthCodec
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Error = string(dAtA[iNdEx:postIndex])
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipCodec(dAtA[iNdEx:])
if err != nil { if err != nil {
return err return err
} }
if skippy < 0 { if skippy < 0 {
return ErrInvalidLengthGetty return ErrInvalidLengthCodec
} }
if (iNdEx + skippy) > l { if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
...@@ -415,14 +614,14 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error { ...@@ -415,14 +614,14 @@ func (m *GettyRPCRequestHeader) Unmarshal(dAtA []byte) error {
} }
return nil return nil
} }
func skipGetty(dAtA []byte) (n int, err error) { func skipCodec(dAtA []byte) (n int, err error) {
l := len(dAtA) l := len(dAtA)
iNdEx := 0 iNdEx := 0
for iNdEx < l { for iNdEx < l {
var wire uint64 var wire uint64
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowGetty return 0, ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
...@@ -439,7 +638,7 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -439,7 +638,7 @@ func skipGetty(dAtA []byte) (n int, err error) {
case 0: case 0:
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowGetty return 0, ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
...@@ -457,7 +656,7 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -457,7 +656,7 @@ func skipGetty(dAtA []byte) (n int, err error) {
var length int var length int
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowGetty return 0, ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
...@@ -471,7 +670,7 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -471,7 +670,7 @@ func skipGetty(dAtA []byte) (n int, err error) {
} }
iNdEx += length iNdEx += length
if length < 0 { if length < 0 {
return 0, ErrInvalidLengthGetty return 0, ErrInvalidLengthCodec
} }
return iNdEx, nil return iNdEx, nil
case 3: case 3:
...@@ -480,7 +679,7 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -480,7 +679,7 @@ func skipGetty(dAtA []byte) (n int, err error) {
var start int = iNdEx var start int = iNdEx
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return 0, ErrIntOverflowGetty return 0, ErrIntOverflowCodec
} }
if iNdEx >= l { if iNdEx >= l {
return 0, io.ErrUnexpectedEOF return 0, io.ErrUnexpectedEOF
...@@ -496,7 +695,7 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -496,7 +695,7 @@ func skipGetty(dAtA []byte) (n int, err error) {
if innerWireType == 4 { if innerWireType == 4 {
break break
} }
next, err := skipGetty(dAtA[start:]) next, err := skipCodec(dAtA[start:])
if err != nil { if err != nil {
return 0, err return 0, err
} }
...@@ -516,30 +715,31 @@ func skipGetty(dAtA []byte) (n int, err error) { ...@@ -516,30 +715,31 @@ func skipGetty(dAtA []byte) (n int, err error) {
} }
var ( var (
ErrInvalidLengthGetty = fmt.Errorf("proto: negative length found during unmarshaling") ErrInvalidLengthCodec = fmt.Errorf("proto: negative length found during unmarshaling")
ErrIntOverflowGetty = fmt.Errorf("proto: integer overflow") ErrIntOverflowCodec = fmt.Errorf("proto: integer overflow")
) )
func init() { proto.RegisterFile("getty.proto", fileDescriptorGetty) } func init() { proto.RegisterFile("codec.proto", fileDescriptorCodec) }
var fileDescriptorGetty = []byte{ var fileDescriptorCodec = []byte{
// 277 bytes of a gzipped FileDescriptorProto // 304 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4e, 0x4f, 0x2d, 0x29, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x54, 0x8e, 0x4f, 0x4b, 0x02, 0x41,
0xa9, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x2e, 0x28, 0x4a, 0x96, 0xd2, 0x4d, 0xcf, 0x18, 0xc6, 0xe7, 0xd5, 0xfe, 0x39, 0x61, 0x2c, 0x4b, 0x85, 0x48, 0xbc, 0x89, 0x27, 0x09, 0x5a,
0x2c, 0xc9, 0x28, 0x4d, 0xd2, 0x4b, 0xce, 0xcf, 0xd5, 0x4f, 0xcf, 0x4f, 0xcf, 0xd7, 0x07, 0xcb, 0x21, 0xfc, 0x04, 0x4a, 0x14, 0x84, 0x1a, 0x9b, 0xe1, 0x31, 0x74, 0x7c, 0x53, 0xc1, 0x9c, 0x69,
0x25, 0x95, 0xa6, 0x81, 0x79, 0x60, 0x0e, 0x98, 0x05, 0xd1, 0xa3, 0xd4, 0xc6, 0xc8, 0x25, 0xea, 0x1c, 0x8b, 0xbd, 0x75, 0xea, 0xdc, 0xc7, 0xe8, 0xa3, 0x78, 0xf4, 0xd8, 0x29, 0xdc, 0xe9, 0xd2,
0x0e, 0x32, 0x23, 0x28, 0xc0, 0x39, 0x28, 0xb5, 0xb0, 0x34, 0xb5, 0xb8, 0xc4, 0x23, 0x35, 0x31, 0xd1, 0x8f, 0x10, 0xad, 0xab, 0xd6, 0x6d, 0x7e, 0xbf, 0xe7, 0x19, 0xde, 0x87, 0xef, 0x0a, 0xd9,
0x25, 0xb5, 0x48, 0x48, 0x8e, 0x8b, 0x3d, 0x38, 0xb5, 0xa8, 0x2c, 0x33, 0x39, 0x55, 0x82, 0x51, 0x21, 0xe1, 0x29, 0x2d, 0x8d, 0x74, 0x93, 0x5a, 0x89, 0xec, 0x69, 0xb7, 0x6f, 0x7a, 0xe3, 0xb6,
0x81, 0x51, 0x83, 0xd3, 0x89, 0xe5, 0xc4, 0x3d, 0x79, 0x86, 0x20, 0x98, 0xa0, 0x90, 0x0c, 0x17, 0x27, 0xe4, 0x43, 0xb1, 0x2b, 0xbb, 0xb2, 0x18, 0x65, 0xed, 0xf1, 0x7d, 0x44, 0x11, 0x44, 0xaf,
0x9b, 0x6f, 0x6a, 0x49, 0x46, 0x7e, 0x8a, 0x04, 0x13, 0x92, 0x34, 0x54, 0x4c, 0x48, 0x9f, 0x8b, 0xc5, 0x9f, 0xfc, 0x2b, 0xf0, 0x83, 0x0b, 0x32, 0x26, 0xf0, 0xaf, 0x2b, 0x3e, 0x3d, 0x8e, 0x69,
0xc3, 0x39, 0x31, 0x27, 0x27, 0xa4, 0xb2, 0x20, 0x55, 0x82, 0x59, 0x81, 0x51, 0x83, 0xcf, 0x88, 0x64, 0x2e, 0xa9, 0xd5, 0x21, 0xed, 0x22, 0xdf, 0xbe, 0x21, 0xfd, 0xd4, 0x17, 0x94, 0x81, 0x1c,
0x57, 0xaf, 0xa0, 0x28, 0x59, 0x0f, 0x26, 0x08, 0x55, 0x0e, 0x57, 0xa4, 0xe5, 0x8b, 0xd0, 0x20, 0x14, 0x52, 0xe5, 0x8d, 0xc9, 0xe7, 0x31, 0xf3, 0x97, 0xd2, 0x3d, 0xe2, 0x5b, 0x55, 0x32, 0x3d,
0xc4, 0xcb, 0xc5, 0xe9, 0x1c, 0x12, 0x1f, 0xea, 0xe7, 0xed, 0x1f, 0xee, 0x27, 0xc0, 0x00, 0xe5, 0xd9, 0xc9, 0x24, 0xfe, 0xc4, 0xb1, 0x73, 0x8b, 0x7c, 0xa7, 0xd2, 0x1a, 0x0c, 0x1a, 0x81, 0xa2,
0xfa, 0xe7, 0xa5, 0x86, 0x27, 0x56, 0x0a, 0x30, 0x42, 0xb9, 0x21, 0xe5, 0xf9, 0x20, 0x2e, 0x93, 0x4c, 0x32, 0x07, 0x85, 0xbd, 0xb3, 0xb4, 0xa7, 0x95, 0xf0, 0x96, 0x32, 0xae, 0xaf, 0x4a, 0xf9,
0x90, 0x08, 0x97, 0x00, 0x9c, 0xeb, 0x97, 0x1f, 0x94, 0x5a, 0x90, 0x53, 0x29, 0xc0, 0xec, 0x64, 0x12, 0x3f, 0x5c, 0xef, 0x18, 0x29, 0x39, 0x1c, 0x51, 0x3c, 0x24, 0xcb, 0x37, 0xcf, 0xb5, 0x96,
0x72, 0xe2, 0xa1, 0x1c, 0xc3, 0x85, 0x87, 0x72, 0x0c, 0x37, 0x1e, 0xca, 0x31, 0x3c, 0x78, 0x28, 0xfa, 0xdf, 0x8c, 0x85, 0x3a, 0xa9, 0xae, 0xcf, 0xb8, 0x69, 0x9e, 0xaa, 0x34, 0xee, 0x6e, 0x6b,
0xc7, 0xf8, 0xe1, 0xa1, 0x1c, 0x63, 0xc3, 0x23, 0x39, 0xc6, 0x15, 0x8f, 0xe4, 0x18, 0x4f, 0x3c, 0x57, 0xf5, 0x66, 0xcd, 0x61, 0x31, 0xd6, 0x87, 0xd4, 0x6c, 0x05, 0x0e, 0xc4, 0xd8, 0x78, 0x96,
0x92, 0x63, 0xbc, 0xf0, 0x48, 0x8e, 0xf1, 0xc1, 0x23, 0x39, 0xc6, 0x17, 0x8f, 0xe4, 0x18, 0x3e, 0xbf, 0x98, 0x70, 0xf7, 0xb9, 0xb3, 0xc2, 0x9a, 0xf4, 0x49, 0x0d, 0x02, 0x27, 0x59, 0x2e, 0x4d,
0x3c, 0x92, 0x63, 0x9c, 0xf0, 0x58, 0x8e, 0x01, 0x10, 0x00, 0x00, 0xff, 0xff, 0x37, 0xfb, 0x13, 0x42, 0x64, 0xd3, 0x10, 0xd9, 0x47, 0x88, 0x6c, 0x16, 0x22, 0xcc, 0x43, 0x84, 0x17, 0x8b, 0xf0,
0x0a, 0x4f, 0x01, 0x00, 0x00, 0x6e, 0x11, 0x26, 0x16, 0x61, 0x6a, 0x11, 0x66, 0x16, 0xe1, 0xdb, 0x22, 0x9b, 0x5b, 0x84, 0xb7,
0x2f, 0x64, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa8, 0xe8, 0x87, 0x62, 0x85, 0x01, 0x00, 0x00,
} }
...@@ -90,7 +90,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) { ...@@ -90,7 +90,7 @@ func (h *RpcServerHandler) OnMessage(session getty.Session, pkg interface{}) {
h.replyCmd(session, req, gettyCmdHbResponse, "") h.replyCmd(session, req, gettyCmdHbResponse, "")
return return
} }
if req.header.CallType == gettyTwoWayNoReply { if req.header.CallType == CT_TwoWayNoReply {
h.replyCmd(session, req, gettyCmdRPCResponse, "") h.replyCmd(session, req, gettyCmdRPCResponse, "")
function := req.methodType.method.Func function := req.methodType.method.Func
function.Call([]reflect.Value{req.service.rcvr, req.argv, req.replyv}) function.Call([]reflect.Value{req.service.rcvr, req.argv, req.replyv})
......
...@@ -35,3 +35,7 @@ message GettyRPCRequestHeader { ...@@ -35,3 +35,7 @@ message GettyRPCRequestHeader {
optional string Method = 2 [(gogoproto.nullable) = false]; optional string Method = 2 [(gogoproto.nullable) = false];
optional CallType CallType = 3 [(gogoproto.nullable) = false]; optional CallType CallType = 3 [(gogoproto.nullable) = false];
} }
message GettyRPCResponseHeader {
optional string Error = 1 [(gogoproto.nullable) = false];
}
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
# FILE : pb.sh # FILE : pb.sh
# ****************************************************** # ******************************************************
mkdir ./src
# descriptor.proto # descriptor.proto
gopath=~/test/golang/lib/src/github.com/gogo/protobuf/protobuf gopath=~/test/golang/lib/src/github.com/gogo/protobuf/protobuf
# If you are using any gogo.proto extensions you will need to specify the # If you are using any gogo.proto extensions you will need to specify the
...@@ -21,4 +19,4 @@ gogopath=~/test/golang/lib/src/ ...@@ -21,4 +19,4 @@ gogopath=~/test/golang/lib/src/
# protoc -I=$gopath:$gogopath:/Users/alex/test/golang/lib/src/github.com/AlexStocks/goext/database/redis/:./ --gogoslick_out=Mredis_meta.proto="github.com/AlexStocks/goext/database/redis":../app/ cluster_meta.proto # protoc -I=$gopath:$gogopath:/Users/alex/test/golang/lib/src/github.com/AlexStocks/goext/database/redis/:./ --gogoslick_out=Mredis_meta.proto="github.com/AlexStocks/goext/database/redis":../app/ cluster_meta.proto
# protoc -I=$gopath:$gogopath:/Users/alex/test/golang/lib/src/github.com/AlexStocks/goext/database/redis/:./ --gogoslick_out=Mredis_meta.proto="github.com/AlexStocks/goext/database/redis":../app/ response.proto # protoc -I=$gopath:$gogopath:/Users/alex/test/golang/lib/src/github.com/AlexStocks/goext/database/redis/:./ --gogoslick_out=Mredis_meta.proto="github.com/AlexStocks/goext/database/redis":../app/ response.proto
# protoc -I=$gopath:$gogopath:./ --gogoslick_out=Mrole.proto="github.com/AlexStocks/goext/database/registry":./src/ service.proto # protoc -I=$gopath:$gogopath:./ --gogoslick_out=Mrole.proto="github.com/AlexStocks/goext/database/registry":./src/ service.proto
protoc -I=$gopath:$gogopath:./ --gogoslick_out=./src/ rpc.proto protoc -I=$gopath:$gogopath:./ --gogoslick_out=../ codec.proto
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
import ( import (
"github.com/AlexStocks/getty" "github.com/AlexStocks/getty"
"github.com/AlexStocks/goext/log"
log "github.com/AlexStocks/log4go" log "github.com/AlexStocks/log4go"
jerrors "github.com/juju/errors" jerrors "github.com/juju/errors"
) )
...@@ -47,12 +48,16 @@ func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface ...@@ -47,12 +48,16 @@ func (p *RpcServerPackageHandler) Read(ss getty.Session, data []byte) (interface
return req, length, nil return req, length, nil
} }
// get service & method // get service & method
gxlog.CError("req service:%s, service map:%#v", req.header.Service, p.server.serviceMap)
req.service = p.server.serviceMap[req.header.Service] req.service = p.server.serviceMap[req.header.Service]
if req.service != nil { if req.service != nil {
req.methodType = req.service.method[req.header.Method] req.methodType = req.service.method[req.header.Method]
} }
if req.service == nil || req.methodType == nil { if req.service == nil {
return nil, 0, ErrNotFoundServiceOrMethod return nil, 0, jerrors.Errorf("request service is nil")
}
if req.methodType == nil {
return nil, 0, jerrors.Errorf("request method is nil")
} }
// get args // get args
argIsValue := false argIsValue := false
......
...@@ -504,7 +504,7 @@ LOOP: ...@@ -504,7 +504,7 @@ LOOP:
case outPkg = <-s.wQ: case outPkg = <-s.wQ:
if flag { if flag {
if err = s.writer.Write(s, outPkg); err != nil { if err = s.writer.Write(s, outPkg); err != nil {
log.Error("%s, [session.handleLoop] = error{%s}", s.sessionToken(), err) log.Error("%s, [session.handleLoop] = error{%s}", s.sessionToken(), jerrors.ErrorStack(err))
s.stop() s.stop()
flag = false flag = false
// break LOOP // break LOOP
...@@ -550,7 +550,7 @@ func (s *session) handlePackage() { ...@@ -550,7 +550,7 @@ func (s *session) handlePackage() {
log.Info("%s, [session.handlePackage] gr will exit now, left gr num %d", s.sessionToken(), grNum) log.Info("%s, [session.handlePackage] gr will exit now, left gr num %d", s.sessionToken(), grNum)
s.stop() s.stop()
if err != nil { if err != nil {
log.Error("%s, [session.handlePackage] error{%s}", s.sessionToken(), err) log.Error("%s, [session.handlePackage] error{%s}", s.sessionToken(), jerrors.ErrorStack(err))
s.listener.OnError(s, err) s.listener.OnError(s, err)
} }
}() }()
...@@ -628,7 +628,7 @@ func (s *session) handleTCPPackage() error { ...@@ -628,7 +628,7 @@ func (s *session) handleTCPPackage() error {
// pkg, err = s.pkgHandler.Read(s, pktBuf) // pkg, err = s.pkgHandler.Read(s, pktBuf)
pkg, pkgLen, err = s.reader.Read(s, pktBuf.Bytes()) pkg, pkgLen, err = s.reader.Read(s, pktBuf.Bytes())
if err == nil && s.maxMsgLen > 0 && pkgLen > int(s.maxMsgLen) { if err == nil && s.maxMsgLen > 0 && pkgLen > int(s.maxMsgLen) {
err = ErrMsgTooLong err = jerrors.Errorf("Message Too Long, pkgLen %d, session max message len %d", pkgLen, s.maxMsgLen)
} }
if err != nil { if err != nil {
log.Warn("%s, [session.handleTCPPackage] = len{%d}, error{%s}", log.Warn("%s, [session.handleTCPPackage] = len{%d}, error{%s}",
...@@ -703,7 +703,7 @@ func (s *session) handleUDPPackage() error { ...@@ -703,7 +703,7 @@ func (s *session) handleUDPPackage() error {
pkg, pkgLen, err = s.reader.Read(s, buf[:bufLen]) pkg, pkgLen, err = s.reader.Read(s, buf[:bufLen])
log.Debug("s.reader.Read() = pkg:%#v, pkgLen:%d, err:%s", pkg, pkgLen, jerrors.ErrorStack(err)) log.Debug("s.reader.Read() = pkg:%#v, pkgLen:%d, err:%s", pkg, pkgLen, jerrors.ErrorStack(err))
if err == nil && s.maxMsgLen > 0 && bufLen > int(s.maxMsgLen) { if err == nil && s.maxMsgLen > 0 && bufLen > int(s.maxMsgLen) {
err = ErrMsgTooLong err = jerrors.Errorf("Message Too Long, bufLen %d, session max message len %d", bufLen, s.maxMsgLen)
} }
if err != nil { if err != nil {
log.Warn("%s, [session.handleUDPPackage] = len{%d}, error{%s}", log.Warn("%s, [session.handleUDPPackage] = len{%d}, error{%s}",
...@@ -753,7 +753,7 @@ func (s *session) handleWSPackage() error { ...@@ -753,7 +753,7 @@ func (s *session) handleWSPackage() error {
if s.reader != nil { if s.reader != nil {
unmarshalPkg, length, err = s.reader.Read(s, pkg) unmarshalPkg, length, err = s.reader.Read(s, pkg)
if err == nil && s.maxMsgLen > 0 && length > int(s.maxMsgLen) { if err == nil && s.maxMsgLen > 0 && length > int(s.maxMsgLen) {
err = ErrMsgTooLong err = jerrors.Errorf("Message Too Long, length %d, session max message len %d", length, s.maxMsgLen)
} }
if err != nil { if err != nil {
log.Warn("%s, [session.handleWSPackage] = len{%d}, error{%s}", log.Warn("%s, [session.handleWSPackage] = len{%d}, error{%s}",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment