// Copyright 2011 Xing Xing . // 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 }