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.

response.go 3.2 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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  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. "bytes"
  8. "encoding/binary"
  9. "fmt"
  10. "strconv"
  11. )
  12. // Response handler
  13. type ResponseHandler func(*Response)
  14. // response
  15. type Response struct {
  16. DataType uint32
  17. Data, UID []byte
  18. Handle string
  19. }
  20. // Extract the Response's result.
  21. // if data == nil, err != nil, then worker failing to execute job
  22. // if data != nil, err != nil, then worker has a exception
  23. // if data != nil, err == nil, then worker complate job
  24. // after calling this method, the Response.Handle will be filled
  25. func (resp *Response) Result() (data []byte, err error) {
  26. switch resp.DataType {
  27. case WORK_FAIL:
  28. resp.Handle = string(resp.Data)
  29. err = ErrWorkFail
  30. return
  31. case WORK_EXCEPTION:
  32. err = ErrWorkException
  33. fallthrough
  34. case WORK_COMPLETE:
  35. s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
  36. if len(s) != 2 {
  37. err = fmt.Errorf("Invalid data: %V", resp.Data)
  38. return
  39. }
  40. resp.Handle = string(s[0])
  41. data = s[1]
  42. default:
  43. err = ErrDataType
  44. }
  45. return
  46. }
  47. // Extract the job's update
  48. func (resp *Response) Update() (data []byte, err error) {
  49. if resp.DataType != WORK_DATA &&
  50. resp.DataType != WORK_WARNING {
  51. err = ErrDataType
  52. return
  53. }
  54. s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
  55. if len(s) != 2 {
  56. err = ErrInvalidData
  57. return
  58. }
  59. if resp.DataType == WORK_WARNING {
  60. err = ErrWorkWarning
  61. }
  62. resp.Handle = string(s[0])
  63. data = s[1]
  64. return
  65. }
  66. // Decode a job from byte slice
  67. func decodeResponse(data []byte) (resp *Response, l int, err error) {
  68. if len(data) < MIN_PACKET_LEN { // valid package should not less 12 bytes
  69. err = fmt.Errorf("Invalid data: %V", data)
  70. return
  71. }
  72. dl := int(binary.BigEndian.Uint32(data[8:12]))
  73. dt := data[MIN_PACKET_LEN : dl+MIN_PACKET_LEN]
  74. if len(dt) != int(dl) { // length not equal
  75. err = fmt.Errorf("Invalid data: %V", data)
  76. return
  77. }
  78. resp = getResponse()
  79. resp.DataType = binary.BigEndian.Uint32(data[4:8])
  80. switch resp.DataType {
  81. case JOB_CREATED:
  82. resp.Handle = string(dt)
  83. case STATUS_RES, WORK_DATA, WORK_WARNING, WORK_STATUS,
  84. WORK_COMPLETE, WORK_FAIL, WORK_EXCEPTION:
  85. s := bytes.SplitN(dt, []byte{'\x00'}, 2)
  86. if len(s) >= 2 {
  87. resp.Handle = string(s[0])
  88. resp.Data = s[1]
  89. } else {
  90. err = fmt.Errorf("Invalid data: %V", data)
  91. return
  92. }
  93. case ECHO_RES:
  94. fallthrough
  95. default:
  96. resp.Data = dt
  97. }
  98. l = dl + MIN_PACKET_LEN
  99. return
  100. }
  101. // status handler
  102. func (resp *Response) Status() (status *Status, err error) {
  103. data := bytes.SplitN(resp.Data, []byte{'\x00'}, 4)
  104. if len(data) != 4 {
  105. err = fmt.Errorf("Invalid data: %V", resp.Data)
  106. return
  107. }
  108. status = &Status{}
  109. status.Handle = resp.Handle
  110. status.Known = (data[0][0] == '1')
  111. status.Running = (data[1][0] == '1')
  112. status.Numerator, err = strconv.ParseUint(string(data[2]), 10, 0)
  113. if err != nil {
  114. err = fmt.Errorf("Invalid Integer: %s", data[2])
  115. return
  116. }
  117. status.Denominator, err = strconv.ParseUint(string(data[3]), 10, 0)
  118. if err != nil {
  119. err = fmt.Errorf("Invalid Integer: %s", data[3])
  120. return
  121. }
  122. return
  123. }
  124. func getResponse() (resp *Response) {
  125. // TODO add a pool
  126. resp = &Response{}
  127. return
  128. }