diff --git a/command.go b/command.go index a9c474bae..fe3d5b08c 100644 --- a/command.go +++ b/command.go @@ -483,7 +483,7 @@ func (cmd *Cmd) readReply(rd *proto.Reader) (err error) { } func (cmd *Cmd) ReadReply(rd *proto.Reader) (err error) { - cmd.val, err = rd.ReadReply(sliceParser) + cmd.val, err = rd.ReadReply() return err } diff --git a/internal/proto/reader.go b/internal/proto/reader.go index 8d23817fe..6c4c873c5 100644 --- a/internal/proto/reader.go +++ b/internal/proto/reader.go @@ -31,6 +31,9 @@ const ( RespPush = '>' // >\r\n... (same as Array) ) +// StatusString is the read golang type of the RespStatus. +type StatusString string + // Not used temporarily. // Redis has not used these two data types for the time being, and will implement them later. // Streamed = "EOF:" @@ -159,7 +162,7 @@ func (r *Reader) ReadReply() (interface{}, error) { switch line[0] { case RespStatus: - return string(line[1:]), nil + return StatusString(line[1:]), nil case RespInt: return util.ParseInt(line[1:], 10, 64) case RespFloat: diff --git a/internal/proto/writer.go b/internal/proto/writer.go index 805286e6c..ebca609a0 100644 --- a/internal/proto/writer.go +++ b/internal/proto/writer.go @@ -71,6 +71,8 @@ func (w *Writer) WriteArg(v interface{}) error { return w.string(v) case *string: return w.string(*v) + case StatusString: + return w.status(v) case []byte: return w.bytes(v) case int: @@ -166,6 +168,18 @@ func (w *Writer) bytes(b []byte) error { return w.crlf() } +func (w *Writer) status(s StatusString) error { + if err := w.WriteByte(RespStatus); err != nil { + return err + } + + if _, err := w.Write([]byte(s)); err != nil { + return err + } + + return w.crlf() +} + func (w *Writer) string(s string) error { return w.bytes(util.StringToBytes(s)) } diff --git a/internal/proto/writer_test.go b/internal/proto/writer_test.go index 7c9d20884..3d31f83bb 100644 --- a/internal/proto/writer_test.go +++ b/internal/proto/writer_test.go @@ -152,3 +152,30 @@ var _ = Describe("WriteArg", func() { }) } }) + +func TestWriteStatus(t *testing.T) { + inputStatusBytes := []byte("+status\r\n") + + // Read it. + reader := proto.NewReader(bytes.NewReader(inputStatusBytes)) + readStatus, err := reader.ReadReply() + if err != nil { + t.Errorf("Failed to ReadReply: %v", err) + } + + if readStatus != proto.StatusString("status") { + t.Errorf("expect read %v but got %v", "status", readStatus) + } + + // Write it. + outputStatusBytes := new(bytes.Buffer) + writer := proto.NewWriter(outputStatusBytes) + err = writer.WriteArg(readStatus) + if err != nil { + t.Errorf("Failed to WriteArg: %v", err) + } + + if string(inputStatusBytes) != outputStatusBytes.String() { + t.Errorf("expect written %v but got %v", string(inputStatusBytes), outputStatusBytes.String()) + } +} diff --git a/proto.go b/proto.go index 9b788c870..d942290c7 100644 --- a/proto.go +++ b/proto.go @@ -4,7 +4,7 @@ import ( "bytes" "io" - "github.com/go-redis/redis/v9/internal/proto" + "github.com/redis/go-redis/v9/internal/proto" ) type Reader = proto.Reader diff --git a/pubsub.go b/pubsub.go index 72b18f49a..c0d311004 100644 --- a/pubsub.go +++ b/pubsub.go @@ -366,6 +366,10 @@ func (p *Pong) String() string { func (c *PubSub) newMessage(reply interface{}) (interface{}, error) { switch reply := reply.(type) { + case proto.StatusString: + return &Pong{ + Payload: string(reply), + }, nil case string: return &Pong{ Payload: reply, diff --git a/redis_test.go b/redis_test.go index ef2125452..560108265 100644 --- a/redis_test.go +++ b/redis_test.go @@ -13,6 +13,7 @@ import ( . "github.com/bsm/gomega" "github.com/redis/go-redis/v9" + "github.com/redis/go-redis/v9/internal/proto" ) type redisHookError struct{} @@ -224,7 +225,7 @@ var _ = Describe("Client", func() { Expect(client.Echo(ctx, "hello").Err()).NotTo(HaveOccurred()) Expect(cmd.Err()).NotTo(HaveOccurred()) - Expect(cmd.Val()).To(Equal("PONG")) + Expect(cmd.Val()).To(Equal(proto.StatusString("PONG"))) }) It("should retry command on network error", func() {