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