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.
 
 
 

133 lines
3.0 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. s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
  32. if len(s) != 2 {
  33. err = fmt.Errorf("Invalid data: %V", resp.Data)
  34. return
  35. }
  36. resp.Handle = string(s[0])
  37. data = s[1]
  38. default:
  39. err = ErrDataType
  40. }
  41. return
  42. }
  43. // Extract the job's update
  44. func (resp *Response) Update() (data []byte, err error) {
  45. if resp.DataType != dtWorkData &&
  46. resp.DataType != dtWorkWarning {
  47. err = ErrDataType
  48. return
  49. }
  50. s := bytes.SplitN(resp.Data, []byte{'\x00'}, 2)
  51. if len(s) != 2 {
  52. err = ErrInvalidData
  53. return
  54. }
  55. if resp.DataType == dtWorkWarning {
  56. err = ErrWorkWarning
  57. }
  58. resp.Handle = string(s[0])
  59. data = s[1]
  60. return
  61. }
  62. // Decode a job from byte slice
  63. func decodeResponse(data []byte) (resp *Response, l int, err error) {
  64. if len(data) < minPacketLength { // valid package should not less 12 bytes
  65. err = fmt.Errorf("Invalid data: %V", data)
  66. return
  67. }
  68. dl := int(binary.BigEndian.Uint32(data[8:12]))
  69. dt := data[minPacketLength : dl+minPacketLength]
  70. if len(dt) != int(dl) { // length not equal
  71. err = fmt.Errorf("Invalid data: %V", data)
  72. return
  73. }
  74. resp = getResponse()
  75. resp.DataType = binary.BigEndian.Uint32(data[4:8])
  76. switch resp.DataType {
  77. case dtJobCreated:
  78. resp.Handle = string(dt)
  79. case dtStatusRes, dtWorkData, dtWorkWarning, dtWorkStatus,
  80. dtWorkComplete, dtWorkFail, dtWorkException:
  81. s := bytes.SplitN(dt, []byte{'\x00'}, 2)
  82. if len(s) >= 2 {
  83. resp.Handle = string(s[0])
  84. resp.Data = s[1]
  85. } else {
  86. err = fmt.Errorf("Invalid data: %V", data)
  87. return
  88. }
  89. case dtEchoRes:
  90. fallthrough
  91. default:
  92. resp.Data = dt
  93. }
  94. l = dl + minPacketLength
  95. return
  96. }
  97. // status handler
  98. func (resp *Response) Status() (status *Status, err error) {
  99. data := bytes.SplitN(resp.Data, []byte{'\x00'}, 4)
  100. if len(data) != 4 {
  101. err = fmt.Errorf("Invalid data: %V", resp.Data)
  102. return
  103. }
  104. status = &Status{}
  105. status.Handle = resp.Handle
  106. status.Known = (data[0][0] == '1')
  107. status.Running = (data[1][0] == '1')
  108. status.Numerator, err = strconv.ParseUint(string(data[2]), 10, 0)
  109. if err != nil {
  110. err = fmt.Errorf("Invalid Integer: %s", data[2])
  111. return
  112. }
  113. status.Denominator, err = strconv.ParseUint(string(data[3]), 10, 0)
  114. if err != nil {
  115. err = fmt.Errorf("Invalid Integer: %s", data[3])
  116. return
  117. }
  118. return
  119. }
  120. func getResponse() (resp *Response) {
  121. // TODO add a pool
  122. resp = &Response{}
  123. return
  124. }