You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

client.go 6.5 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // Copyright 2011 Xing Xing <mikespook@gmail.com>.
  2. // All rights reserved.
  3. // Use of this source code is governed by a MIT
  4. // license that can be found in the LICENSE file.
  5. package client
  6. import (
  7. "io"
  8. "net"
  9. "sync"
  10. // "fmt"
  11. )
  12. /*
  13. The client side api for gearman
  14. usage:
  15. c := client.New("tcp4", "127.0.0.1:4730")
  16. handle := c.Do("foobar", []byte("data here"), JOB_LOW | JOB_BG)
  17. */
  18. type Client struct {
  19. sync.Mutex
  20. net, addr, lastcall string
  21. respHandler map[string]ResponseHandler
  22. innerHandler map[string]ResponseHandler
  23. in chan []byte
  24. isConn bool
  25. conn net.Conn
  26. ErrorHandler ErrorHandler
  27. }
  28. // Create a new client.
  29. // Connect to "addr" through "network"
  30. // Eg.
  31. // client, err := client.New("127.0.0.1:4730")
  32. func New(net, addr string) (client *Client, err error) {
  33. client = &Client{
  34. net: net,
  35. addr: addr,
  36. respHandler: make(map[string]ResponseHandler, QUEUE_SIZE),
  37. innerHandler: make(map[string]ResponseHandler, QUEUE_SIZE),
  38. in: make(chan []byte, QUEUE_SIZE),
  39. }
  40. if err = client.connect(); err != nil {
  41. return
  42. }
  43. go client.readLoop()
  44. go client.processLoop()
  45. return
  46. }
  47. // {{{ private functions
  48. //
  49. func (client *Client) connect() (err error) {
  50. client.conn, err = net.Dial(client.net, client.addr)
  51. if err != nil {
  52. return
  53. }
  54. client.isConn = true
  55. return
  56. }
  57. // Internal write
  58. func (client *Client) write(req *request) (err error) {
  59. var n int
  60. buf := req.Encode()
  61. for i := 0; i < len(buf); i += n {
  62. n, err = client.conn.Write(buf[i:])
  63. if err != nil {
  64. return
  65. }
  66. }
  67. return
  68. }
  69. // read length bytes from the socket
  70. func (client *Client) read(length int) (data []byte, err error) {
  71. n := 0
  72. buf := getBuffer(BUFFER_SIZE)
  73. // read until data can be unpacked
  74. for i := length; i > 0 || len(data) < MIN_PACKET_LEN; i -= n {
  75. if n, err = client.conn.Read(buf); err != nil {
  76. if !client.isConn {
  77. err = ErrConnClosed
  78. return
  79. }
  80. if err == io.EOF && n == 0 {
  81. if data == nil {
  82. err = ErrConnection
  83. }
  84. }
  85. return
  86. }
  87. data = append(data, buf[0:n]...)
  88. if n < BUFFER_SIZE {
  89. break
  90. }
  91. }
  92. return
  93. }
  94. // read data from socket
  95. func (client *Client) readLoop() {
  96. var data []byte
  97. var err error
  98. for client.isConn {
  99. if data, err = client.read(BUFFER_SIZE); err != nil {
  100. if err == ErrConnClosed {
  101. break
  102. }
  103. client.err(err)
  104. continue
  105. }
  106. client.in <- data
  107. }
  108. close(client.in)
  109. }
  110. // decode data & process it
  111. func (client *Client) processLoop() {
  112. var resp *Response
  113. var l int
  114. var err error
  115. var data, leftdata []byte
  116. for data = range client.in {
  117. if len(leftdata) > 0 { // some data left for processing
  118. data = append(leftdata, data...)
  119. }
  120. l = len(data)
  121. if l < MIN_PACKET_LEN { // not enough data
  122. leftdata = data
  123. continue
  124. }
  125. if resp, l, err = decodeResponse(data); err != nil {
  126. client.err(err)
  127. continue
  128. }
  129. leftdata = nil
  130. for resp != nil {
  131. switch resp.DataType {
  132. case ERROR:
  133. if client.lastcall != "" {
  134. resp = client.handleInner(client.lastcall, resp)
  135. client.lastcall = ""
  136. } else {
  137. client.err(GetError(resp.Data))
  138. }
  139. case STATUS_RES:
  140. resp = client.handleInner("s"+resp.Handle, resp)
  141. case JOB_CREATED:
  142. resp = client.handleInner("c", resp)
  143. case ECHO_RES:
  144. resp = client.handleInner("e", resp)
  145. case WORK_DATA, WORK_WARNING, WORK_STATUS, WORK_COMPLETE,
  146. WORK_FAIL, WORK_EXCEPTION:
  147. resp = client.handleResponse(resp.Handle, resp)
  148. }
  149. }
  150. if len(data) > l {
  151. leftdata = data[l:]
  152. }
  153. }
  154. }
  155. // error handler
  156. func (client *Client) err(e error) {
  157. if client.ErrorHandler != nil {
  158. client.ErrorHandler(e)
  159. }
  160. }
  161. // job handler
  162. func (client *Client) handleResponse(key string, resp *Response) *Response {
  163. if h, ok := client.respHandler[key]; ok {
  164. h(resp)
  165. delete(client.respHandler, key)
  166. return nil
  167. }
  168. return resp
  169. }
  170. // job handler
  171. func (client *Client) handleInner(key string, resp *Response) * Response {
  172. if h, ok := client.innerHandler[key]; ok {
  173. h(resp)
  174. delete(client.innerHandler, key)
  175. return nil
  176. }
  177. return resp
  178. }
  179. // Internal do
  180. func (client *Client) do(funcname string, data []byte,
  181. flag uint32) (handle string, err error) {
  182. var mutex sync.Mutex
  183. mutex.Lock()
  184. client.lastcall = "c"
  185. client.innerHandler["c"] = func(resp *Response) {
  186. if resp.DataType == ERROR {
  187. err = GetError(resp.Data)
  188. return
  189. }
  190. handle = resp.Handle
  191. mutex.Unlock()
  192. }
  193. id := IdGen.Id()
  194. req := getJob(id, []byte(funcname), data)
  195. req.DataType = flag
  196. client.write(req)
  197. mutex.Lock()
  198. return
  199. }
  200. // }}}
  201. // Do the function.
  202. // funcname is a string with function name.
  203. // data is encoding to byte array.
  204. // flag set the job type, include running level: JOB_LOW, JOB_NORMAL, JOB_HIGH
  205. func (client *Client) Do(funcname string, data []byte,
  206. flag byte, h ResponseHandler) (handle string, err error) {
  207. var datatype uint32
  208. switch flag {
  209. case JOB_LOW:
  210. datatype = SUBMIT_JOB_LOW
  211. case JOB_HIGH:
  212. datatype = SUBMIT_JOB_HIGH
  213. default:
  214. datatype = SUBMIT_JOB
  215. }
  216. handle, err = client.do(funcname, data, datatype)
  217. if h != nil {
  218. client.respHandler[handle] = h
  219. }
  220. return
  221. }
  222. // Do the function at background.
  223. // funcname is a string with function name.
  224. // data is encoding to byte array.
  225. // flag set the job type, include running level: JOB_LOW, JOB_NORMAL, JOB_HIGH
  226. func (client *Client) DoBg(funcname string, data []byte,
  227. flag byte) (handle string, err error) {
  228. var datatype uint32
  229. switch flag {
  230. case JOB_LOW:
  231. datatype = SUBMIT_JOB_LOW_BG
  232. case JOB_HIGH:
  233. datatype = SUBMIT_JOB_HIGH_BG
  234. default:
  235. datatype = SUBMIT_JOB_BG
  236. }
  237. handle, err = client.do(funcname, data, datatype)
  238. return
  239. }
  240. // Get job status from job server.
  241. // !!!Not fully tested.!!!
  242. func (client *Client) Status(handle string) (status *Status, err error) {
  243. var mutex sync.Mutex
  244. mutex.Lock()
  245. client.lastcall = "s" + handle
  246. client.innerHandler["s"+handle] = func(resp *Response) {
  247. var err error
  248. status, err = resp.Status()
  249. if err != nil {
  250. client.err(err)
  251. }
  252. mutex.Unlock()
  253. }
  254. req := getRequest()
  255. req.DataType = GET_STATUS
  256. req.Data = []byte(handle)
  257. client.write(req)
  258. mutex.Lock()
  259. return
  260. }
  261. // Send a something out, get the samething back.
  262. func (client *Client) Echo(data []byte) (echo []byte, err error) {
  263. var mutex sync.Mutex
  264. mutex.Lock()
  265. client.innerHandler["e"] = func(resp *Response) {
  266. echo = resp.Data
  267. mutex.Unlock()
  268. }
  269. req := getRequest()
  270. req.DataType = ECHO_REQ
  271. req.Data = data
  272. client.lastcall = "e"
  273. client.write(req)
  274. mutex.Lock()
  275. return
  276. }
  277. // Close
  278. func (client *Client) Close() (err error) {
  279. client.isConn = false
  280. return client.conn.Close()
  281. }