github.com/gogf/gf@v1.16.9/database/gredis/gredis_conn.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gredis 8 9 import ( 10 "context" 11 "github.com/gomodule/redigo/redis" 12 "reflect" 13 "time" 14 15 "github.com/gogf/gf/container/gvar" 16 "github.com/gogf/gf/errors/gcode" 17 "github.com/gogf/gf/errors/gerror" 18 "github.com/gogf/gf/internal/json" 19 "github.com/gogf/gf/os/gtime" 20 "github.com/gogf/gf/util/gconv" 21 ) 22 23 // Do sends a command to the server and returns the received reply. 24 // It uses json.Marshal for struct/slice/map type values before committing them to redis. 25 // The timeout overrides the read timeout set when dialing the connection. 26 func (c *Conn) do(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error) { 27 var ( 28 reflectValue reflect.Value 29 reflectKind reflect.Kind 30 ) 31 for k, v := range args { 32 reflectValue = reflect.ValueOf(v) 33 reflectKind = reflectValue.Kind() 34 if reflectKind == reflect.Ptr { 35 reflectValue = reflectValue.Elem() 36 reflectKind = reflectValue.Kind() 37 } 38 switch reflectKind { 39 case 40 reflect.Struct, 41 reflect.Map, 42 reflect.Slice, 43 reflect.Array: 44 // Ignore slice type of: []byte. 45 if _, ok := v.([]byte); !ok { 46 if args[k], err = json.Marshal(v); err != nil { 47 return nil, err 48 } 49 } 50 } 51 } 52 if timeout > 0 { 53 conn, ok := c.Conn.(redis.ConnWithTimeout) 54 if !ok { 55 return gvar.New(nil), gerror.NewCode(gcode.CodeNotSupported, `current connection does not support "ConnWithTimeout"`) 56 } 57 return conn.DoWithTimeout(timeout, commandName, args...) 58 } 59 timestampMilli1 := gtime.TimestampMilli() 60 reply, err = c.Conn.Do(commandName, args...) 61 timestampMilli2 := gtime.TimestampMilli() 62 63 // Tracing. 64 c.addTracingItem(&tracingItem{ 65 err: err, 66 commandName: commandName, 67 arguments: args, 68 costMilli: timestampMilli2 - timestampMilli1, 69 }) 70 return 71 } 72 73 // Ctx is a channing function which sets the context for next operation. 74 func (c *Conn) Ctx(ctx context.Context) *Conn { 75 c.ctx = ctx 76 return c 77 } 78 79 // Do sends a command to the server and returns the received reply. 80 // It uses json.Marshal for struct/slice/map type values before committing them to redis. 81 func (c *Conn) Do(commandName string, args ...interface{}) (reply interface{}, err error) { 82 return c.do(0, commandName, args...) 83 } 84 85 // DoWithTimeout sends a command to the server and returns the received reply. 86 // The timeout overrides the read timeout set when dialing the connection. 87 func (c *Conn) DoWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (reply interface{}, err error) { 88 return c.do(timeout, commandName, args...) 89 } 90 91 // DoVar retrieves and returns the result from command as gvar.Var. 92 func (c *Conn) DoVar(commandName string, args ...interface{}) (*gvar.Var, error) { 93 return resultToVar(c.Do(commandName, args...)) 94 } 95 96 // DoVarWithTimeout retrieves and returns the result from command as gvar.Var. 97 // The timeout overrides the read timeout set when dialing the connection. 98 func (c *Conn) DoVarWithTimeout(timeout time.Duration, commandName string, args ...interface{}) (*gvar.Var, error) { 99 return resultToVar(c.DoWithTimeout(timeout, commandName, args...)) 100 } 101 102 // ReceiveVar receives a single reply as gvar.Var from the Redis server. 103 func (c *Conn) ReceiveVar() (*gvar.Var, error) { 104 return resultToVar(c.Receive()) 105 } 106 107 // ReceiveVarWithTimeout receives a single reply as gvar.Var from the Redis server. 108 // The timeout overrides the read timeout set when dialing the connection. 109 func (c *Conn) ReceiveVarWithTimeout(timeout time.Duration) (*gvar.Var, error) { 110 conn, ok := c.Conn.(redis.ConnWithTimeout) 111 if !ok { 112 return gvar.New(nil), gerror.NewCode(gcode.CodeNotSupported, `current connection does not support "ConnWithTimeout"`) 113 } 114 return resultToVar(conn.ReceiveWithTimeout(timeout)) 115 } 116 117 // resultToVar converts redis operation result to gvar.Var. 118 func resultToVar(result interface{}, err error) (*gvar.Var, error) { 119 if err == nil { 120 if result, ok := result.([]byte); ok { 121 return gvar.New(string(result)), err 122 } 123 // It treats all returned slice as string slice. 124 if result, ok := result.([]interface{}); ok { 125 return gvar.New(gconv.Strings(result)), err 126 } 127 } 128 return gvar.New(result), err 129 }