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
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
10 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // The client package helps developers connect to Gearmand, send
  2. // jobs and fetch result.
  3. package client
  4. import (
  5. "bufio"
  6. "net"
  7. "sync"
  8. )
  9. // One client connect to one server.
  10. // Use Pool for multi-connections.
  11. type Client struct {
  12. sync.Mutex
  13. net, addr, lastcall string
  14. respHandler map[string]ResponseHandler
  15. innerHandler map[string]ResponseHandler
  16. in chan *Response
  17. conn net.Conn
  18. rw *bufio.ReadWriter
  19. ErrorHandler ErrorHandler
  20. }
  21. // Return a client.
  22. func New(network, addr string) (client *Client, err error) {
  23. client = &Client{
  24. net: network,
  25. addr: addr,
  26. respHandler: make(map[string]ResponseHandler, queueSize),
  27. innerHandler: make(map[string]ResponseHandler, queueSize),
  28. in: make(chan *Response, queueSize),
  29. }
  30. client.conn, err = net.Dial(client.net, client.addr)
  31. if err != nil {
  32. return
  33. }
  34. client.rw = bufio.NewReadWriter(bufio.NewReader(client.conn),
  35. bufio.NewWriter(client.conn))
  36. go client.readLoop()
  37. go client.processLoop()
  38. return
  39. }
  40. func (client *Client) write(req *request) (err error) {
  41. var n int
  42. buf := req.Encode()
  43. for i := 0; i < len(buf); i += n {
  44. n, err = client.rw.Write(buf[i:])
  45. if err != nil {
  46. return
  47. }
  48. }
  49. return client.rw.Flush()
  50. }
  51. func (client *Client) read(length int) (data []byte, err error) {
  52. n := 0
  53. buf := getBuffer(bufferSize)
  54. // read until data can be unpacked
  55. for i := length; i > 0 || len(data) < minPacketLength; i -= n {
  56. if n, err = client.rw.Read(buf); err != nil {
  57. return
  58. }
  59. data = append(data, buf[0:n]...)
  60. if n < bufferSize {
  61. break
  62. }
  63. }
  64. return
  65. }
  66. func (client *Client) readLoop() {
  67. defer close(client.in)
  68. var data, leftdata []byte
  69. var err error
  70. var resp *Response
  71. ReadLoop:
  72. for client.conn != nil {
  73. if data, err = client.read(bufferSize); err != nil {
  74. if opErr, ok := err.(*net.OpError); ok {
  75. if opErr.Timeout() {
  76. client.err(err)
  77. }
  78. if opErr.Temporary() {
  79. continue
  80. }
  81. break
  82. }
  83. client.err(err)
  84. // If it is unexpected error and the connection wasn't
  85. // closed by Gearmand, the client should close the conection
  86. // and reconnect to job server.
  87. client.Close()
  88. client.conn, err = net.Dial(client.net, client.addr)
  89. if err != nil {
  90. client.err(err)
  91. break
  92. }
  93. client.rw = bufio.NewReadWriter(bufio.NewReader(client.conn),
  94. bufio.NewWriter(client.conn))
  95. continue
  96. }
  97. if len(leftdata) > 0 { // some data left for processing
  98. data = append(leftdata, data...)
  99. leftdata = nil
  100. }
  101. for {
  102. l := len(data)
  103. if l < minPacketLength { // not enough data
  104. leftdata = data
  105. continue ReadLoop
  106. }
  107. if resp, l, err = decodeResponse(data); err != nil {
  108. leftdata = data[l:]
  109. continue ReadLoop
  110. } else {
  111. client.in <- resp
  112. }
  113. data = data[l:]
  114. if len(data) > 0 {
  115. continue
  116. }
  117. break
  118. }
  119. }
  120. }
  121. func (client *Client) processLoop() {
  122. for resp := range client.in {
  123. switch resp.DataType {
  124. case dtError:
  125. if client.lastcall != "" {
  126. resp = client.handleInner(client.lastcall, resp)
  127. client.lastcall = ""
  128. } else {
  129. client.err(getError(resp.Data))
  130. }
  131. case dtStatusRes:
  132. resp = client.handleInner("s"+resp.Handle, resp)
  133. case dtJobCreated:
  134. resp = client.handleInner("c", resp)
  135. case dtEchoRes:
  136. resp = client.handleInner("e", resp)
  137. case dtWorkData, dtWorkWarning, dtWorkStatus:
  138. resp = client.handleResponse(resp.Handle, resp)
  139. case dtWorkComplete, dtWorkFail, dtWorkException:
  140. client.handleResponse(resp.Handle, resp)
  141. delete(client.respHandler, resp.Handle)
  142. }
  143. }
  144. }
  145. func (client *Client) err(e error) {
  146. if client.ErrorHandler != nil {
  147. client.ErrorHandler(e)
  148. }
  149. }
  150. func (client *Client) handleResponse(key string, resp *Response) *Response {
  151. if h, ok := client.respHandler[key]; ok {
  152. h(resp)
  153. return nil
  154. }
  155. return resp
  156. }
  157. func (client *Client) handleInner(key string, resp *Response) *Response {
  158. if h, ok := client.innerHandler[key]; ok {
  159. h(resp)
  160. delete(client.innerHandler, key)
  161. return nil
  162. }
  163. return resp
  164. }
  165. func (client *Client) do(funcname string, data []byte,
  166. flag uint32) (handle string, err error) {
  167. if client.conn == nil {
  168. return "", ErrLostConn
  169. }
  170. var mutex sync.Mutex
  171. mutex.Lock()
  172. client.lastcall = "c"
  173. client.innerHandler["c"] = func(resp *Response) {
  174. defer mutex.Unlock()
  175. if resp.DataType == dtError {
  176. err = getError(resp.Data)
  177. return
  178. }
  179. handle = resp.Handle
  180. }
  181. id := IdGen.Id()
  182. req := getJob(id, []byte(funcname), data)
  183. req.DataType = flag
  184. if err = client.write(req); err != nil {
  185. delete(client.innerHandler, "c")
  186. client.lastcall = ""
  187. return
  188. }
  189. mutex.Lock()
  190. return
  191. }
  192. // Call the function and get a response.
  193. // flag can be set to: JobLow, JobNormal and JobHigh
  194. func (client *Client) Do(funcname string, data []byte,
  195. flag byte, h ResponseHandler) (handle string, err error) {
  196. var datatype uint32
  197. switch flag {
  198. case JobLow:
  199. datatype = dtSubmitJobLow
  200. case JobHigh:
  201. datatype = dtSubmitJobHigh
  202. default:
  203. datatype = dtSubmitJob
  204. }
  205. handle, err = client.do(funcname, data, datatype)
  206. if err == nil && h != nil {
  207. client.respHandler[handle] = h
  208. }
  209. return
  210. }
  211. // Call the function in background, no response needed.
  212. // flag can be set to: JobLow, JobNormal and JobHigh
  213. func (client *Client) DoBg(funcname string, data []byte,
  214. flag byte) (handle string, err error) {
  215. if client.conn == nil {
  216. return "", ErrLostConn
  217. }
  218. var datatype uint32
  219. switch flag {
  220. case JobLow:
  221. datatype = dtSubmitJobLowBg
  222. case JobHigh:
  223. datatype = dtSubmitJobHighBg
  224. default:
  225. datatype = dtSubmitJobBg
  226. }
  227. handle, err = client.do(funcname, data, datatype)
  228. return
  229. }
  230. // Get job status from job server.
  231. func (client *Client) Status(handle string) (status *Status, err error) {
  232. if client.conn == nil {
  233. return nil, ErrLostConn
  234. }
  235. var mutex sync.Mutex
  236. mutex.Lock()
  237. client.lastcall = "s" + handle
  238. client.innerHandler["s"+handle] = func(resp *Response) {
  239. defer mutex.Unlock()
  240. var err error
  241. status, err = resp._status()
  242. if err != nil {
  243. client.err(err)
  244. }
  245. }
  246. req := getRequest()
  247. req.DataType = dtGetStatus
  248. req.Data = []byte(handle)
  249. client.write(req)
  250. mutex.Lock()
  251. return
  252. }
  253. // Echo.
  254. func (client *Client) Echo(data []byte) (echo []byte, err error) {
  255. if client.conn == nil {
  256. return nil, ErrLostConn
  257. }
  258. var mutex sync.Mutex
  259. mutex.Lock()
  260. client.innerHandler["e"] = func(resp *Response) {
  261. echo = resp.Data
  262. mutex.Unlock()
  263. }
  264. req := getRequest()
  265. req.DataType = dtEchoReq
  266. req.Data = data
  267. client.lastcall = "e"
  268. client.write(req)
  269. mutex.Lock()
  270. return
  271. }
  272. // Close connection
  273. func (client *Client) Close() (err error) {
  274. client.Lock()
  275. defer client.Unlock()
  276. if client.conn != nil {
  277. err = client.conn.Close()
  278. client.conn = nil
  279. }
  280. return
  281. }