package protocol import ( "encoding/binary" "fmt" ) // protocol // 1byte: magic: 99 // 1byte: type 1 request, 2 response, 3 event notice, 4 error // 1byte: status: 20-OK, 30-CLIENT_TIMEOUT, 31-SERVER_TIMEOUT, 40-BAD_REQUEST, 41-BAD_RESPONSE, 44-SERVICE_NOT_FOUND, 50-CLIENT_ERROR, 51-SERVER_ERROR, 52-SERVICE_ERROR // 4bit: urlType svc,method url desc: 1 name, 2 number // 4bit: serializeType: 1proto, 2json // 4byte: seqId // 变长部分 ↓ // string: // urlType=1: service, method / 4byte svc, // urlType=2: 4byte SvcId + 4byte TargetId(when request methodId, when notice/response messageId) // proto bytes / json bytes const ( Magic byte = 99 TypeRequest byte = 1 TypeResponse byte = 2 TypeNotice byte = 3 TypeError byte = 4 ) type Header struct { Magic byte Type byte // 1 request, 2 response, 3 event, 4 error Status byte UrlType byte // 4bit: svc,method url: 1 name, 2 number SerializeType byte // 4bit: body serialize: 1proto, 2json SeqId int32 SvcNo int32 // optional 1 TargetNo int32 // optional 2 Svc string // optional 1 Target string // optional 2 method/message } type Payload struct { Header *Header Body []byte } func DecodeSo(bytes []byte) (payload *Payload, err error) { header := &Header{} payload = &Payload{Header: header} header.Magic = bytes[0] if header.Magic != Magic { err = fmt.Errorf("unknown magic: %d", header.Magic) return } header.Type = bytes[1] header.Status = bytes[2] header.UrlType = bytes[3] >> 4 header.SerializeType = bytes[3] & 0xF header.SeqId = int32(binary.BigEndian.Uint32(bytes[4:8])) // error message if header.Type == TypeError { body := bytes[8:] payload.Body = make([]byte, len(body)) copy(payload.Body, body) return } var cursor int switch header.UrlType { case 1: svcLen := int(binary.BigEndian.Uint32(bytes[8:12])) header.Svc = string(bytes[12 : 12+svcLen]) cursor = 12 + svcLen targetLen := int(binary.BigEndian.Uint32(bytes[cursor : cursor+4])) header.Target = string(bytes[cursor+4 : cursor+4+targetLen]) cursor = cursor + 4 + targetLen case 2: header.SvcNo = int32(binary.BigEndian.Uint32(bytes[8:12])) header.TargetNo = int32(binary.BigEndian.Uint32(bytes[12:16])) cursor = 16 default: err = fmt.Errorf("unknown url type: %d", header.UrlType) return } body := bytes[cursor:] payload.Body = make([]byte, len(body)) copy(payload.Body, body) return } func EncodeSo(payload *Payload) (bytes []byte, err error) { header := payload.Header headerLen, bodyLen := 8, 0 var svc, target []byte var svcLen, targetLen int // 定位符为字符串,计算占用长度 if header.Type != TypeError { // error头只8字节 headerLen += 8 if header.UrlType == 1 { svc = []byte(header.Svc) target = []byte(header.Target) svcLen = len(svc) targetLen = len(target) headerLen += svcLen + targetLen } } bodyLen = len(payload.Body) bytes = make([]byte, headerLen+bodyLen) bytes[0] = header.Magic bytes[1] = header.Type bytes[2] = header.Status bytes[3] = (header.UrlType << 4) | header.SerializeType binary.BigEndian.PutUint32(bytes[4:8], uint32(header.SeqId)) if header.Type == TypeError { if bodyLen > 0 { copy(bytes[8:], payload.Body) } return } var cursor int switch header.UrlType { case 1: binary.BigEndian.PutUint32(bytes[8:12], uint32(svcLen)) copy(bytes[12:12+svcLen], svc) cursor = 12 + svcLen binary.BigEndian.PutUint32(bytes[cursor:cursor+4], uint32(targetLen)) copy(bytes[cursor+4:cursor+4+targetLen], target) cursor = cursor + 4 + targetLen case 2: binary.BigEndian.PutUint32(bytes[8:12], uint32(header.SvcNo)) binary.BigEndian.PutUint32(bytes[12:16], uint32(header.TargetNo)) cursor = 16 default: err = fmt.Errorf("unknown url type: %d", header.UrlType) } if bodyLen > 0 { copy(bytes[cursor:], payload.Body) } return }