forked from yuxh/gearman-go
		
	The client can work now...with some known bugs. :(
This commit is contained in:
		
							parent
							
								
									c5b9f19962
								
							
						
					
					
						commit
						016dd669aa
					
				@ -9,7 +9,7 @@ TARG=gearman
 | 
			
		||||
# GOFILES=\
 | 
			
		||||
#	worker.go\
 | 
			
		||||
 | 
			
		||||
CLEANFILES+= worker
 | 
			
		||||
CLEANFILES+= worker client
 | 
			
		||||
 | 
			
		||||
include $(GOROOT)/src/Make.pkg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										40
									
								
								example/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								example/client.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    "gearman"
 | 
			
		||||
    "log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
    client := gearman.NewClient()
 | 
			
		||||
    defer client.Close()
 | 
			
		||||
    client.AddServer("127.0.0.1:4730")
 | 
			
		||||
    echo := []byte("Hello world")
 | 
			
		||||
    log.Println(echo)
 | 
			
		||||
    log.Println(client.Echo(echo))
 | 
			
		||||
 | 
			
		||||
    handle, err := client.Do("ToUpper", echo, gearman.JOB_HIGH)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Println(err)
 | 
			
		||||
    }
 | 
			
		||||
    known, running, numerator, denominator, err := client.Status(handle)
 | 
			
		||||
    if err != nil {
 | 
			
		||||
        log.Println(err)
 | 
			
		||||
    }
 | 
			
		||||
    if !known {
 | 
			
		||||
        log.Println("Unknown")
 | 
			
		||||
    }
 | 
			
		||||
    if running {
 | 
			
		||||
        log.Printf("%g%%\n", float32(numerator) * 100 / float32(denominator))
 | 
			
		||||
    } else {
 | 
			
		||||
        log.Println("Not running")
 | 
			
		||||
    }
 | 
			
		||||
    log.Println("read")
 | 
			
		||||
    if job, err := client.ReadJob(); err != nil {
 | 
			
		||||
        log.Println(err)
 | 
			
		||||
    } else {
 | 
			
		||||
        data, err := job.Result(); 
 | 
			
		||||
        log.Println(err)
 | 
			
		||||
        log.Println(data)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,20 +3,19 @@ package gearman
 | 
			
		||||
import (
 | 
			
		||||
    "os"
 | 
			
		||||
    "net"
 | 
			
		||||
//    "log"
 | 
			
		||||
    "sync"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Client struct {
 | 
			
		||||
    mutex sync.Mutex
 | 
			
		||||
    conn net.Conn
 | 
			
		||||
    running bool
 | 
			
		||||
    JobQueue chan *ClientJob
 | 
			
		||||
    ErrQueue chan os.Error
 | 
			
		||||
    UId uint32
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewClient() (client * Client){
 | 
			
		||||
    client = &Client{running:false,
 | 
			
		||||
        JobQueue:make(chan *ClientJob, QUEUE_CAP),
 | 
			
		||||
        ErrQueue:make(chan os.Error, QUEUE_CAP),}
 | 
			
		||||
    client = &Client{JobQueue:make(chan *ClientJob, QUEUE_CAP),
 | 
			
		||||
        UId:1}
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,49 +25,42 @@ func (client *Client) AddServer(addr string) (err os.Error) {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    client.conn = conn
 | 
			
		||||
    go client.work()
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) work() {
 | 
			
		||||
    OUT: for client.running {
 | 
			
		||||
        var rel []byte
 | 
			
		||||
        for {
 | 
			
		||||
            buf := make([]byte, 2048)
 | 
			
		||||
            n, err := client.conn.Read(buf)
 | 
			
		||||
            if err != nil {
 | 
			
		||||
                if err == os.EOF && n == 0 {
 | 
			
		||||
                    break
 | 
			
		||||
                }
 | 
			
		||||
                client.ErrQueue <- err
 | 
			
		||||
                continue OUT
 | 
			
		||||
func (client *Client) ReadJob() (job *ClientJob, err os.Error) {
 | 
			
		||||
    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
 | 
			
		||||
            }
 | 
			
		||||
            rel = append(rel, buf[0: n] ...)
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        job, err := DecodeClientJob(rel)
 | 
			
		||||
        if err != nil {
 | 
			
		||||
            client.ErrQueue <- err
 | 
			
		||||
        } else {
 | 
			
		||||
            switch(job.dataType) {
 | 
			
		||||
                case ERROR:
 | 
			
		||||
                    _, err := getError(job.Data)
 | 
			
		||||
                    client.ErrQueue <- err
 | 
			
		||||
                case ECHO_RES:
 | 
			
		||||
                    client.JobQueue <- job
 | 
			
		||||
            }
 | 
			
		||||
        rel = append(rel, buf[0: n] ...)
 | 
			
		||||
        if n < BUFFER_SIZE {
 | 
			
		||||
            break
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if job, err = DecodeClientJob(rel); err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    } else {
 | 
			
		||||
        switch(job.dataType) {
 | 
			
		||||
            case ERROR:
 | 
			
		||||
                _, err = getError(job.Data)
 | 
			
		||||
                return
 | 
			
		||||
            case WORK_DATA, WORK_WARNING, WORK_STATUS, WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
 | 
			
		||||
                client.JobQueue <- job
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) Do(funcname string, data []byte, flag byte) (err os.Error) {
 | 
			
		||||
func (client *Client) Do(funcname string, data []byte, flag byte) (handle string, err os.Error) {
 | 
			
		||||
    var datatype uint32
 | 
			
		||||
    if flag & JOB_NORMAL == JOB_NORMAL {
 | 
			
		||||
        if flag & JOB_BG == JOB_BG {
 | 
			
		||||
            datatype = SUBMIT_JOB_BG
 | 
			
		||||
        } else {
 | 
			
		||||
            datatype = SUBMIT_JOB
 | 
			
		||||
        }
 | 
			
		||||
    } else if flag & JOB_LOW == JOB_LOW {
 | 
			
		||||
    if flag & JOB_LOW == JOB_LOW {
 | 
			
		||||
        if flag & JOB_BG == JOB_BG {
 | 
			
		||||
            datatype = SUBMIT_JOB_LOW_BG
 | 
			
		||||
        } else {
 | 
			
		||||
@ -80,20 +72,97 @@ func (client *Client) Do(funcname string, data []byte, flag byte) (err os.Error)
 | 
			
		||||
        } else {
 | 
			
		||||
            datatype = SUBMIT_JOB_HIGH
 | 
			
		||||
        }
 | 
			
		||||
    } else if flag & JOB_BG == JOB_BG {
 | 
			
		||||
        datatype = SUBMIT_JOB_BG
 | 
			
		||||
    } else {
 | 
			
		||||
        datatype = SUBMIT_JOB
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    rel := make([]byte, 0, 1024 * 64)
 | 
			
		||||
    rel = append(rel, []byte(funcname) ...)
 | 
			
		||||
    rel = append(rel, '\x00')
 | 
			
		||||
    rel = append(rel, '\xFF')
 | 
			
		||||
    client.mutex.Lock()
 | 
			
		||||
    uid := uint32ToByte(client.UId)
 | 
			
		||||
    client.UId ++
 | 
			
		||||
    rel = append(rel, uid[:] ...)
 | 
			
		||||
    client.mutex.Unlock()
 | 
			
		||||
    rel = append(rel, '\x00')
 | 
			
		||||
    rel = append(rel, data ...)
 | 
			
		||||
    job := NewClientJob(REQ, datatype, data)
 | 
			
		||||
    return client.WriteJob(job)
 | 
			
		||||
    if err = client.WriteJob(NewClientJob(REQ, datatype, rel)); err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    var job *ClientJob
 | 
			
		||||
    if job, err = client.ReadLastJob(JOB_CREATED); err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    handle = string(job.Data)
 | 
			
		||||
    go func() {
 | 
			
		||||
        if flag & JOB_BG != JOB_BG {
 | 
			
		||||
            for {
 | 
			
		||||
                if job, err = client.ReadJob(); err != nil {
 | 
			
		||||
                    return
 | 
			
		||||
                }
 | 
			
		||||
                switch job.dataType {
 | 
			
		||||
                    case WORK_DATA, WORK_WARNING:
 | 
			
		||||
                    case WORK_STATUS:
 | 
			
		||||
                    case WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
 | 
			
		||||
                        return
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }()
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) Echo(data []byte) (err os.Error) {
 | 
			
		||||
    job := NewClientJob(REQ, ECHO_REQ, data)
 | 
			
		||||
    return client.WriteJob(job)
 | 
			
		||||
func (client *Client) ReadLastJob(datatype uint32) (job *ClientJob, err os.Error){
 | 
			
		||||
    for {
 | 
			
		||||
        if job, err = client.ReadJob(); err != nil {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        if job.dataType == datatype {
 | 
			
		||||
            break
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if job.dataType != datatype {
 | 
			
		||||
        err = os.NewError("No job got.")
 | 
			
		||||
    }
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
    if job, err = client.ReadLastJob(STATUS_RES); err != nil {
 | 
			
		||||
        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
 | 
			
		||||
    if job, err = client.ReadLastJob(ECHO_RES); err != nil {
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    return job.Data, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) LastResult() (job *ClientJob) {
 | 
			
		||||
@ -108,18 +177,6 @@ func (client *Client) LastResult() (job *ClientJob) {
 | 
			
		||||
    return <-client.JobQueue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) LastError() (err os.Error) {
 | 
			
		||||
    if l := len(client.ErrQueue); l != 1 {
 | 
			
		||||
        if l == 0 {
 | 
			
		||||
            return
 | 
			
		||||
        }
 | 
			
		||||
        for i := 0; i < l - 1; i ++ {
 | 
			
		||||
            <-client.ErrQueue
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return <-client.ErrQueue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) WriteJob(job *ClientJob) (err os.Error) {
 | 
			
		||||
    return client.Write(job.Encode())
 | 
			
		||||
}
 | 
			
		||||
@ -136,9 +193,7 @@ func (client *Client) Write(buf []byte) (err os.Error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (client *Client) Close() (err os.Error) {
 | 
			
		||||
    client.running = false
 | 
			
		||||
    err = client.conn.Close()
 | 
			
		||||
    close(client.JobQueue)
 | 
			
		||||
    close(client.ErrQueue)
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ package gearman
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
    "os"
 | 
			
		||||
//    "log"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ClientJob struct {
 | 
			
		||||
@ -47,3 +48,43 @@ func (job *ClientJob) Encode() (data []byte) {
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (job * ClientJob) Result() (data []byte, err os.Error){
 | 
			
		||||
    switch job.dataType {
 | 
			
		||||
        case WORK_FAIL:
 | 
			
		||||
            job.Handle = string(job.Data)
 | 
			
		||||
            err = os.NewError("Work fail.")
 | 
			
		||||
            return
 | 
			
		||||
        case WORK_EXCEPTION:
 | 
			
		||||
            err = os.NewError("Work exception.")
 | 
			
		||||
            fallthrough
 | 
			
		||||
        case WORK_COMPLETE:
 | 
			
		||||
            s := splitByteArray(job.Data, '\x00')
 | 
			
		||||
            if len(s) != 2 {
 | 
			
		||||
                err = os.NewError("Invalid data.")
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            job.Handle = string(s[0])
 | 
			
		||||
            data = s[1]
 | 
			
		||||
        default:
 | 
			
		||||
            err = os.NewError("The job is not a result.")
 | 
			
		||||
    }
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (job *ClientJob) Update() (data []byte, err os.Error) {
 | 
			
		||||
    if job.dataType != WORK_DATA && job.dataType != WORK_WARNING {
 | 
			
		||||
        err = os.NewError("The job is not a update.")
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    s := splitByteArray(job.Data, '\x00')
 | 
			
		||||
    if len(s) != 2 {
 | 
			
		||||
        err = os.NewError("Invalid data.")
 | 
			
		||||
        return
 | 
			
		||||
    }
 | 
			
		||||
    if job.dataType == WORK_WARNING {
 | 
			
		||||
        err = os.NewError("Work warning")
 | 
			
		||||
    }
 | 
			
		||||
    job.Handle = string(s[0])
 | 
			
		||||
    data = s[1]
 | 
			
		||||
    return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,17 +19,21 @@ func TestClientAddServer(t * testing.T) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestClientEcho(t * testing.T) {
 | 
			
		||||
    if err := client.Echo([]byte("Hello world")); err != nil {
 | 
			
		||||
    if echo, err := client.Echo([]byte("Hello world")); err != nil {
 | 
			
		||||
        t.Error(err)
 | 
			
		||||
    } else {
 | 
			
		||||
        t.Log(echo)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
func TestClientDo(t * testing.T) {
 | 
			
		||||
    if err := client.Do("ToUpper", []byte("abcdef"), JOB_NORMAL); err != nil {
 | 
			
		||||
    if handle, err := client.Do("ToUpper", []byte("abcdef"), JOB_LOW | JOB_BG); err != nil {
 | 
			
		||||
        t.Error(err)
 | 
			
		||||
    } else {
 | 
			
		||||
        t.Log(handle)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
/*
 | 
			
		||||
func TestClientLastResult(t * testing.T) {
 | 
			
		||||
    job := client.LastResult()
 | 
			
		||||
@ -46,3 +50,4 @@ func TestClientClose(t * testing.T) {
 | 
			
		||||
        t.Error(err)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,27 +9,33 @@ const (
 | 
			
		||||
    WORKER_SERVER_CAP = 32
 | 
			
		||||
    WORKER_FUNCTION_CAP = 512
 | 
			
		||||
    QUEUE_CAP = 512
 | 
			
		||||
    BUFFER_SIZE = 1024
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
     // \x00REQ
 | 
			
		||||
    REQ = 5391697
 | 
			
		||||
    REQ_STR = "\x00REQ"
 | 
			
		||||
    // \x00RES
 | 
			
		||||
    RES = 5391699
 | 
			
		||||
    RES_STR = "\x00RES"
 | 
			
		||||
 | 
			
		||||
    CAN_DO = 1
 | 
			
		||||
    CANT_DO = 2
 | 
			
		||||
    RESET_ABILITIES = 3
 | 
			
		||||
    PRE_SLEEP = 4
 | 
			
		||||
    NOOP = 6
 | 
			
		||||
    JOB_CREATED = 8
 | 
			
		||||
    GRAB_JOB = 9
 | 
			
		||||
    NO_JOB = 10
 | 
			
		||||
    JOB_ASSIGN = 11
 | 
			
		||||
    WORK_STATUS = 12
 | 
			
		||||
    WORK_COMPLETE = 13
 | 
			
		||||
    WORK_FAIL = 14
 | 
			
		||||
    GET_STATUS = 15
 | 
			
		||||
    ECHO_REQ = 16
 | 
			
		||||
    ECHO_RES = 17
 | 
			
		||||
    ERROR = 19
 | 
			
		||||
    STATUS_RES = 20
 | 
			
		||||
    SET_CLIENT_ID = 22
 | 
			
		||||
    CAN_DO_TIMEOUT = 23
 | 
			
		||||
    WORK_EXCEPTION = 25
 | 
			
		||||
 | 
			
		||||
@ -121,7 +121,7 @@ func (worker * Worker) Work() {
 | 
			
		||||
                        if err := worker.exec(job); err != nil {
 | 
			
		||||
                            worker.ErrQueue <- err
 | 
			
		||||
                        }
 | 
			
		||||
                        continue
 | 
			
		||||
                        fallthrough
 | 
			
		||||
                    default:
 | 
			
		||||
                        worker.JobQueue <- job
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
@ -30,7 +30,7 @@ func (client *jobClient) Work() {
 | 
			
		||||
        }
 | 
			
		||||
        var rel []byte
 | 
			
		||||
        for {
 | 
			
		||||
            buf := make([]byte, 2048)
 | 
			
		||||
            buf := make([]byte, BUFFER_SIZE)
 | 
			
		||||
            n, err := client.conn.Read(buf)
 | 
			
		||||
            if err != nil {
 | 
			
		||||
                if err == os.EOF && n == 0 {
 | 
			
		||||
@ -40,6 +40,9 @@ func (client *jobClient) Work() {
 | 
			
		||||
                continue OUT
 | 
			
		||||
            }
 | 
			
		||||
            rel = append(rel, buf[0: n] ...)
 | 
			
		||||
            if n < BUFFER_SIZE {
 | 
			
		||||
                break
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        job, err := DecodeWorkerJob(rel)
 | 
			
		||||
        if err != nil {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user