2011-03-15 20:21:42 +08:00
|
|
|
package gearman
|
|
|
|
|
2011-05-19 20:10:53 +08:00
|
|
|
import (
|
|
|
|
"os"
|
|
|
|
"net"
|
2011-05-20 17:38:10 +08:00
|
|
|
"sync"
|
2011-05-21 12:32:44 +08:00
|
|
|
"log"
|
|
|
|
"strconv"
|
2011-05-19 20:10:53 +08:00
|
|
|
)
|
2011-03-15 20:21:42 +08:00
|
|
|
|
2011-05-19 20:10:53 +08:00
|
|
|
type Client struct {
|
2011-05-20 17:38:10 +08:00
|
|
|
mutex sync.Mutex
|
2011-05-19 20:10:53 +08:00
|
|
|
conn net.Conn
|
|
|
|
JobQueue chan *ClientJob
|
2011-05-21 12:32:44 +08:00
|
|
|
incoming chan []byte
|
2011-05-20 17:38:10 +08:00
|
|
|
UId uint32
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewClient() (client * Client){
|
2011-05-20 17:38:10 +08:00
|
|
|
client = &Client{JobQueue:make(chan *ClientJob, QUEUE_CAP),
|
2011-05-21 12:32:44 +08:00
|
|
|
incoming:make(chan []byte, QUEUE_CAP),
|
2011-05-20 17:38:10 +08:00
|
|
|
UId:1}
|
2011-05-19 20:10:53 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) AddServer(addr string) (err os.Error) {
|
|
|
|
conn, err := net.Dial(TCP, addr)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
client.conn = conn
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-05-21 12:32:44 +08:00
|
|
|
func (client *Client) read() (data []byte, err os.Error) {
|
2011-05-20 17:38:10 +08:00
|
|
|
var rel []byte
|
|
|
|
for {
|
|
|
|
buf := make([]byte, BUFFER_SIZE)
|
|
|
|
var n int
|
|
|
|
if n, err = client.conn.Read(buf); err != nil {
|
|
|
|
if (err == os.EOF && n == 0) {
|
|
|
|
break
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
return
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
rel = append(rel, buf[0: n] ...)
|
|
|
|
if n < BUFFER_SIZE {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2011-05-21 12:32:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) ReadJob() (job *ClientJob, err os.Error) {
|
|
|
|
var rel []byte
|
|
|
|
if rel, err = client.read(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
if job, err = DecodeClientJob(rel); err != nil {
|
|
|
|
return
|
|
|
|
} else {
|
2011-05-21 12:32:44 +08:00
|
|
|
switch(job.DataType) {
|
2011-05-20 17:38:10 +08:00
|
|
|
case ERROR:
|
|
|
|
_, err = getError(job.Data)
|
|
|
|
return
|
|
|
|
case WORK_DATA, WORK_WARNING, WORK_STATUS, WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
|
|
|
|
client.JobQueue <- job
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
return
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-20 17:38:10 +08:00
|
|
|
func (client *Client) Do(funcname string, data []byte, flag byte) (handle string, err os.Error) {
|
2011-05-19 23:29:34 +08:00
|
|
|
var datatype uint32
|
2011-05-20 17:38:10 +08:00
|
|
|
if flag & JOB_LOW == JOB_LOW {
|
2011-05-19 23:29:34 +08:00
|
|
|
if flag & JOB_BG == JOB_BG {
|
|
|
|
datatype = SUBMIT_JOB_LOW_BG
|
|
|
|
} else {
|
|
|
|
datatype = SUBMIT_JOB_LOW
|
|
|
|
}
|
|
|
|
} else if flag & JOB_HIGH == JOB_HIGH {
|
|
|
|
if flag & JOB_BG == JOB_BG {
|
|
|
|
datatype = SUBMIT_JOB_HIGH_BG
|
|
|
|
} else {
|
|
|
|
datatype = SUBMIT_JOB_HIGH
|
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
} else if flag & JOB_BG == JOB_BG {
|
|
|
|
datatype = SUBMIT_JOB_BG
|
|
|
|
} else {
|
|
|
|
datatype = SUBMIT_JOB
|
2011-05-19 23:29:34 +08:00
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
|
2011-05-19 23:29:34 +08:00
|
|
|
rel := make([]byte, 0, 1024 * 64)
|
|
|
|
rel = append(rel, []byte(funcname) ...)
|
|
|
|
rel = append(rel, '\x00')
|
2011-05-20 17:38:10 +08:00
|
|
|
client.mutex.Lock()
|
2011-05-21 12:32:44 +08:00
|
|
|
uid := strconv.Itoa(int(client.UId))
|
2011-05-20 17:38:10 +08:00
|
|
|
client.UId ++
|
2011-05-21 12:32:44 +08:00
|
|
|
rel = append(rel, []byte(uid) ...)
|
2011-05-20 17:38:10 +08:00
|
|
|
client.mutex.Unlock()
|
2011-05-19 23:29:34 +08:00
|
|
|
rel = append(rel, '\x00')
|
|
|
|
rel = append(rel, data ...)
|
2011-05-20 17:38:10 +08:00
|
|
|
if err = client.WriteJob(NewClientJob(REQ, datatype, rel)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var job *ClientJob
|
2011-05-21 12:32:44 +08:00
|
|
|
if job, err = client.readLastJob(JOB_CREATED); err != nil {
|
2011-05-20 17:38:10 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
handle = string(job.Data)
|
2011-05-21 12:32:44 +08:00
|
|
|
log.Println(handle)
|
2011-05-20 17:38:10 +08:00
|
|
|
go func() {
|
|
|
|
if flag & JOB_BG != JOB_BG {
|
|
|
|
for {
|
|
|
|
if job, err = client.ReadJob(); err != nil {
|
|
|
|
return
|
|
|
|
}
|
2011-05-21 12:32:44 +08:00
|
|
|
switch job.DataType {
|
2011-05-20 17:38:10 +08:00
|
|
|
case WORK_DATA, WORK_WARNING:
|
|
|
|
case WORK_STATUS:
|
|
|
|
case WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-21 12:32:44 +08:00
|
|
|
func (client *Client) readLastJob(datatype uint32) (job *ClientJob, err os.Error){
|
2011-05-20 17:38:10 +08:00
|
|
|
for {
|
|
|
|
if job, err = client.ReadJob(); err != nil {
|
2011-05-19 20:10:53 +08:00
|
|
|
return
|
|
|
|
}
|
2011-05-21 12:32:44 +08:00
|
|
|
if job.DataType == datatype {
|
2011-05-20 17:38:10 +08:00
|
|
|
break
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
2011-05-21 12:32:44 +08:00
|
|
|
if job.DataType != datatype {
|
2011-05-20 17:38:10 +08:00
|
|
|
err = os.NewError("No job got.")
|
|
|
|
}
|
|
|
|
return
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-20 17:38:10 +08:00
|
|
|
func (client *Client) Status(handle string) (known, running bool, numerator, denominator uint, err os.Error) {
|
|
|
|
|
|
|
|
if err = client.WriteJob(NewClientJob(REQ, GET_STATUS, []byte(handle))); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var job * ClientJob
|
2011-05-21 12:32:44 +08:00
|
|
|
if job, err = client.readLastJob(STATUS_RES); err != nil {
|
2011-05-20 17:38:10 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
data := splitByteArray(job.Data, '\x00')
|
|
|
|
if len(data) != 5 {
|
|
|
|
err = os.NewError("Data Error.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if handle != string(data[0]) {
|
|
|
|
err = os.NewError("Invalid handle.")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
known = data[1][0] == '1'
|
|
|
|
running = data[2][0] == '1'
|
|
|
|
numerator = uint(data[3][0])
|
|
|
|
denominator = uint(data[4][0])
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) Echo(data []byte) (echo []byte, err os.Error) {
|
|
|
|
if err = client.WriteJob(NewClientJob(REQ, ECHO_REQ, data)); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
var job *ClientJob
|
2011-05-21 12:32:44 +08:00
|
|
|
if job, err = client.readLastJob(ECHO_RES); err != nil {
|
2011-05-20 17:38:10 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
return job.Data, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) LastResult() (job *ClientJob) {
|
|
|
|
if l := len(client.JobQueue); l != 1 {
|
2011-05-19 20:10:53 +08:00
|
|
|
if l == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for i := 0; i < l - 1; i ++ {
|
2011-05-20 17:38:10 +08:00
|
|
|
<-client.JobQueue
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
}
|
2011-05-20 17:38:10 +08:00
|
|
|
return <-client.JobQueue
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) WriteJob(job *ClientJob) (err os.Error) {
|
2011-05-21 12:32:44 +08:00
|
|
|
return client.write(job.Encode())
|
2011-05-19 20:10:53 +08:00
|
|
|
}
|
|
|
|
|
2011-05-21 12:32:44 +08:00
|
|
|
func (client *Client) write(buf []byte) (err os.Error) {
|
2011-05-19 20:10:53 +08:00
|
|
|
var n int
|
|
|
|
for i := 0; i < len(buf); i += n {
|
|
|
|
n, err = client.conn.Write(buf[i:])
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (client *Client) Close() (err os.Error) {
|
|
|
|
err = client.conn.Close()
|
|
|
|
close(client.JobQueue)
|
|
|
|
return
|
|
|
|
}
|