143 lines
3.6 KiB
Go
143 lines
3.6 KiB
Go
// Copyright 2011 Xing Xing <mikespook@gmail.com>.
|
|
// All rights reserved.
|
|
// Use of this source code is governed by a MIT
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package client
|
|
|
|
import (
|
|
"bytes"
|
|
"github.com/mikespook/gearman-go/common"
|
|
)
|
|
|
|
const (
|
|
// Job type
|
|
// JOB_NORMAL | JOB_BG means a normal level job run in background
|
|
// normal level
|
|
JOB_NORMAL = 0
|
|
// background job
|
|
JOB_BG = 1
|
|
// low level
|
|
JOB_LOW = 2
|
|
// high level
|
|
JOB_HIGH = 4
|
|
)
|
|
|
|
// An error handler
|
|
type ErrorHandler func(error)
|
|
|
|
// Client side job
|
|
type Job struct {
|
|
Data []byte
|
|
Handle, UniqueId string
|
|
magicCode, DataType uint32
|
|
}
|
|
|
|
// Create a new job
|
|
func newJob(magiccode, datatype uint32, data []byte) (job *Job) {
|
|
return &Job{magicCode: magiccode,
|
|
DataType: datatype,
|
|
Data: data}
|
|
}
|
|
|
|
// Decode a job from byte slice
|
|
func decodeJob(data []byte) (job *Job, err error) {
|
|
if len(data) < 12 {
|
|
return nil, common.Errorf("Invalid data: %V", data)
|
|
}
|
|
datatype := common.BytesToUint32([4]byte{data[4], data[5], data[6], data[7]})
|
|
l := common.BytesToUint32([4]byte{data[8], data[9], data[10], data[11]})
|
|
if len(data[12:]) != int(l) {
|
|
return nil, common.Errorf("Invalid data: %V", data)
|
|
}
|
|
data = data[12:]
|
|
var handle string
|
|
switch datatype {
|
|
case common.WORK_DATA, common.WORK_WARNING, common.WORK_STATUS,
|
|
common.WORK_COMPLETE, common.WORK_FAIL, common.WORK_EXCEPTION:
|
|
i := bytes.IndexByte(data, '\x00')
|
|
if i != -1 {
|
|
handle = string(data[:i])
|
|
data = data[i + 1:]
|
|
}
|
|
}
|
|
|
|
return &Job{magicCode: common.RES,
|
|
DataType: datatype,
|
|
Data: data,
|
|
Handle: handle}, nil
|
|
}
|
|
|
|
// Encode a job to byte slice
|
|
func (job *Job) Encode() (data []byte) {
|
|
l := len(job.Data)
|
|
tl := l + 12
|
|
data = make([]byte, tl)
|
|
|
|
magiccode := common.Uint32ToBytes(job.magicCode)
|
|
datatype := common.Uint32ToBytes(job.DataType)
|
|
datalength := common.Uint32ToBytes(uint32(l))
|
|
|
|
for i := 0; i < tl; i ++ {
|
|
switch {
|
|
case i < 4:
|
|
data[i] = magiccode[i]
|
|
case i < 8:
|
|
data[i] = datatype[i - 4]
|
|
case i < 12:
|
|
data[i] = datalength[i - 8]
|
|
default:
|
|
data[i] = job.Data[i - 12]
|
|
}
|
|
}
|
|
// Alternative
|
|
/*
|
|
data = append(data, magiccode[:] ...)
|
|
data = append(data, datatype[:] ...)
|
|
data = append(data, datalength[:] ...)
|
|
data = append(data, job.Data ...)
|
|
*/
|
|
return
|
|
}
|
|
|
|
// Extract the job's result.
|
|
func (job *Job) Result() (data []byte, err error) {
|
|
switch job.DataType {
|
|
case common.WORK_FAIL:
|
|
job.Handle = string(job.Data)
|
|
return nil, common.ErrWorkFail
|
|
case common.WORK_EXCEPTION:
|
|
err = common.ErrWorkException
|
|
fallthrough
|
|
case common.WORK_COMPLETE:
|
|
s := bytes.SplitN(job.Data, []byte{'\x00'}, 2)
|
|
if len(s) != 2 {
|
|
return nil, common.Errorf("Invalid data: %V", job.Data)
|
|
}
|
|
job.Handle = string(s[0])
|
|
data = s[1]
|
|
default:
|
|
err = common.ErrDataType
|
|
}
|
|
return
|
|
}
|
|
|
|
// Extract the job's update
|
|
func (job *Job) Update() (data []byte, err error) {
|
|
if job.DataType != common.WORK_DATA && job.DataType != common.WORK_WARNING {
|
|
err = common.ErrDataType
|
|
return
|
|
}
|
|
s := bytes.SplitN(job.Data, []byte{'\x00'}, 2)
|
|
if len(s) != 2 {
|
|
err = common.ErrInvalidData
|
|
return
|
|
}
|
|
if job.DataType == common.WORK_WARNING {
|
|
err = common.ErrWorkWarning
|
|
}
|
|
job.Handle = string(s[0])
|
|
data = s[1]
|
|
return
|
|
}
|