1package redis 2 3import ( 4 "crypto/sha1" 5 "encoding/hex" 6 "io" 7 "strings" 8) 9 10type scripter interface { 11 Eval(script string, keys []string, args ...interface{}) *Cmd 12 EvalSha(sha1 string, keys []string, args ...interface{}) *Cmd 13 ScriptExists(hashes ...string) *BoolSliceCmd 14 ScriptLoad(script string) *StringCmd 15} 16 17var _ scripter = (*Client)(nil) 18var _ scripter = (*Ring)(nil) 19var _ scripter = (*ClusterClient)(nil) 20 21type Script struct { 22 src, hash string 23} 24 25func NewScript(src string) *Script { 26 h := sha1.New() 27 _, _ = io.WriteString(h, src) 28 return &Script{ 29 src: src, 30 hash: hex.EncodeToString(h.Sum(nil)), 31 } 32} 33 34func (s *Script) Hash() string { 35 return s.hash 36} 37 38func (s *Script) Load(c scripter) *StringCmd { 39 return c.ScriptLoad(s.src) 40} 41 42func (s *Script) Exists(c scripter) *BoolSliceCmd { 43 return c.ScriptExists(s.hash) 44} 45 46func (s *Script) Eval(c scripter, keys []string, args ...interface{}) *Cmd { 47 return c.Eval(s.src, keys, args...) 48} 49 50func (s *Script) EvalSha(c scripter, keys []string, args ...interface{}) *Cmd { 51 return c.EvalSha(s.hash, keys, args...) 52} 53 54// Run optimistically uses EVALSHA to run the script. If script does not exist 55// it is retried using EVAL. 56func (s *Script) Run(c scripter, keys []string, args ...interface{}) *Cmd { 57 r := s.EvalSha(c, keys, args...) 58 if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") { 59 return s.Eval(c, keys, args...) 60 } 61 return r 62} 63