reply.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. // Copyright 2012 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redis
  15. import (
  16. "errors"
  17. "fmt"
  18. "strconv"
  19. )
  20. var ErrNil = errors.New("redigo: nil returned")
  21. func Values(multiBulk []interface{}, values ...interface{}) ([]interface{}, error) {
  22. if len(multiBulk) < len(values) {
  23. return nil, errors.New("redigo Values: short multibulk")
  24. }
  25. var err error
  26. for i, value := range values {
  27. bulk := multiBulk[i]
  28. if bulk != nil {
  29. switch value := value.(type) {
  30. case *string:
  31. *value, err = String(bulk, nil)
  32. case *int:
  33. *value, err = Int(bulk, nil)
  34. case *bool:
  35. *value, err = Bool(bulk, nil)
  36. case *[]byte:
  37. *value, err = Bytes(bulk, nil)
  38. default:
  39. panic("Value type not supported")
  40. }
  41. if err != nil {
  42. break
  43. }
  44. }
  45. }
  46. return multiBulk[len(values):], err
  47. }
  48. // Int is a helper that converts a Redis reply to an int.
  49. //
  50. // Reply type Result
  51. // integer return reply as int
  52. // bulk parse decimal integer from reply
  53. // nil return error ErrNil
  54. // other return error
  55. //
  56. func Int(v interface{}, err error) (int, error) {
  57. if err != nil {
  58. return 0, err
  59. }
  60. switch v := v.(type) {
  61. case int64:
  62. return int(v), nil
  63. case []byte:
  64. n, err := strconv.ParseInt(string(v), 10, 0)
  65. return int(n), err
  66. case nil:
  67. return 0, ErrNil
  68. case Error:
  69. return 0, v
  70. }
  71. return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", v)
  72. }
  73. // String is a helper that converts a Redis reply to a string.
  74. //
  75. // Reply type Result
  76. // integer format as decimal string
  77. // bulk return reply as string
  78. // string return as is
  79. // nil return error ErrNil
  80. // other return error
  81. func String(v interface{}, err error) (string, error) {
  82. if err != nil {
  83. return "", err
  84. }
  85. switch v := v.(type) {
  86. case []byte:
  87. return string(v), nil
  88. case string:
  89. return v, nil
  90. case int64:
  91. return strconv.FormatInt(v, 10), nil
  92. case nil:
  93. return "", ErrNil
  94. case Error:
  95. return "", v
  96. }
  97. return "", fmt.Errorf("redigo: unexpected type for String, got type %T", v)
  98. }
  99. // Bytes is a helper that converts a Redis reply to slice of bytes.
  100. //
  101. // Reply type Result
  102. // integer format as decimal string
  103. // bulk return reply as slice of bytes
  104. // string return reply as slice of bytes
  105. // nil return error ErrNil
  106. // other return error
  107. func Bytes(v interface{}, err error) ([]byte, error) {
  108. if err != nil {
  109. return nil, err
  110. }
  111. switch v := v.(type) {
  112. case []byte:
  113. return v, nil
  114. case string:
  115. return []byte(v), nil
  116. case int64:
  117. return strconv.AppendInt(nil, v, 10), nil
  118. case nil:
  119. return nil, ErrNil
  120. case Error:
  121. return nil, v
  122. }
  123. return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", v)
  124. }
  125. // Bool is a helper that converts a Redis reply to a bool.
  126. //
  127. // Reply type Result
  128. // integer return value != 0
  129. // bulk return false if reply is "" or "0", otherwise return true.
  130. // nil return error ErrNil
  131. // other return error
  132. func Bool(v interface{}, err error) (bool, error) {
  133. if err != nil {
  134. return false, err
  135. }
  136. switch v := v.(type) {
  137. case int64:
  138. return v != 0, nil
  139. case []byte:
  140. if len(v) == 0 || (len(v) == 1 && v[0] == '0') {
  141. return false, nil
  142. }
  143. return true, nil
  144. case nil:
  145. return false, ErrNil
  146. case Error:
  147. return false, v
  148. }
  149. return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", v)
  150. }
  151. // MultiBulk is a helper that converts a Redis reply to a []interface{}.
  152. //
  153. // Reply type Result
  154. // multi-bulk return []interface{}
  155. // nil return error ErrNil
  156. // other return error
  157. func MultiBulk(v interface{}, err error) ([]interface{}, error) {
  158. if err != nil {
  159. return nil, err
  160. }
  161. switch v := v.(type) {
  162. case []interface{}:
  163. return v, nil
  164. case nil:
  165. return nil, ErrNil
  166. case Error:
  167. return nil, v
  168. }
  169. return nil, fmt.Errorf("redigo: unexpected type for MultiBulk, got type %T", v)
  170. }
  171. // Subscribe represents a subscribe or unsubscribe notification.
  172. type Subscription struct {
  173. // Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe"
  174. Kind string
  175. // The channel that was changed.
  176. Channel string
  177. // The current number of subscriptions for connection.
  178. Count int
  179. }
  180. // Message represents a message notification.
  181. type Message struct {
  182. // The originating channel.
  183. Channel string
  184. // The message data.
  185. Data []byte
  186. }
  187. // Notification is a helper that returns a pub/sub notification as a
  188. // Subscription or a Message.
  189. func Notification(reply interface{}, err error) (interface{}, error) {
  190. multiBulk, err := MultiBulk(reply, err)
  191. if err != nil {
  192. return nil, err
  193. }
  194. var kind, channel string
  195. multiBulk, err = Values(multiBulk, &kind, &channel)
  196. if err != nil {
  197. return nil, err
  198. }
  199. if kind == "message" {
  200. var data []byte
  201. if _, err := Values(multiBulk, &data); err != nil {
  202. return nil, err
  203. }
  204. return Message{channel, data}, nil
  205. }
  206. var count int
  207. if _, err := Values(multiBulk, &count); err != nil {
  208. return nil, err
  209. }
  210. return Subscription{kind, channel, count}, nil
  211. }