diff --git a/pipe.go b/pipe.go index 1d78f798..bd8e65e6 100644 --- a/pipe.go +++ b/pipe.go @@ -168,10 +168,14 @@ func _newPipe(connFn func() (net.Conn, error), option *ClientOption, r2ps, nobg if option.ClientNoEvict { init = append(init, []string{"CLIENT", "NO-EVICT", "ON"}) } + + addClientSetInfoCmds := true if len(option.ClientSetInfo) == 2 { init = append(init, []string{"CLIENT", "SETINFO", "LIB-NAME", option.ClientSetInfo[0]}, []string{"CLIENT", "SETINFO", "LIB-VER", option.ClientSetInfo[1]}) - } else { + } else if option.ClientSetInfo == nil { init = append(init, []string{"CLIENT", "SETINFO", "LIB-NAME", LibName}, []string{"CLIENT", "SETINFO", "LIB-VER", LibVer}) + } else { + addClientSetInfoCmds = false } timeout := option.Dialer.Timeout @@ -186,7 +190,14 @@ func _newPipe(connFn func() (net.Conn, error), option *ClientOption, r2ps, nobg if !r2 && !r2ps { resp := p.DoMulti(ctx, cmds.NewMultiCompleted(init)...) defer resultsp.Put(resp) - for i, r := range resp.s[:len(resp.s)-2] { // skip error checking on the last CLIENT SETINFO + + count := len(resp.s) + if addClientSetInfoCmds { + // skip error checking on the last CLIENT SETINFO + count -= 2 + } + + for i, r := range resp.s[:count] { if i == 0 { p.info, err = r.AsMap() } else { @@ -249,16 +260,28 @@ func _newPipe(connFn func() (net.Conn, error), option *ClientOption, r2ps, nobg if option.ClientNoEvict { init = append(init, []string{"CLIENT", "NO-EVICT", "ON"}) } + + addClientSetInfoCmds := true if len(option.ClientSetInfo) == 2 { init = append(init, []string{"CLIENT", "SETINFO", "LIB-NAME", option.ClientSetInfo[0]}, []string{"CLIENT", "SETINFO", "LIB-VER", option.ClientSetInfo[1]}) - } else { + } else if option.ClientSetInfo == nil { init = append(init, []string{"CLIENT", "SETINFO", "LIB-NAME", LibName}, []string{"CLIENT", "SETINFO", "LIB-VER", LibVer}) + } else { + addClientSetInfoCmds = false } + p.version = 5 if len(init) != 0 { resp := p.DoMulti(ctx, cmds.NewMultiCompleted(init)...) defer resultsp.Put(resp) - for i, r := range resp.s[:len(resp.s)-2] { // skip error checking on the last CLIENT SETINFO + + count := len(resp.s) + if addClientSetInfoCmds { + // skip error checking on the last CLIENT SETINFO + count -= 2 + } + + for i, r := range resp.s[:len(resp.s)-2] { if init[i][0] == "READONLY" { // ignore READONLY command error continue diff --git a/pipe_test.go b/pipe_test.go index 261cabea..5b41448f 100644 --- a/pipe_test.go +++ b/pipe_test.go @@ -491,6 +491,36 @@ func TestNewPipe(t *testing.T) { n1.Close() n2.Close() }) + t.Run("With DisableClientSetInfo", func(t *testing.T) { + n1, n2 := net.Pipe() + mock := &redisMock{buf: bufio.NewReader(n2), conn: n2, t: t} + go func() { + mock.Expect("HELLO", "3"). + Reply(RedisMessage{ + typ: '%', + values: []RedisMessage{ + {typ: '+', string: "proto"}, + {typ: ':', integer: 3}, + }, + }) + mock.Expect("CLIENT", "TRACKING", "ON", "OPTIN"). + ReplyString("OK") + }() + p, err := newPipe(func() (net.Conn, error) { return n1, nil }, &ClientOption{ + ClientSetInfo: DisableClientSetInfo, + }) + go func() { + mock.Expect("PING"). + ReplyString("OK") + }() + if err != nil { + t.Fatalf("pipe setup failed: %v", err) + } + p.Close() + mock.Close() + n1.Close() + n2.Close() + }) } func TestNewRESP2Pipe(t *testing.T) { diff --git a/rueidis.go b/rueidis.go index b066fa7c..b582eeb2 100644 --- a/rueidis.go +++ b/rueidis.go @@ -53,6 +53,8 @@ var ( ErrWrongPipelineMultiplex = errors.New("ClientOption.PipelineMultiplex must not be bigger than MaxPipelineMultiplex") // ErrDedicatedClientRecycled means the caller attempted to use the dedicated client which has been already recycled (after canceled/closed). ErrDedicatedClientRecycled = errors.New("dedicated client should not be used after recycled") + // DisableClientSetInfo is the value that can be used for ClientOption.ClientSetInfo to disable making the CLIENT SETINFO command + DisableClientSetInfo = make([]string, 0) ) // ClientOption should be passed to NewClient to construct a Client