136 lines
3.3 KiB
Go
136 lines
3.3 KiB
Go
package rpc
|
|
|
|
import "lux/proto"
|
|
|
|
// FSM to handle TCP-window split XML packets
|
|
const LUX_XML_REQUEST_BEGIN = "<request"
|
|
const LUX_XML_REQUEST_END = "</request>"
|
|
const LUX_XML_RESPONSE_BEGIN = "<response"
|
|
const LUX_XML_RESPONSE_END = "</response>"
|
|
const LUX_XML_ERROR_BEGIN = "<error"
|
|
const LUX_XML_ERROR_END = "</error>"
|
|
|
|
type LuxRpcDefragState int
|
|
|
|
const (
|
|
LuxRpcDefragStateOff = 0
|
|
|
|
LuxRpcDefragStateReading = 1
|
|
LuxRpcDefragStateReadingRequest = 1
|
|
LuxRpcDefragStateReadingResponse = 2
|
|
LuxRpcDefragStateReadingError = 3
|
|
|
|
LuxRpcDefragStateHasData = 4
|
|
LuxRpcDefragStateHasRequest = 4
|
|
LuxRpcDefragStateHasResponse = 5
|
|
LuxRpcDefragStateHasError = 6
|
|
)
|
|
|
|
type LuxRpcDefrag struct {
|
|
buffer proto.LuxBuffer
|
|
state LuxRpcDefragState
|
|
beginOff int
|
|
endOff int
|
|
}
|
|
|
|
func NewLuxRpcDefrag() LuxRpcDefrag {
|
|
return LuxRpcDefrag{
|
|
buffer: proto.NewLuxBuffer(),
|
|
state: LuxRpcDefragStateOff,
|
|
beginOff: 0,
|
|
endOff: 0,
|
|
}
|
|
}
|
|
|
|
func (def *LuxRpcDefrag) HasRequest() bool {
|
|
return def.state == LuxRpcDefragStateHasRequest
|
|
}
|
|
|
|
func (def *LuxRpcDefrag) HasResponse() bool {
|
|
return def.state == LuxRpcDefragStateHasResponse
|
|
}
|
|
|
|
func (def *LuxRpcDefrag) HasError() bool {
|
|
return def.state == LuxRpcDefragStateHasError
|
|
}
|
|
|
|
func matchTag(slice []byte, tag string) bool {
|
|
tagLen := len(tag)
|
|
if len(slice) >= tagLen {
|
|
return string(slice[:tagLen]) == tag
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// will return true if data is complete
|
|
func (def *LuxRpcDefrag) Feed(data []byte) bool {
|
|
// try find tag opening at beginning
|
|
if def.state == LuxRpcDefragStateOff {
|
|
for i := 0; i < len(data); i++ {
|
|
slice := data[i:]
|
|
|
|
if matchTag(slice, LUX_XML_REQUEST_BEGIN) {
|
|
def.state = LuxRpcDefragStateReadingRequest
|
|
def.beginOff = i + len(LUX_XML_REQUEST_BEGIN)
|
|
break
|
|
} else if matchTag(slice, LUX_XML_RESPONSE_BEGIN) {
|
|
def.state = LuxRpcDefragStateReadingResponse
|
|
def.beginOff = i + len(LUX_XML_RESPONSE_BEGIN)
|
|
break
|
|
} else if matchTag(slice, LUX_XML_ERROR_BEGIN) {
|
|
def.state = LuxRpcDefragStateReadingError
|
|
def.beginOff = i + len(LUX_XML_ERROR_BEGIN)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// now check if slice has ending tag, if so - complete data
|
|
if def.state >= LuxRpcDefragStateReading {
|
|
for i := def.beginOff; i < len(data); i++ {
|
|
slice := data[i:]
|
|
|
|
if matchTag(slice, LUX_XML_REQUEST_END) {
|
|
def.state = LuxRpcDefragStateHasRequest
|
|
def.endOff = i + len(LUX_XML_REQUEST_END)
|
|
break
|
|
} else if matchTag(slice, LUX_XML_RESPONSE_END) {
|
|
def.state = LuxRpcDefragStateHasResponse
|
|
def.endOff = i + len(LUX_XML_RESPONSE_END)
|
|
break
|
|
} else if matchTag(slice, LUX_XML_ERROR_END) {
|
|
def.state = LuxRpcDefragStateHasError
|
|
def.endOff = i + len(LUX_XML_ERROR_END)
|
|
break
|
|
}
|
|
}
|
|
|
|
// got end tag? push exact 0:endOff slice
|
|
if def.state >= LuxRpcDefragStateHasData {
|
|
def.buffer.WriteBytes(data[:def.endOff])
|
|
|
|
return true // we got complete data!
|
|
} else {
|
|
// if there is no end tag, then reset beginOff so it wont
|
|
// confuse next Feed call
|
|
def.beginOff = 0
|
|
}
|
|
}
|
|
|
|
// push whatever data is
|
|
def.buffer.WriteBytes(data)
|
|
return false
|
|
}
|
|
|
|
func (def *LuxRpcDefrag) GetAndForget() []byte {
|
|
data := def.buffer.AllBytes()
|
|
|
|
// reset state
|
|
def.buffer = proto.NewLuxBuffer()
|
|
def.state = LuxRpcDefragStateOff
|
|
def.beginOff = 0
|
|
def.endOff = 0
|
|
|
|
return data
|
|
}
|