reply.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Package reply 实现了Redis序列化协议(RESP)的回复处理功能。
  2. //
  3. // 本包包含构建符合Redis RESP协议的各种响应格式的实现,支持以下类型:
  4. // - 简单字符串(Simple Strings): StatusReply
  5. // - 错误类型(Errors): StandardErrReply 及其子类型
  6. // - 整型(Integers): IntReply
  7. // - 批量字符串(Bulk Strings): BulkReply
  8. // - 数组(Arrays): MultiBulkReply
  9. //
  10. // 所有回复类型都实现了 `resp.Reply` 接口,通过 `ToBytes()` 方法生成符合RESP协议格式的字节数据。
  11. //
  12. // 示例用法:
  13. //
  14. // 创建整数回复
  15. //
  16. // reply := NewIntReply(42)
  17. // output := reply.ToBytes() // 输出 ":42\r\n"
  18. //
  19. // 创建批量字符串回复
  20. //
  21. // bulk := NewBulkReply([]byte("hello"))
  22. // output := bulk.ToBytes() // 输出 "$5\r\nhello\r\n"
  23. package reply
  24. import (
  25. "bytes"
  26. "strconv"
  27. "github.com/runningwater/go-redis/interface/resp"
  28. )
  29. var (
  30. nullBulkReplyBytes = []byte("$-1")
  31. CRLF = "\r\n"
  32. )
  33. // BulkReply 表示批量字符串回复的结构体。
  34. type BulkReply struct {
  35. Arg []byte // "test" => "$4\r\ntest\r\n"
  36. }
  37. func (b *BulkReply) String() string {
  38. return string(b.ToBytes())
  39. }
  40. func (b *BulkReply) ToBytes() []byte {
  41. if len(b.Arg) == 0 {
  42. return nullBulkReplyBytes
  43. }
  44. return []byte("$" + strconv.Itoa(len(b.Arg)) + CRLF + string(b.Arg) + CRLF)
  45. }
  46. func NewBulkReply(arg []byte) *BulkReply {
  47. return &BulkReply{Arg: arg}
  48. }
  49. // MultiBulkReply 表示多条批量字符串回复的结构体。 数组
  50. type MultiBulkReply struct {
  51. Args [][]byte
  52. }
  53. func (m *MultiBulkReply) String() string {
  54. return string(m.ToBytes())
  55. }
  56. func (m *MultiBulkReply) ToBytes() []byte {
  57. argLen := len(m.Args)
  58. var buf bytes.Buffer
  59. buf.WriteString("*" + strconv.Itoa(argLen) + CRLF)
  60. for _, arg := range m.Args {
  61. if arg == nil {
  62. buf.WriteString(string(nullBulkReplyBytes) + CRLF)
  63. } else {
  64. buf.WriteString("$" + strconv.Itoa(len(arg)) + CRLF + string(arg) + CRLF)
  65. }
  66. }
  67. return buf.Bytes()
  68. }
  69. func NewMultiBulkReply(args [][]byte) *MultiBulkReply {
  70. return &MultiBulkReply{Args: args}
  71. }
  72. // StatusReply 表示简单字符串回复的结构体。
  73. // 例如:OK、PING、SET、GET等命令的回复。
  74. // 对应Redis的"+"开头的回复。
  75. // 例如:"+OK\r\n"
  76. type StatusReply struct {
  77. Status string
  78. }
  79. func (s *StatusReply) String() string {
  80. return string(s.ToBytes())
  81. }
  82. func (s *StatusReply) ToBytes() []byte {
  83. return []byte("+" + s.Status + CRLF)
  84. }
  85. func NewStatusReply(status string) *StatusReply {
  86. return &StatusReply{Status: status}
  87. }
  88. // IntReply 表示整数回复的结构体。
  89. // 对应Redis的":"开头的回复。
  90. // 例如:":1\r\n"
  91. type IntReply struct {
  92. Code int64
  93. }
  94. func (i *IntReply) String() string {
  95. return string(i.ToBytes())
  96. }
  97. func (i *IntReply) ToBytes() []byte {
  98. return []byte(":" + strconv.FormatInt(i.Code, 10) + CRLF)
  99. }
  100. func NewIntReply(code int64) *IntReply {
  101. return &IntReply{Code: code}
  102. }
  103. // ErrorReply 表示错误回复的接口。
  104. type ErrorReply interface {
  105. Error() string
  106. ToBytes() []byte
  107. }
  108. // StandardErrReply 表示标准错误回复的结构体。
  109. // 对应Redis的"-"开头的回复。
  110. // 例如:"-ERR unknown command 'foobar'\r\n"
  111. type StandardErrReply struct {
  112. Status string
  113. }
  114. func (s *StandardErrReply) String() string {
  115. return string(s.ToBytes())
  116. }
  117. func (s *StandardErrReply) Error() string {
  118. return s.Status
  119. }
  120. func (s *StandardErrReply) ToBytes() []byte {
  121. return []byte("-" + s.Status + CRLF)
  122. }
  123. func NewErrReply(status string) *StandardErrReply {
  124. return &StandardErrReply{Status: status}
  125. }
  126. // IsErrReply 判断回复是否为错误回复。
  127. // 错误回复的第一个字节为"-"。
  128. // 例如:"-ERR unknown command 'foobar'\r\n"
  129. func IsErrReply(reply resp.Reply) bool {
  130. return reply.ToBytes()[0] == '-'
  131. }