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

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
}