You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
135 lines
3.5 KiB
135 lines
3.5 KiB
package protocol |
|
|
|
import ( |
|
"encoding/binary" |
|
"fmt" |
|
) |
|
|
|
// protocol |
|
// 1byte: magic: 99 |
|
// 1byte: type 1 request, 2 response, 3 event, 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: service, method / 4byte svc, 4byte method/4byte notice |
|
// 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 desc: 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{} |
|
|
|
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 { |
|
payload.Body = bytes[8:] |
|
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 |
|
} |
|
|
|
payload = &Payload{Header: header} |
|
payload.Body = bytes[cursor:] |
|
return |
|
} |
|
|
|
func EncodeSo(payload *Payload) (bytes []byte, err error) { |
|
header := payload.Header |
|
headerLen := 16 |
|
var svc, target []byte |
|
var svcLen, targetLen, bodyLen int |
|
// 定位符为字符串 |
|
if header.Type != TypeError && 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 |
|
}
|
|
|