diff --git a/command.go b/command.go index 59cd8a6c6..86395f167 100644 --- a/command.go +++ b/command.go @@ -468,6 +468,11 @@ func (cmd *Cmd) readReply(rd *proto.Reader) (err error) { return err } +func (cmd *Cmd) ReadReply(rd *proto.Reader) (err error) { + cmd.val, err = rd.ReadReply() + return err +} + //------------------------------------------------------------------------------ type SliceCmd struct { diff --git a/internal/proto/writer.go b/internal/proto/writer.go index 15e15989f..0bee3f7f0 100644 --- a/internal/proto/writer.go +++ b/internal/proto/writer.go @@ -59,6 +59,10 @@ func (w *Writer) writeLen(n int) error { return err } +func (w *Writer) WriteLen(n int) error { + return w.writeLen(n) +} + func (w *Writer) WriteArg(v interface{}) error { switch v := v.(type) { case nil: diff --git a/options.go b/options.go index 56eab5354..55cd43cfe 100644 --- a/options.go +++ b/options.go @@ -128,6 +128,10 @@ type Options struct { // Enables read only queries on slave/follower nodes. readOnly bool + + // DisableAuthOnConnect (Teleport) disables sending AUTH or HELLO commands + // on new connection. + DisableAuthOnConnect bool } func (opt *Options) init() { diff --git a/proto.go b/proto.go new file mode 100644 index 000000000..9b788c870 --- /dev/null +++ b/proto.go @@ -0,0 +1,23 @@ +package redis + +import ( + "bytes" + "io" + + "github.com/go-redis/redis/v9/internal/proto" +) + +type Reader = proto.Reader +type Writer = proto.Writer +type RedisError = proto.RedisError + +const RespArray = proto.RespArray +const RespInt = proto.RespInt + +func NewReader(rd io.Reader) *Reader { + return proto.NewReader(rd) +} + +func NewWriter(wr *bytes.Buffer) *Writer { + return proto.NewWriter(wr) +} diff --git a/redis.go b/redis.go index 4d683f75c..1bd1c143e 100644 --- a/redis.go +++ b/redis.go @@ -221,45 +221,47 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { } cn.Inited = true - username, password := c.opt.Username, c.opt.Password - if c.opt.CredentialsProvider != nil { - username, password = c.opt.CredentialsProvider() - } - connPool := pool.NewSingleConnPool(c.connPool, cn) conn := newConn(c.opt, connPool) - var auth bool + if !c.opt.DisableAuthOnConnect { + username, password := c.opt.Username, c.opt.Password + if c.opt.CredentialsProvider != nil { + username, password = c.opt.CredentialsProvider() + } - // For redis-server < 6.0 that does not support the Hello command, - // we continue to provide services with RESP2. - if err := conn.Hello(ctx, 3, username, password, "").Err(); err == nil { - auth = true - } else if !strings.HasPrefix(err.Error(), "ERR unknown command") { - return err - } + var auth bool - _, err := conn.Pipelined(ctx, func(pipe Pipeliner) error { - if !auth && password != "" { - if username != "" { - pipe.AuthACL(ctx, username, password) - } else { - pipe.Auth(ctx, password) - } + // For redis-server < 6.0 that does not support the Hello command, + // we continue to provide services with RESP2. + if err := conn.Hello(ctx, 3, username, password, "").Err(); err == nil { + auth = true + } else if !strings.HasPrefix(err.Error(), "ERR unknown command") { + return err } - if c.opt.DB > 0 { - pipe.Select(ctx, c.opt.DB) - } + _, err := conn.Pipelined(ctx, func(pipe Pipeliner) error { + if !auth && password != "" { + if username != "" { + pipe.AuthACL(ctx, username, password) + } else { + pipe.Auth(ctx, password) + } + } - if c.opt.readOnly { - pipe.ReadOnly(ctx) - } + if c.opt.DB > 0 { + pipe.Select(ctx, c.opt.DB) + } - return nil - }) - if err != nil { - return err + if c.opt.readOnly { + pipe.ReadOnly(ctx) + } + + return nil + }) + if err != nil { + return err + } } if c.opt.OnConnect != nil {