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.
 
 
 

308 lines
6.6 KiB

  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. }