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 {
|
2013-12-26 15:28:42 +08:00
|
|
|
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
|
2013-12-26 15:28:42 +08:00
|
|
|
case dtWorkException:
|
2013-08-29 16:51:23 +08:00
|
|
|
err = ErrWorkException
|
|
|
|
fallthrough
|
2013-12-26 15:28:42 +08:00
|
|
|
case dtWorkComplete:
|
2014-01-09 16:16:34 +08:00
|
|
|
data = resp.Data
|
2013-08-29 16:51:23 +08:00
|
|
|
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) {
|
2013-12-26 15:28:42 +08:00
|
|
|
if resp.DataType != dtWorkData &&
|
|
|
|
resp.DataType != dtWorkWarning {
|
2013-08-29 16:51:23 +08:00
|
|
|
err = ErrDataType
|
|
|
|
return
|
|
|
|
}
|
2014-01-09 16:16:34 +08:00
|
|
|
data = resp.Data
|
2013-12-26 15:28:42 +08:00
|
|
|
if resp.DataType == dtWorkWarning {
|
2013-08-29 16:51:23 +08:00
|
|
|
err = ErrWorkWarning
|
|
|
|
}
|
|
|
|
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) {
|
2014-01-09 16:16:34 +08:00
|
|
|
a := len(data)
|
|
|
|
if a < minPacketLength { // valid package should not less 12 bytes
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", data)
|
2013-08-29 16:51:23 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
dl := int(binary.BigEndian.Uint32(data[8:12]))
|
2014-01-09 17:58:02 +08:00
|
|
|
if a < minPacketLength+dl {
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", data)
|
2014-01-09 16:16:34 +08:00
|
|
|
return
|
|
|
|
}
|
2013-12-26 15:28:42 +08:00
|
|
|
dt := data[minPacketLength : dl+minPacketLength]
|
2013-08-29 16:51:23 +08:00
|
|
|
if len(dt) != int(dl) { // length not equal
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", data)
|
2013-08-29 16:51:23 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
resp = getResponse()
|
|
|
|
resp.DataType = binary.BigEndian.Uint32(data[4:8])
|
|
|
|
switch resp.DataType {
|
2013-12-26 15:28:42 +08:00
|
|
|
case dtJobCreated:
|
2013-08-30 11:20:51 +08:00
|
|
|
resp.Handle = string(dt)
|
2013-12-26 15:28:42 +08:00
|
|
|
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 {
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", data)
|
2013-08-29 16:51:23 +08:00
|
|
|
return
|
|
|
|
}
|
2013-12-26 15:28:42 +08:00
|
|
|
case dtEchoRes:
|
2013-08-30 11:20:51 +08:00
|
|
|
fallthrough
|
|
|
|
default:
|
|
|
|
resp.Data = dt
|
2013-08-29 16:51:23 +08:00
|
|
|
}
|
2013-12-26 15:28:42 +08:00
|
|
|
l = dl + minPacketLength
|
2013-08-29 16:51:23 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-08-29 18:08:05 +08:00
|
|
|
func (resp *Response) Status() (status *Status, err error) {
|
2014-01-09 16:16:34 +08:00
|
|
|
data := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
|
|
|
|
if len(data) != 2 {
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", resp.Data)
|
2014-01-09 16:16:34 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
status = &Status{}
|
|
|
|
status.Handle = resp.Handle
|
|
|
|
status.Known = true
|
|
|
|
status.Running = true
|
|
|
|
status.Numerator, err = strconv.ParseUint(string(data[0]), 10, 0)
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("Invalid Integer: %s", data[0])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
status.Denominator, err = strconv.ParseUint(string(data[1]), 10, 0)
|
|
|
|
if err != nil {
|
|
|
|
err = fmt.Errorf("Invalid Integer: %s", data[1])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// status handler
|
|
|
|
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 {
|
2014-03-07 17:21:45 +08:00
|
|
|
err = fmt.Errorf("Invalid data: %v", resp.Data)
|
2013-08-29 16:51:23 +08:00
|
|
|
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
|
|
|
|
}
|