gearman-go/client/response.go

133 lines
3.0 KiB
Go
Raw Normal View History

2013-08-29 16:51:23 +08:00
package client
import (
2013-08-30 11:20:51 +08:00
"bytes"
"encoding/binary"
2013-08-30 12:36:57 +08:00
"fmt"
"strconv"
2013-08-29 16:51:23 +08:00
)
2013-08-30 12:36:57 +08:00
// Response handler
type ResponseHandler func(*Response)
2013-08-29 16:51:23 +08:00
// response
2013-08-29 18:08:05 +08:00
type Response struct {
2013-08-30 12:36:57 +08:00
DataType uint32
Data, UID []byte
Handle string
2013-08-29 16:51:23 +08:00
}
// Extract the Response's result.
// if data == nil, err != nil, then worker failing to execute job
// if data != nil, err != nil, then worker has a exception
// if data != nil, err == nil, then worker complate job
// after calling this method, the Response.Handle will be filled
2013-08-29 18:08:05 +08:00
func (resp *Response) Result() (data []byte, err error) {
2013-08-29 16:51:23 +08:00
switch resp.DataType {
case dtWorkFail:
2013-08-29 18:08:05 +08:00
resp.Handle = string(resp.Data)
2013-08-29 16:51:23 +08:00
err = ErrWorkFail
return
case dtWorkException:
2013-08-29 16:51:23 +08:00
err = ErrWorkException
fallthrough
case dtWorkComplete:
2013-08-29 16:51:23 +08:00
s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
if len(s) != 2 {
err = fmt.Errorf("Invalid data: %V", resp.Data)
return
}
2013-08-29 18:08:05 +08:00
resp.Handle = string(s[0])
2013-08-29 16:51:23 +08:00
data = s[1]
default:
err = ErrDataType
}
return
}
// Extract the job's update
2013-08-29 18:08:05 +08:00
func (resp *Response) Update() (data []byte, err error) {
if resp.DataType != dtWorkData &&
resp.DataType != dtWorkWarning {
2013-08-29 16:51:23 +08:00
err = ErrDataType
return
}
s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
if len(s) != 2 {
err = ErrInvalidData
return
}
if resp.DataType == dtWorkWarning {
2013-08-29 16:51:23 +08:00
err = ErrWorkWarning
}
2013-08-29 18:08:05 +08:00
resp.Handle = string(s[0])
2013-08-29 16:51:23 +08:00
data = s[1]
return
}
// Decode a job from byte slice
2013-08-29 18:08:05 +08:00
func decodeResponse(data []byte) (resp *Response, l int, err error) {
if len(data) < minPacketLength { // valid package should not less 12 bytes
2013-08-29 16:51:23 +08:00
err = fmt.Errorf("Invalid data: %V", data)
return
}
dl := int(binary.BigEndian.Uint32(data[8:12]))
dt := data[minPacketLength : dl+minPacketLength]
2013-08-29 16:51:23 +08:00
if len(dt) != int(dl) { // length not equal
err = fmt.Errorf("Invalid data: %V", data)
return
}
resp = getResponse()
resp.DataType = binary.BigEndian.Uint32(data[4:8])
switch resp.DataType {
case dtJobCreated:
2013-08-30 11:20:51 +08:00
resp.Handle = string(dt)
case dtStatusRes, dtWorkData, dtWorkWarning, dtWorkStatus,
dtWorkComplete, dtWorkFail, dtWorkException:
2013-08-29 18:08:05 +08:00
s := bytes.SplitN(dt, []byte{'\x00'}, 2)
2013-08-29 16:51:23 +08:00
if len(s) >= 2 {
2013-08-29 18:08:05 +08:00
resp.Handle = string(s[0])
2013-08-29 16:51:23 +08:00
resp.Data = s[1]
} else {
err = fmt.Errorf("Invalid data: %V", data)
return
}
case dtEchoRes:
2013-08-30 11:20:51 +08:00
fallthrough
default:
resp.Data = dt
2013-08-29 16:51:23 +08:00
}
l = dl + minPacketLength
2013-08-29 16:51:23 +08:00
return
}
// status handler
2013-08-29 18:08:05 +08:00
func (resp *Response) Status() (status *Status, err error) {
2013-08-30 11:20:51 +08:00
data := bytes.SplitN(resp.Data, []byte{'\x00'}, 4)
if len(data) != 4 {
2013-08-29 16:51:23 +08:00
err = fmt.Errorf("Invalid data: %V", resp.Data)
return
}
status = &Status{}
2013-08-30 11:20:51 +08:00
status.Handle = resp.Handle
status.Known = (data[0][0] == '1')
status.Running = (data[1][0] == '1')
status.Numerator, err = strconv.ParseUint(string(data[2]), 10, 0)
2013-08-29 16:51:23 +08:00
if err != nil {
2013-08-30 11:20:51 +08:00
err = fmt.Errorf("Invalid Integer: %s", data[2])
2013-08-29 16:51:23 +08:00
return
}
2013-08-30 11:20:51 +08:00
status.Denominator, err = strconv.ParseUint(string(data[3]), 10, 0)
2013-08-29 16:51:23 +08:00
if err != nil {
2013-08-30 11:20:51 +08:00
err = fmt.Errorf("Invalid Integer: %s", data[3])
2013-08-29 16:51:23 +08:00
return
}
return
}
2013-08-29 18:08:05 +08:00
func getResponse() (resp *Response) {
2013-08-29 16:51:23 +08:00
// TODO add a pool
2013-08-29 18:08:05 +08:00
resp = &Response{}
2013-08-29 16:51:23 +08:00
return
}