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.

157 lines
3.6 KiB

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