mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Move deps from _workspace/ to vendor/
godep restore pushd $GOPATH/src/github.com/appc/spec git co master popd go get go4.org/errorutil rm -rf Godeps godep save ./... git add vendor git add -f $(git ls-files --other vendor/) git co -- Godeps/LICENSES Godeps/.license_file_state Godeps/OWNERS
This commit is contained in:
		
							
								
								
									
										45
									
								
								vendor/github.com/garyburd/redigo/internal/commandinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								vendor/github.com/garyburd/redigo/internal/commandinfo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| // Copyright 2014 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package internal | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	WatchState = 1 << iota | ||||
| 	MultiState | ||||
| 	SubscribeState | ||||
| 	MonitorState | ||||
| ) | ||||
|  | ||||
| type CommandInfo struct { | ||||
| 	Set, Clear int | ||||
| } | ||||
|  | ||||
| var commandInfos = map[string]CommandInfo{ | ||||
| 	"WATCH":      {Set: WatchState}, | ||||
| 	"UNWATCH":    {Clear: WatchState}, | ||||
| 	"MULTI":      {Set: MultiState}, | ||||
| 	"EXEC":       {Clear: WatchState | MultiState}, | ||||
| 	"DISCARD":    {Clear: WatchState | MultiState}, | ||||
| 	"PSUBSCRIBE": {Set: SubscribeState}, | ||||
| 	"SUBSCRIBE":  {Set: SubscribeState}, | ||||
| 	"MONITOR":    {Set: MonitorState}, | ||||
| } | ||||
|  | ||||
| func LookupCommandInfo(commandName string) CommandInfo { | ||||
| 	return commandInfos[strings.ToUpper(commandName)] | ||||
| } | ||||
							
								
								
									
										65
									
								
								vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/garyburd/redigo/internal/redistest/testdb.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| // Copyright 2014 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| // Package redistest contains utilities for writing Redigo tests. | ||||
| package redistest | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/garyburd/redigo/redis" | ||||
| ) | ||||
|  | ||||
| type testConn struct { | ||||
| 	redis.Conn | ||||
| } | ||||
|  | ||||
| func (t testConn) Close() error { | ||||
| 	_, err := t.Conn.Do("SELECT", "9") | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	_, err = t.Conn.Do("FLUSHDB") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return t.Conn.Close() | ||||
| } | ||||
|  | ||||
| // Dial dials the local Redis server and selects database 9. To prevent | ||||
| // stomping on real data, DialTestDB fails if database 9 contains data. The | ||||
| // returned connection flushes database 9 on close. | ||||
| func Dial() (redis.Conn, error) { | ||||
| 	c, err := redis.DialTimeout("tcp", ":6379", 0, 1*time.Second, 1*time.Second) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	_, err = c.Do("SELECT", "9") | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	n, err := redis.Int(c.Do("DBSIZE")) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if n != 0 { | ||||
| 		return nil, errors.New("database #9 is not empty, test can not continue") | ||||
| 	} | ||||
|  | ||||
| 	return testConn{c}, nil | ||||
| } | ||||
							
								
								
									
										455
									
								
								vendor/github.com/garyburd/redigo/redis/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										455
									
								
								vendor/github.com/garyburd/redigo/redis/conn.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,455 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // conn is the low-level implementation of Conn | ||||
| type conn struct { | ||||
|  | ||||
| 	// Shared | ||||
| 	mu      sync.Mutex | ||||
| 	pending int | ||||
| 	err     error | ||||
| 	conn    net.Conn | ||||
|  | ||||
| 	// Read | ||||
| 	readTimeout time.Duration | ||||
| 	br          *bufio.Reader | ||||
|  | ||||
| 	// Write | ||||
| 	writeTimeout time.Duration | ||||
| 	bw           *bufio.Writer | ||||
|  | ||||
| 	// Scratch space for formatting argument length. | ||||
| 	// '*' or '$', length, "\r\n" | ||||
| 	lenScratch [32]byte | ||||
|  | ||||
| 	// Scratch space for formatting integers and floats. | ||||
| 	numScratch [40]byte | ||||
| } | ||||
|  | ||||
| // Dial connects to the Redis server at the given network and address. | ||||
| func Dial(network, address string) (Conn, error) { | ||||
| 	dialer := xDialer{} | ||||
| 	return dialer.Dial(network, address) | ||||
| } | ||||
|  | ||||
| // DialTimeout acts like Dial but takes timeouts for establishing the | ||||
| // connection to the server, writing a command and reading a reply. | ||||
| func DialTimeout(network, address string, connectTimeout, readTimeout, writeTimeout time.Duration) (Conn, error) { | ||||
| 	netDialer := net.Dialer{Timeout: connectTimeout} | ||||
| 	dialer := xDialer{ | ||||
| 		NetDial:      netDialer.Dial, | ||||
| 		ReadTimeout:  readTimeout, | ||||
| 		WriteTimeout: writeTimeout, | ||||
| 	} | ||||
| 	return dialer.Dial(network, address) | ||||
| } | ||||
|  | ||||
| // A Dialer specifies options for connecting to a Redis server. | ||||
| type xDialer struct { | ||||
| 	// NetDial specifies the dial function for creating TCP connections. If | ||||
| 	// NetDial is nil, then net.Dial is used. | ||||
| 	NetDial func(network, addr string) (net.Conn, error) | ||||
|  | ||||
| 	// ReadTimeout specifies the timeout for reading a single command | ||||
| 	// reply. If ReadTimeout is zero, then no timeout is used. | ||||
| 	ReadTimeout time.Duration | ||||
|  | ||||
| 	// WriteTimeout specifies the timeout for writing a single command.  If | ||||
| 	// WriteTimeout is zero, then no timeout is used. | ||||
| 	WriteTimeout time.Duration | ||||
| } | ||||
|  | ||||
| // Dial connects to the Redis server at address on the named network. | ||||
| func (d *xDialer) Dial(network, address string) (Conn, error) { | ||||
| 	dial := d.NetDial | ||||
| 	if dial == nil { | ||||
| 		dial = net.Dial | ||||
| 	} | ||||
| 	netConn, err := dial(network, address) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &conn{ | ||||
| 		conn:         netConn, | ||||
| 		bw:           bufio.NewWriter(netConn), | ||||
| 		br:           bufio.NewReader(netConn), | ||||
| 		readTimeout:  d.ReadTimeout, | ||||
| 		writeTimeout: d.WriteTimeout, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // NewConn returns a new Redigo connection for the given net connection. | ||||
| func NewConn(netConn net.Conn, readTimeout, writeTimeout time.Duration) Conn { | ||||
| 	return &conn{ | ||||
| 		conn:         netConn, | ||||
| 		bw:           bufio.NewWriter(netConn), | ||||
| 		br:           bufio.NewReader(netConn), | ||||
| 		readTimeout:  readTimeout, | ||||
| 		writeTimeout: writeTimeout, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *conn) Close() error { | ||||
| 	c.mu.Lock() | ||||
| 	err := c.err | ||||
| 	if c.err == nil { | ||||
| 		c.err = errors.New("redigo: closed") | ||||
| 		err = c.conn.Close() | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) fatal(err error) error { | ||||
| 	c.mu.Lock() | ||||
| 	if c.err == nil { | ||||
| 		c.err = err | ||||
| 		// Close connection to force errors on subsequent calls and to unblock | ||||
| 		// other reader or writer. | ||||
| 		c.conn.Close() | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) Err() error { | ||||
| 	c.mu.Lock() | ||||
| 	err := c.err | ||||
| 	c.mu.Unlock() | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) writeLen(prefix byte, n int) error { | ||||
| 	c.lenScratch[len(c.lenScratch)-1] = '\n' | ||||
| 	c.lenScratch[len(c.lenScratch)-2] = '\r' | ||||
| 	i := len(c.lenScratch) - 3 | ||||
| 	for { | ||||
| 		c.lenScratch[i] = byte('0' + n%10) | ||||
| 		i -= 1 | ||||
| 		n = n / 10 | ||||
| 		if n == 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	c.lenScratch[i] = prefix | ||||
| 	_, err := c.bw.Write(c.lenScratch[i:]) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) writeString(s string) error { | ||||
| 	c.writeLen('$', len(s)) | ||||
| 	c.bw.WriteString(s) | ||||
| 	_, err := c.bw.WriteString("\r\n") | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) writeBytes(p []byte) error { | ||||
| 	c.writeLen('$', len(p)) | ||||
| 	c.bw.Write(p) | ||||
| 	_, err := c.bw.WriteString("\r\n") | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *conn) writeInt64(n int64) error { | ||||
| 	return c.writeBytes(strconv.AppendInt(c.numScratch[:0], n, 10)) | ||||
| } | ||||
|  | ||||
| func (c *conn) writeFloat64(n float64) error { | ||||
| 	return c.writeBytes(strconv.AppendFloat(c.numScratch[:0], n, 'g', -1, 64)) | ||||
| } | ||||
|  | ||||
| func (c *conn) writeCommand(cmd string, args []interface{}) (err error) { | ||||
| 	c.writeLen('*', 1+len(args)) | ||||
| 	err = c.writeString(cmd) | ||||
| 	for _, arg := range args { | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 		switch arg := arg.(type) { | ||||
| 		case string: | ||||
| 			err = c.writeString(arg) | ||||
| 		case []byte: | ||||
| 			err = c.writeBytes(arg) | ||||
| 		case int: | ||||
| 			err = c.writeInt64(int64(arg)) | ||||
| 		case int64: | ||||
| 			err = c.writeInt64(arg) | ||||
| 		case float64: | ||||
| 			err = c.writeFloat64(arg) | ||||
| 		case bool: | ||||
| 			if arg { | ||||
| 				err = c.writeString("1") | ||||
| 			} else { | ||||
| 				err = c.writeString("0") | ||||
| 			} | ||||
| 		case nil: | ||||
| 			err = c.writeString("") | ||||
| 		default: | ||||
| 			var buf bytes.Buffer | ||||
| 			fmt.Fprint(&buf, arg) | ||||
| 			err = c.writeBytes(buf.Bytes()) | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type protocolError string | ||||
|  | ||||
| func (pe protocolError) Error() string { | ||||
| 	return fmt.Sprintf("redigo: %s (possible server error or unsupported concurrent read by application)", string(pe)) | ||||
| } | ||||
|  | ||||
| func (c *conn) readLine() ([]byte, error) { | ||||
| 	p, err := c.br.ReadSlice('\n') | ||||
| 	if err == bufio.ErrBufferFull { | ||||
| 		return nil, protocolError("long response line") | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	i := len(p) - 2 | ||||
| 	if i < 0 || p[i] != '\r' { | ||||
| 		return nil, protocolError("bad response line terminator") | ||||
| 	} | ||||
| 	return p[:i], nil | ||||
| } | ||||
|  | ||||
| // parseLen parses bulk string and array lengths. | ||||
| func parseLen(p []byte) (int, error) { | ||||
| 	if len(p) == 0 { | ||||
| 		return -1, protocolError("malformed length") | ||||
| 	} | ||||
|  | ||||
| 	if p[0] == '-' && len(p) == 2 && p[1] == '1' { | ||||
| 		// handle $-1 and $-1 null replies. | ||||
| 		return -1, nil | ||||
| 	} | ||||
|  | ||||
| 	var n int | ||||
| 	for _, b := range p { | ||||
| 		n *= 10 | ||||
| 		if b < '0' || b > '9' { | ||||
| 			return -1, protocolError("illegal bytes in length") | ||||
| 		} | ||||
| 		n += int(b - '0') | ||||
| 	} | ||||
|  | ||||
| 	return n, nil | ||||
| } | ||||
|  | ||||
| // parseInt parses an integer reply. | ||||
| func parseInt(p []byte) (interface{}, error) { | ||||
| 	if len(p) == 0 { | ||||
| 		return 0, protocolError("malformed integer") | ||||
| 	} | ||||
|  | ||||
| 	var negate bool | ||||
| 	if p[0] == '-' { | ||||
| 		negate = true | ||||
| 		p = p[1:] | ||||
| 		if len(p) == 0 { | ||||
| 			return 0, protocolError("malformed integer") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var n int64 | ||||
| 	for _, b := range p { | ||||
| 		n *= 10 | ||||
| 		if b < '0' || b > '9' { | ||||
| 			return 0, protocolError("illegal bytes in length") | ||||
| 		} | ||||
| 		n += int64(b - '0') | ||||
| 	} | ||||
|  | ||||
| 	if negate { | ||||
| 		n = -n | ||||
| 	} | ||||
| 	return n, nil | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	okReply   interface{} = "OK" | ||||
| 	pongReply interface{} = "PONG" | ||||
| ) | ||||
|  | ||||
| func (c *conn) readReply() (interface{}, error) { | ||||
| 	line, err := c.readLine() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(line) == 0 { | ||||
| 		return nil, protocolError("short response line") | ||||
| 	} | ||||
| 	switch line[0] { | ||||
| 	case '+': | ||||
| 		switch { | ||||
| 		case len(line) == 3 && line[1] == 'O' && line[2] == 'K': | ||||
| 			// Avoid allocation for frequent "+OK" response. | ||||
| 			return okReply, nil | ||||
| 		case len(line) == 5 && line[1] == 'P' && line[2] == 'O' && line[3] == 'N' && line[4] == 'G': | ||||
| 			// Avoid allocation in PING command benchmarks :) | ||||
| 			return pongReply, nil | ||||
| 		default: | ||||
| 			return string(line[1:]), nil | ||||
| 		} | ||||
| 	case '-': | ||||
| 		return Error(string(line[1:])), nil | ||||
| 	case ':': | ||||
| 		return parseInt(line[1:]) | ||||
| 	case '$': | ||||
| 		n, err := parseLen(line[1:]) | ||||
| 		if n < 0 || err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		p := make([]byte, n) | ||||
| 		_, err = io.ReadFull(c.br, p) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if line, err := c.readLine(); err != nil { | ||||
| 			return nil, err | ||||
| 		} else if len(line) != 0 { | ||||
| 			return nil, protocolError("bad bulk string format") | ||||
| 		} | ||||
| 		return p, nil | ||||
| 	case '*': | ||||
| 		n, err := parseLen(line[1:]) | ||||
| 		if n < 0 || err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		r := make([]interface{}, n) | ||||
| 		for i := range r { | ||||
| 			r[i], err = c.readReply() | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 		} | ||||
| 		return r, nil | ||||
| 	} | ||||
| 	return nil, protocolError("unexpected response line") | ||||
| } | ||||
|  | ||||
| func (c *conn) Send(cmd string, args ...interface{}) error { | ||||
| 	c.mu.Lock() | ||||
| 	c.pending += 1 | ||||
| 	c.mu.Unlock() | ||||
| 	if c.writeTimeout != 0 { | ||||
| 		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) | ||||
| 	} | ||||
| 	if err := c.writeCommand(cmd, args); err != nil { | ||||
| 		return c.fatal(err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *conn) Flush() error { | ||||
| 	if c.writeTimeout != 0 { | ||||
| 		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) | ||||
| 	} | ||||
| 	if err := c.bw.Flush(); err != nil { | ||||
| 		return c.fatal(err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *conn) Receive() (reply interface{}, err error) { | ||||
| 	if c.readTimeout != 0 { | ||||
| 		c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)) | ||||
| 	} | ||||
| 	if reply, err = c.readReply(); err != nil { | ||||
| 		return nil, c.fatal(err) | ||||
| 	} | ||||
| 	// When using pub/sub, the number of receives can be greater than the | ||||
| 	// number of sends. To enable normal use of the connection after | ||||
| 	// unsubscribing from all channels, we do not decrement pending to a | ||||
| 	// negative value. | ||||
| 	// | ||||
| 	// The pending field is decremented after the reply is read to handle the | ||||
| 	// case where Receive is called before Send. | ||||
| 	c.mu.Lock() | ||||
| 	if c.pending > 0 { | ||||
| 		c.pending -= 1 | ||||
| 	} | ||||
| 	c.mu.Unlock() | ||||
| 	if err, ok := reply.(Error); ok { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) { | ||||
| 	c.mu.Lock() | ||||
| 	pending := c.pending | ||||
| 	c.pending = 0 | ||||
| 	c.mu.Unlock() | ||||
|  | ||||
| 	if cmd == "" && pending == 0 { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	if c.writeTimeout != 0 { | ||||
| 		c.conn.SetWriteDeadline(time.Now().Add(c.writeTimeout)) | ||||
| 	} | ||||
|  | ||||
| 	if cmd != "" { | ||||
| 		c.writeCommand(cmd, args) | ||||
| 	} | ||||
|  | ||||
| 	if err := c.bw.Flush(); err != nil { | ||||
| 		return nil, c.fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	if c.readTimeout != 0 { | ||||
| 		c.conn.SetReadDeadline(time.Now().Add(c.readTimeout)) | ||||
| 	} | ||||
|  | ||||
| 	if cmd == "" { | ||||
| 		reply := make([]interface{}, pending) | ||||
| 		for i := range reply { | ||||
| 			r, e := c.readReply() | ||||
| 			if e != nil { | ||||
| 				return nil, c.fatal(e) | ||||
| 			} | ||||
| 			reply[i] = r | ||||
| 		} | ||||
| 		return reply, nil | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var reply interface{} | ||||
| 	for i := 0; i <= pending; i++ { | ||||
| 		var e error | ||||
| 		if reply, e = c.readReply(); e != nil { | ||||
| 			return nil, c.fatal(e) | ||||
| 		} | ||||
| 		if e, ok := reply.(Error); ok && err == nil { | ||||
| 			err = e | ||||
| 		} | ||||
| 	} | ||||
| 	return reply, err | ||||
| } | ||||
							
								
								
									
										169
									
								
								vendor/github.com/garyburd/redigo/redis/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								vendor/github.com/garyburd/redigo/redis/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| // Package redis is a client for the Redis database. | ||||
| // | ||||
| // The Redigo FAQ (https://github.com/garyburd/redigo/wiki/FAQ) contains more | ||||
| // documentation about this package. | ||||
| // | ||||
| // Connections | ||||
| // | ||||
| // The Conn interface is the primary interface for working with Redis. | ||||
| // Applications create connections by calling the Dial, DialWithTimeout or | ||||
| // NewConn functions. In the future, functions will be added for creating | ||||
| // sharded and other types of connections. | ||||
| // | ||||
| // The application must call the connection Close method when the application | ||||
| // is done with the connection. | ||||
| // | ||||
| // Executing Commands | ||||
| // | ||||
| // The Conn interface has a generic method for executing Redis commands: | ||||
| // | ||||
| //  Do(commandName string, args ...interface{}) (reply interface{}, err error) | ||||
| // | ||||
| // The Redis command reference (http://redis.io/commands) lists the available | ||||
| // commands. An example of using the Redis APPEND command is: | ||||
| // | ||||
| //  n, err := conn.Do("APPEND", "key", "value") | ||||
| // | ||||
| // The Do method converts command arguments to binary strings for transmission | ||||
| // to the server as follows: | ||||
| // | ||||
| //  Go Type                 Conversion | ||||
| //  []byte                  Sent as is | ||||
| //  string                  Sent as is | ||||
| //  int, int64              strconv.FormatInt(v) | ||||
| //  float64                 strconv.FormatFloat(v, 'g', -1, 64) | ||||
| //  bool                    true -> "1", false -> "0" | ||||
| //  nil                     "" | ||||
| //  all other types         fmt.Print(v) | ||||
| // | ||||
| // Redis command reply types are represented using the following Go types: | ||||
| // | ||||
| //  Redis type              Go type | ||||
| //  error                   redis.Error | ||||
| //  integer                 int64 | ||||
| //  simple string           string | ||||
| //  bulk string             []byte or nil if value not present. | ||||
| //  array                   []interface{} or nil if value not present. | ||||
| // | ||||
| // Use type assertions or the reply helper functions to convert from | ||||
| // interface{} to the specific Go type for the command result. | ||||
| // | ||||
| // Pipelining | ||||
| // | ||||
| // Connections support pipelining using the Send, Flush and Receive methods. | ||||
| // | ||||
| //  Send(commandName string, args ...interface{}) error | ||||
| //  Flush() error | ||||
| //  Receive() (reply interface{}, err error) | ||||
| // | ||||
| // Send writes the command to the connection's output buffer. Flush flushes the | ||||
| // connection's output buffer to the server. Receive reads a single reply from | ||||
| // the server. The following example shows a simple pipeline. | ||||
| // | ||||
| //  c.Send("SET", "foo", "bar") | ||||
| //  c.Send("GET", "foo") | ||||
| //  c.Flush() | ||||
| //  c.Receive() // reply from SET | ||||
| //  v, err = c.Receive() // reply from GET | ||||
| // | ||||
| // The Do method combines the functionality of the Send, Flush and Receive | ||||
| // methods. The Do method starts by writing the command and flushing the output | ||||
| // buffer. Next, the Do method receives all pending replies including the reply | ||||
| // for the command just sent by Do. If any of the received replies is an error, | ||||
| // then Do returns the error. If there are no errors, then Do returns the last | ||||
| // reply. If the command argument to the Do method is "", then the Do method | ||||
| // will flush the output buffer and receive pending replies without sending a | ||||
| // command. | ||||
| // | ||||
| // Use the Send and Do methods to implement pipelined transactions. | ||||
| // | ||||
| //  c.Send("MULTI") | ||||
| //  c.Send("INCR", "foo") | ||||
| //  c.Send("INCR", "bar") | ||||
| //  r, err := c.Do("EXEC") | ||||
| //  fmt.Println(r) // prints [1, 1] | ||||
| // | ||||
| // Concurrency | ||||
| // | ||||
| // Connections do not support concurrent calls to the write methods (Send, | ||||
| // Flush) or concurrent calls to the read method (Receive). Connections do | ||||
| // allow a concurrent reader and writer. | ||||
| // | ||||
| // Because the Do method combines the functionality of Send, Flush and Receive, | ||||
| // the Do method cannot be called concurrently with the other methods. | ||||
| // | ||||
| // For full concurrent access to Redis, use the thread-safe Pool to get and | ||||
| // release connections from within a goroutine. | ||||
| // | ||||
| // Publish and Subscribe | ||||
| // | ||||
| // Use the Send, Flush and Receive methods to implement Pub/Sub subscribers. | ||||
| // | ||||
| //  c.Send("SUBSCRIBE", "example") | ||||
| //  c.Flush() | ||||
| //  for { | ||||
| //      reply, err := c.Receive() | ||||
| //      if err != nil { | ||||
| //          return err | ||||
| //      } | ||||
| //      // process pushed message | ||||
| //  } | ||||
| // | ||||
| // The PubSubConn type wraps a Conn with convenience methods for implementing | ||||
| // subscribers. The Subscribe, PSubscribe, Unsubscribe and PUnsubscribe methods | ||||
| // send and flush a subscription management command. The receive method | ||||
| // converts a pushed message to convenient types for use in a type switch. | ||||
| // | ||||
| //  psc := redis.PubSubConn{c} | ||||
| //  psc.Subscribe("example") | ||||
| //  for { | ||||
| //      switch v := psc.Receive().(type) { | ||||
| //      case redis.Message: | ||||
| //          fmt.Printf("%s: message: %s\n", v.Channel, v.Data) | ||||
| //      case redis.Subscription: | ||||
| //          fmt.Printf("%s: %s %d\n", v.Channel, v.Kind, v.Count) | ||||
| //      case error: | ||||
| //          return v | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| // Reply Helpers | ||||
| // | ||||
| // The Bool, Int, Bytes, String, Strings and Values functions convert a reply | ||||
| // to a value of a specific type. To allow convenient wrapping of calls to the | ||||
| // connection Do and Receive methods, the functions take a second argument of | ||||
| // type error.  If the error is non-nil, then the helper function returns the | ||||
| // error. If the error is nil, the function converts the reply to the specified | ||||
| // type: | ||||
| // | ||||
| //  exists, err := redis.Bool(c.Do("EXISTS", "foo")) | ||||
| //  if err != nil { | ||||
| //      // handle error return from c.Do or type conversion error. | ||||
| //  } | ||||
| // | ||||
| // The Scan function converts elements of a array reply to Go types: | ||||
| // | ||||
| //  var value1 int | ||||
| //  var value2 string | ||||
| //  reply, err := redis.Values(c.Do("MGET", "key1", "key2")) | ||||
| //  if err != nil { | ||||
| //      // handle error | ||||
| //  } | ||||
| //   if _, err := redis.Scan(reply, &value1, &value2); err != nil { | ||||
| //      // handle error | ||||
| //  } | ||||
| package redis | ||||
							
								
								
									
										117
									
								
								vendor/github.com/garyburd/redigo/redis/log.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								vendor/github.com/garyburd/redigo/redis/log.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,117 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| ) | ||||
|  | ||||
| // NewLoggingConn returns a logging wrapper around a connection. | ||||
| func NewLoggingConn(conn Conn, logger *log.Logger, prefix string) Conn { | ||||
| 	if prefix != "" { | ||||
| 		prefix = prefix + "." | ||||
| 	} | ||||
| 	return &loggingConn{conn, logger, prefix} | ||||
| } | ||||
|  | ||||
| type loggingConn struct { | ||||
| 	Conn | ||||
| 	logger *log.Logger | ||||
| 	prefix string | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) Close() error { | ||||
| 	err := c.Conn.Close() | ||||
| 	var buf bytes.Buffer | ||||
| 	fmt.Fprintf(&buf, "%sClose() -> (%v)", c.prefix, err) | ||||
| 	c.logger.Output(2, buf.String()) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) printValue(buf *bytes.Buffer, v interface{}) { | ||||
| 	const chop = 32 | ||||
| 	switch v := v.(type) { | ||||
| 	case []byte: | ||||
| 		if len(v) > chop { | ||||
| 			fmt.Fprintf(buf, "%q...", v[:chop]) | ||||
| 		} else { | ||||
| 			fmt.Fprintf(buf, "%q", v) | ||||
| 		} | ||||
| 	case string: | ||||
| 		if len(v) > chop { | ||||
| 			fmt.Fprintf(buf, "%q...", v[:chop]) | ||||
| 		} else { | ||||
| 			fmt.Fprintf(buf, "%q", v) | ||||
| 		} | ||||
| 	case []interface{}: | ||||
| 		if len(v) == 0 { | ||||
| 			buf.WriteString("[]") | ||||
| 		} else { | ||||
| 			sep := "[" | ||||
| 			fin := "]" | ||||
| 			if len(v) > chop { | ||||
| 				v = v[:chop] | ||||
| 				fin = "...]" | ||||
| 			} | ||||
| 			for _, vv := range v { | ||||
| 				buf.WriteString(sep) | ||||
| 				c.printValue(buf, vv) | ||||
| 				sep = ", " | ||||
| 			} | ||||
| 			buf.WriteString(fin) | ||||
| 		} | ||||
| 	default: | ||||
| 		fmt.Fprint(buf, v) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) print(method, commandName string, args []interface{}, reply interface{}, err error) { | ||||
| 	var buf bytes.Buffer | ||||
| 	fmt.Fprintf(&buf, "%s%s(", c.prefix, method) | ||||
| 	if method != "Receive" { | ||||
| 		buf.WriteString(commandName) | ||||
| 		for _, arg := range args { | ||||
| 			buf.WriteString(", ") | ||||
| 			c.printValue(&buf, arg) | ||||
| 		} | ||||
| 	} | ||||
| 	buf.WriteString(") -> (") | ||||
| 	if method != "Send" { | ||||
| 		c.printValue(&buf, reply) | ||||
| 		buf.WriteString(", ") | ||||
| 	} | ||||
| 	fmt.Fprintf(&buf, "%v)", err) | ||||
| 	c.logger.Output(3, buf.String()) | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) Do(commandName string, args ...interface{}) (interface{}, error) { | ||||
| 	reply, err := c.Conn.Do(commandName, args...) | ||||
| 	c.print("Do", commandName, args, reply, err) | ||||
| 	return reply, err | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) Send(commandName string, args ...interface{}) error { | ||||
| 	err := c.Conn.Send(commandName, args...) | ||||
| 	c.print("Send", commandName, args, nil, err) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *loggingConn) Receive() (interface{}, error) { | ||||
| 	reply, err := c.Conn.Receive() | ||||
| 	c.print("Receive", "", nil, reply, err) | ||||
| 	return reply, err | ||||
| } | ||||
							
								
								
									
										389
									
								
								vendor/github.com/garyburd/redigo/redis/pool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										389
									
								
								vendor/github.com/garyburd/redigo/redis/pool.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,389 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"container/list" | ||||
| 	"crypto/rand" | ||||
| 	"crypto/sha1" | ||||
| 	"errors" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/garyburd/redigo/internal" | ||||
| ) | ||||
|  | ||||
| var nowFunc = time.Now // for testing | ||||
|  | ||||
| // ErrPoolExhausted is returned from a pool connection method (Do, Send, | ||||
| // Receive, Flush, Err) when the maximum number of database connections in the | ||||
| // pool has been reached. | ||||
| var ErrPoolExhausted = errors.New("redigo: connection pool exhausted") | ||||
|  | ||||
| var ( | ||||
| 	errPoolClosed = errors.New("redigo: connection pool closed") | ||||
| 	errConnClosed = errors.New("redigo: connection closed") | ||||
| ) | ||||
|  | ||||
| // Pool maintains a pool of connections. The application calls the Get method | ||||
| // to get a connection from the pool and the connection's Close method to | ||||
| // return the connection's resources to the pool. | ||||
| // | ||||
| // The following example shows how to use a pool in a web application. The | ||||
| // application creates a pool at application startup and makes it available to | ||||
| // request handlers using a global variable. | ||||
| // | ||||
| //  func newPool(server, password string) *redis.Pool { | ||||
| //      return &redis.Pool{ | ||||
| //          MaxIdle: 3, | ||||
| //          IdleTimeout: 240 * time.Second, | ||||
| //          Dial: func () (redis.Conn, error) { | ||||
| //              c, err := redis.Dial("tcp", server) | ||||
| //              if err != nil { | ||||
| //                  return nil, err | ||||
| //              } | ||||
| //              if _, err := c.Do("AUTH", password); err != nil { | ||||
| //                  c.Close() | ||||
| //                  return nil, err | ||||
| //              } | ||||
| //              return c, err | ||||
| //          }, | ||||
| //          TestOnBorrow: func(c redis.Conn, t time.Time) error { | ||||
| //              _, err := c.Do("PING") | ||||
| //              return err | ||||
| //          }, | ||||
| //      } | ||||
| //  } | ||||
| // | ||||
| //  var ( | ||||
| //      pool *redis.Pool | ||||
| //      redisServer = flag.String("redisServer", ":6379", "") | ||||
| //      redisPassword = flag.String("redisPassword", "", "") | ||||
| //  ) | ||||
| // | ||||
| //  func main() { | ||||
| //      flag.Parse() | ||||
| //      pool = newPool(*redisServer, *redisPassword) | ||||
| //      ... | ||||
| //  } | ||||
| // | ||||
| // A request handler gets a connection from the pool and closes the connection | ||||
| // when the handler is done: | ||||
| // | ||||
| //  func serveHome(w http.ResponseWriter, r *http.Request) { | ||||
| //      conn := pool.Get() | ||||
| //      defer conn.Close() | ||||
| //      .... | ||||
| //  } | ||||
| // | ||||
| type Pool struct { | ||||
|  | ||||
| 	// Dial is an application supplied function for creating and configuring a | ||||
| 	// connection | ||||
| 	Dial func() (Conn, error) | ||||
|  | ||||
| 	// TestOnBorrow is an optional application supplied function for checking | ||||
| 	// the health of an idle connection before the connection is used again by | ||||
| 	// the application. Argument t is the time that the connection was returned | ||||
| 	// to the pool. If the function returns an error, then the connection is | ||||
| 	// closed. | ||||
| 	TestOnBorrow func(c Conn, t time.Time) error | ||||
|  | ||||
| 	// Maximum number of idle connections in the pool. | ||||
| 	MaxIdle int | ||||
|  | ||||
| 	// Maximum number of connections allocated by the pool at a given time. | ||||
| 	// When zero, there is no limit on the number of connections in the pool. | ||||
| 	MaxActive int | ||||
|  | ||||
| 	// Close connections after remaining idle for this duration. If the value | ||||
| 	// is zero, then idle connections are not closed. Applications should set | ||||
| 	// the timeout to a value less than the server's timeout. | ||||
| 	IdleTimeout time.Duration | ||||
|  | ||||
| 	// If Wait is true and the pool is at the MaxIdle limit, then Get() waits | ||||
| 	// for a connection to be returned to the pool before returning. | ||||
| 	Wait bool | ||||
|  | ||||
| 	// mu protects fields defined below. | ||||
| 	mu     sync.Mutex | ||||
| 	cond   *sync.Cond | ||||
| 	closed bool | ||||
| 	active int | ||||
|  | ||||
| 	// Stack of idleConn with most recently used at the front. | ||||
| 	idle list.List | ||||
| } | ||||
|  | ||||
| type idleConn struct { | ||||
| 	c Conn | ||||
| 	t time.Time | ||||
| } | ||||
|  | ||||
| // NewPool creates a new pool. This function is deprecated. Applications should | ||||
| // initialize the Pool fields directly as shown in example. | ||||
| func NewPool(newFn func() (Conn, error), maxIdle int) *Pool { | ||||
| 	return &Pool{Dial: newFn, MaxIdle: maxIdle} | ||||
| } | ||||
|  | ||||
| // Get gets a connection. The application must close the returned connection. | ||||
| // This method always returns a valid connection so that applications can defer | ||||
| // error handling to the first use of the connection. If there is an error | ||||
| // getting an underlying connection, then the connection Err, Do, Send, Flush | ||||
| // and Receive methods return that error. | ||||
| func (p *Pool) Get() Conn { | ||||
| 	c, err := p.get() | ||||
| 	if err != nil { | ||||
| 		return errorConnection{err} | ||||
| 	} | ||||
| 	return &pooledConnection{p: p, c: c} | ||||
| } | ||||
|  | ||||
| // ActiveCount returns the number of active connections in the pool. | ||||
| func (p *Pool) ActiveCount() int { | ||||
| 	p.mu.Lock() | ||||
| 	active := p.active | ||||
| 	p.mu.Unlock() | ||||
| 	return active | ||||
| } | ||||
|  | ||||
| // Close releases the resources used by the pool. | ||||
| func (p *Pool) Close() error { | ||||
| 	p.mu.Lock() | ||||
| 	idle := p.idle | ||||
| 	p.idle.Init() | ||||
| 	p.closed = true | ||||
| 	p.active -= idle.Len() | ||||
| 	if p.cond != nil { | ||||
| 		p.cond.Broadcast() | ||||
| 	} | ||||
| 	p.mu.Unlock() | ||||
| 	for e := idle.Front(); e != nil; e = e.Next() { | ||||
| 		e.Value.(idleConn).c.Close() | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // release decrements the active count and signals waiters. The caller must | ||||
| // hold p.mu during the call. | ||||
| func (p *Pool) release() { | ||||
| 	p.active -= 1 | ||||
| 	if p.cond != nil { | ||||
| 		p.cond.Signal() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // get prunes stale connections and returns a connection from the idle list or | ||||
| // creates a new connection. | ||||
| func (p *Pool) get() (Conn, error) { | ||||
| 	p.mu.Lock() | ||||
|  | ||||
| 	// Prune stale connections. | ||||
|  | ||||
| 	if timeout := p.IdleTimeout; timeout > 0 { | ||||
| 		for i, n := 0, p.idle.Len(); i < n; i++ { | ||||
| 			e := p.idle.Back() | ||||
| 			if e == nil { | ||||
| 				break | ||||
| 			} | ||||
| 			ic := e.Value.(idleConn) | ||||
| 			if ic.t.Add(timeout).After(nowFunc()) { | ||||
| 				break | ||||
| 			} | ||||
| 			p.idle.Remove(e) | ||||
| 			p.release() | ||||
| 			p.mu.Unlock() | ||||
| 			ic.c.Close() | ||||
| 			p.mu.Lock() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for { | ||||
|  | ||||
| 		// Get idle connection. | ||||
|  | ||||
| 		for i, n := 0, p.idle.Len(); i < n; i++ { | ||||
| 			e := p.idle.Front() | ||||
| 			if e == nil { | ||||
| 				break | ||||
| 			} | ||||
| 			ic := e.Value.(idleConn) | ||||
| 			p.idle.Remove(e) | ||||
| 			test := p.TestOnBorrow | ||||
| 			p.mu.Unlock() | ||||
| 			if test == nil || test(ic.c, ic.t) == nil { | ||||
| 				return ic.c, nil | ||||
| 			} | ||||
| 			ic.c.Close() | ||||
| 			p.mu.Lock() | ||||
| 			p.release() | ||||
| 		} | ||||
|  | ||||
| 		// Check for pool closed before dialing a new connection. | ||||
|  | ||||
| 		if p.closed { | ||||
| 			p.mu.Unlock() | ||||
| 			return nil, errors.New("redigo: get on closed pool") | ||||
| 		} | ||||
|  | ||||
| 		// Dial new connection if under limit. | ||||
|  | ||||
| 		if p.MaxActive == 0 || p.active < p.MaxActive { | ||||
| 			dial := p.Dial | ||||
| 			p.active += 1 | ||||
| 			p.mu.Unlock() | ||||
| 			c, err := dial() | ||||
| 			if err != nil { | ||||
| 				p.mu.Lock() | ||||
| 				p.release() | ||||
| 				p.mu.Unlock() | ||||
| 				c = nil | ||||
| 			} | ||||
| 			return c, err | ||||
| 		} | ||||
|  | ||||
| 		if !p.Wait { | ||||
| 			p.mu.Unlock() | ||||
| 			return nil, ErrPoolExhausted | ||||
| 		} | ||||
|  | ||||
| 		if p.cond == nil { | ||||
| 			p.cond = sync.NewCond(&p.mu) | ||||
| 		} | ||||
| 		p.cond.Wait() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (p *Pool) put(c Conn, forceClose bool) error { | ||||
| 	err := c.Err() | ||||
| 	p.mu.Lock() | ||||
| 	if !p.closed && err == nil && !forceClose { | ||||
| 		p.idle.PushFront(idleConn{t: nowFunc(), c: c}) | ||||
| 		if p.idle.Len() > p.MaxIdle { | ||||
| 			c = p.idle.Remove(p.idle.Back()).(idleConn).c | ||||
| 		} else { | ||||
| 			c = nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if c == nil { | ||||
| 		if p.cond != nil { | ||||
| 			p.cond.Signal() | ||||
| 		} | ||||
| 		p.mu.Unlock() | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	p.release() | ||||
| 	p.mu.Unlock() | ||||
| 	return c.Close() | ||||
| } | ||||
|  | ||||
| type pooledConnection struct { | ||||
| 	p     *Pool | ||||
| 	c     Conn | ||||
| 	state int | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	sentinel     []byte | ||||
| 	sentinelOnce sync.Once | ||||
| ) | ||||
|  | ||||
| func initSentinel() { | ||||
| 	p := make([]byte, 64) | ||||
| 	if _, err := rand.Read(p); err == nil { | ||||
| 		sentinel = p | ||||
| 	} else { | ||||
| 		h := sha1.New() | ||||
| 		io.WriteString(h, "Oops, rand failed. Use time instead.") | ||||
| 		io.WriteString(h, strconv.FormatInt(time.Now().UnixNano(), 10)) | ||||
| 		sentinel = h.Sum(nil) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Close() error { | ||||
| 	c := pc.c | ||||
| 	if _, ok := c.(errorConnection); ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	pc.c = errorConnection{errConnClosed} | ||||
|  | ||||
| 	if pc.state&internal.MultiState != 0 { | ||||
| 		c.Send("DISCARD") | ||||
| 		pc.state &^= (internal.MultiState | internal.WatchState) | ||||
| 	} else if pc.state&internal.WatchState != 0 { | ||||
| 		c.Send("UNWATCH") | ||||
| 		pc.state &^= internal.WatchState | ||||
| 	} | ||||
| 	if pc.state&internal.SubscribeState != 0 { | ||||
| 		c.Send("UNSUBSCRIBE") | ||||
| 		c.Send("PUNSUBSCRIBE") | ||||
| 		// To detect the end of the message stream, ask the server to echo | ||||
| 		// a sentinel value and read until we see that value. | ||||
| 		sentinelOnce.Do(initSentinel) | ||||
| 		c.Send("ECHO", sentinel) | ||||
| 		c.Flush() | ||||
| 		for { | ||||
| 			p, err := c.Receive() | ||||
| 			if err != nil { | ||||
| 				break | ||||
| 			} | ||||
| 			if p, ok := p.([]byte); ok && bytes.Equal(p, sentinel) { | ||||
| 				pc.state &^= internal.SubscribeState | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	c.Do("") | ||||
| 	pc.p.put(c, pc.state != 0) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Err() error { | ||||
| 	return pc.c.Err() | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Do(commandName string, args ...interface{}) (reply interface{}, err error) { | ||||
| 	ci := internal.LookupCommandInfo(commandName) | ||||
| 	pc.state = (pc.state | ci.Set) &^ ci.Clear | ||||
| 	return pc.c.Do(commandName, args...) | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Send(commandName string, args ...interface{}) error { | ||||
| 	ci := internal.LookupCommandInfo(commandName) | ||||
| 	pc.state = (pc.state | ci.Set) &^ ci.Clear | ||||
| 	return pc.c.Send(commandName, args...) | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Flush() error { | ||||
| 	return pc.c.Flush() | ||||
| } | ||||
|  | ||||
| func (pc *pooledConnection) Receive() (reply interface{}, err error) { | ||||
| 	return pc.c.Receive() | ||||
| } | ||||
|  | ||||
| type errorConnection struct{ err error } | ||||
|  | ||||
| func (ec errorConnection) Do(string, ...interface{}) (interface{}, error) { return nil, ec.err } | ||||
| func (ec errorConnection) Send(string, ...interface{}) error              { return ec.err } | ||||
| func (ec errorConnection) Err() error                                     { return ec.err } | ||||
| func (ec errorConnection) Close() error                                   { return ec.err } | ||||
| func (ec errorConnection) Flush() error                                   { return ec.err } | ||||
| func (ec errorConnection) Receive() (interface{}, error)                  { return nil, ec.err } | ||||
							
								
								
									
										129
									
								
								vendor/github.com/garyburd/redigo/redis/pubsub.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								vendor/github.com/garyburd/redigo/redis/pubsub.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,129 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| ) | ||||
|  | ||||
| // Subscription represents a subscribe or unsubscribe notification. | ||||
| type Subscription struct { | ||||
|  | ||||
| 	// Kind is "subscribe", "unsubscribe", "psubscribe" or "punsubscribe" | ||||
| 	Kind string | ||||
|  | ||||
| 	// The channel that was changed. | ||||
| 	Channel string | ||||
|  | ||||
| 	// The current number of subscriptions for connection. | ||||
| 	Count int | ||||
| } | ||||
|  | ||||
| // Message represents a message notification. | ||||
| type Message struct { | ||||
|  | ||||
| 	// The originating channel. | ||||
| 	Channel string | ||||
|  | ||||
| 	// The message data. | ||||
| 	Data []byte | ||||
| } | ||||
|  | ||||
| // PMessage represents a pmessage notification. | ||||
| type PMessage struct { | ||||
|  | ||||
| 	// The matched pattern. | ||||
| 	Pattern string | ||||
|  | ||||
| 	// The originating channel. | ||||
| 	Channel string | ||||
|  | ||||
| 	// The message data. | ||||
| 	Data []byte | ||||
| } | ||||
|  | ||||
| // PubSubConn wraps a Conn with convenience methods for subscribers. | ||||
| type PubSubConn struct { | ||||
| 	Conn Conn | ||||
| } | ||||
|  | ||||
| // Close closes the connection. | ||||
| func (c PubSubConn) Close() error { | ||||
| 	return c.Conn.Close() | ||||
| } | ||||
|  | ||||
| // Subscribe subscribes the connection to the specified channels. | ||||
| func (c PubSubConn) Subscribe(channel ...interface{}) error { | ||||
| 	c.Conn.Send("SUBSCRIBE", channel...) | ||||
| 	return c.Conn.Flush() | ||||
| } | ||||
|  | ||||
| // PSubscribe subscribes the connection to the given patterns. | ||||
| func (c PubSubConn) PSubscribe(channel ...interface{}) error { | ||||
| 	c.Conn.Send("PSUBSCRIBE", channel...) | ||||
| 	return c.Conn.Flush() | ||||
| } | ||||
|  | ||||
| // Unsubscribe unsubscribes the connection from the given channels, or from all | ||||
| // of them if none is given. | ||||
| func (c PubSubConn) Unsubscribe(channel ...interface{}) error { | ||||
| 	c.Conn.Send("UNSUBSCRIBE", channel...) | ||||
| 	return c.Conn.Flush() | ||||
| } | ||||
|  | ||||
| // PUnsubscribe unsubscribes the connection from the given patterns, or from all | ||||
| // of them if none is given. | ||||
| func (c PubSubConn) PUnsubscribe(channel ...interface{}) error { | ||||
| 	c.Conn.Send("PUNSUBSCRIBE", channel...) | ||||
| 	return c.Conn.Flush() | ||||
| } | ||||
|  | ||||
| // Receive returns a pushed message as a Subscription, Message, PMessage or | ||||
| // error. The return value is intended to be used directly in a type switch as | ||||
| // illustrated in the PubSubConn example. | ||||
| func (c PubSubConn) Receive() interface{} { | ||||
| 	reply, err := Values(c.Conn.Receive()) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var kind string | ||||
| 	reply, err = Scan(reply, &kind) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	switch kind { | ||||
| 	case "message": | ||||
| 		var m Message | ||||
| 		if _, err := Scan(reply, &m.Channel, &m.Data); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return m | ||||
| 	case "pmessage": | ||||
| 		var pm PMessage | ||||
| 		if _, err := Scan(reply, &pm.Pattern, &pm.Channel, &pm.Data); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return pm | ||||
| 	case "subscribe", "psubscribe", "unsubscribe", "punsubscribe": | ||||
| 		s := Subscription{Kind: kind} | ||||
| 		if _, err := Scan(reply, &s.Channel, &s.Count); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return s | ||||
| 	} | ||||
| 	return errors.New("redigo: unknown pubsub notification") | ||||
| } | ||||
							
								
								
									
										44
									
								
								vendor/github.com/garyburd/redigo/redis/redis.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								vendor/github.com/garyburd/redigo/redis/redis.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| // Error represents an error returned in a command reply. | ||||
| type Error string | ||||
|  | ||||
| func (err Error) Error() string { return string(err) } | ||||
|  | ||||
| // Conn represents a connection to a Redis server. | ||||
| type Conn interface { | ||||
| 	// Close closes the connection. | ||||
| 	Close() error | ||||
|  | ||||
| 	// Err returns a non-nil value if the connection is broken. The returned | ||||
| 	// value is either the first non-nil value returned from the underlying | ||||
| 	// network connection or a protocol parsing error. Applications should | ||||
| 	// close broken connections. | ||||
| 	Err() error | ||||
|  | ||||
| 	// Do sends a command to the server and returns the received reply. | ||||
| 	Do(commandName string, args ...interface{}) (reply interface{}, err error) | ||||
|  | ||||
| 	// Send writes the command to the client's output buffer. | ||||
| 	Send(commandName string, args ...interface{}) error | ||||
|  | ||||
| 	// Flush flushes the output buffer to the Redis server. | ||||
| 	Flush() error | ||||
|  | ||||
| 	// Receive receives a single reply from the Redis server | ||||
| 	Receive() (reply interface{}, err error) | ||||
| } | ||||
							
								
								
									
										312
									
								
								vendor/github.com/garyburd/redigo/redis/reply.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										312
									
								
								vendor/github.com/garyburd/redigo/redis/reply.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,312 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // ErrNil indicates that a reply value is nil. | ||||
| var ErrNil = errors.New("redigo: nil returned") | ||||
|  | ||||
| // Int is a helper that converts a command reply to an integer. If err is not | ||||
| // equal to nil, then Int returns 0, err. Otherwise, Int converts the | ||||
| // reply to an int as follows: | ||||
| // | ||||
| //  Reply type    Result | ||||
| //  integer       int(reply), nil | ||||
| //  bulk string   parsed reply, nil | ||||
| //  nil           0, ErrNil | ||||
| //  other         0, error | ||||
| func Int(reply interface{}, err error) (int, error) { | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case int64: | ||||
| 		x := int(reply) | ||||
| 		if int64(x) != reply { | ||||
| 			return 0, strconv.ErrRange | ||||
| 		} | ||||
| 		return x, nil | ||||
| 	case []byte: | ||||
| 		n, err := strconv.ParseInt(string(reply), 10, 0) | ||||
| 		return int(n), err | ||||
| 	case nil: | ||||
| 		return 0, ErrNil | ||||
| 	case Error: | ||||
| 		return 0, reply | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("redigo: unexpected type for Int, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Int64 is a helper that converts a command reply to 64 bit integer. If err is | ||||
| // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the | ||||
| // reply to an int64 as follows: | ||||
| // | ||||
| //  Reply type    Result | ||||
| //  integer       reply, nil | ||||
| //  bulk string   parsed reply, nil | ||||
| //  nil           0, ErrNil | ||||
| //  other         0, error | ||||
| func Int64(reply interface{}, err error) (int64, error) { | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case int64: | ||||
| 		return reply, nil | ||||
| 	case []byte: | ||||
| 		n, err := strconv.ParseInt(string(reply), 10, 64) | ||||
| 		return n, err | ||||
| 	case nil: | ||||
| 		return 0, ErrNil | ||||
| 	case Error: | ||||
| 		return 0, reply | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("redigo: unexpected type for Int64, got type %T", reply) | ||||
| } | ||||
|  | ||||
| var errNegativeInt = errors.New("redigo: unexpected value for Uint64") | ||||
|  | ||||
| // Uint64 is a helper that converts a command reply to 64 bit integer. If err is | ||||
| // not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the | ||||
| // reply to an int64 as follows: | ||||
| // | ||||
| //  Reply type    Result | ||||
| //  integer       reply, nil | ||||
| //  bulk string   parsed reply, nil | ||||
| //  nil           0, ErrNil | ||||
| //  other         0, error | ||||
| func Uint64(reply interface{}, err error) (uint64, error) { | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case int64: | ||||
| 		if reply < 0 { | ||||
| 			return 0, errNegativeInt | ||||
| 		} | ||||
| 		return uint64(reply), nil | ||||
| 	case []byte: | ||||
| 		n, err := strconv.ParseUint(string(reply), 10, 64) | ||||
| 		return n, err | ||||
| 	case nil: | ||||
| 		return 0, ErrNil | ||||
| 	case Error: | ||||
| 		return 0, reply | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("redigo: unexpected type for Uint64, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Float64 is a helper that converts a command reply to 64 bit float. If err is | ||||
| // not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts | ||||
| // the reply to an int as follows: | ||||
| // | ||||
| //  Reply type    Result | ||||
| //  bulk string   parsed reply, nil | ||||
| //  nil           0, ErrNil | ||||
| //  other         0, error | ||||
| func Float64(reply interface{}, err error) (float64, error) { | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case []byte: | ||||
| 		n, err := strconv.ParseFloat(string(reply), 64) | ||||
| 		return n, err | ||||
| 	case nil: | ||||
| 		return 0, ErrNil | ||||
| 	case Error: | ||||
| 		return 0, reply | ||||
| 	} | ||||
| 	return 0, fmt.Errorf("redigo: unexpected type for Float64, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // String is a helper that converts a command reply to a string. If err is not | ||||
| // equal to nil, then String returns "", err. Otherwise String converts the | ||||
| // reply to a string as follows: | ||||
| // | ||||
| //  Reply type      Result | ||||
| //  bulk string     string(reply), nil | ||||
| //  simple string   reply, nil | ||||
| //  nil             "",  ErrNil | ||||
| //  other           "",  error | ||||
| func String(reply interface{}, err error) (string, error) { | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case []byte: | ||||
| 		return string(reply), nil | ||||
| 	case string: | ||||
| 		return reply, nil | ||||
| 	case nil: | ||||
| 		return "", ErrNil | ||||
| 	case Error: | ||||
| 		return "", reply | ||||
| 	} | ||||
| 	return "", fmt.Errorf("redigo: unexpected type for String, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Bytes is a helper that converts a command reply to a slice of bytes. If err | ||||
| // is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts | ||||
| // the reply to a slice of bytes as follows: | ||||
| // | ||||
| //  Reply type      Result | ||||
| //  bulk string     reply, nil | ||||
| //  simple string   []byte(reply), nil | ||||
| //  nil             nil, ErrNil | ||||
| //  other           nil, error | ||||
| func Bytes(reply interface{}, err error) ([]byte, error) { | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case []byte: | ||||
| 		return reply, nil | ||||
| 	case string: | ||||
| 		return []byte(reply), nil | ||||
| 	case nil: | ||||
| 		return nil, ErrNil | ||||
| 	case Error: | ||||
| 		return nil, reply | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("redigo: unexpected type for Bytes, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Bool is a helper that converts a command reply to a boolean. If err is not | ||||
| // equal to nil, then Bool returns false, err. Otherwise Bool converts the | ||||
| // reply to boolean as follows: | ||||
| // | ||||
| //  Reply type      Result | ||||
| //  integer         value != 0, nil | ||||
| //  bulk string     strconv.ParseBool(reply) | ||||
| //  nil             false, ErrNil | ||||
| //  other           false, error | ||||
| func Bool(reply interface{}, err error) (bool, error) { | ||||
| 	if err != nil { | ||||
| 		return false, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case int64: | ||||
| 		return reply != 0, nil | ||||
| 	case []byte: | ||||
| 		return strconv.ParseBool(string(reply)) | ||||
| 	case nil: | ||||
| 		return false, ErrNil | ||||
| 	case Error: | ||||
| 		return false, reply | ||||
| 	} | ||||
| 	return false, fmt.Errorf("redigo: unexpected type for Bool, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // MultiBulk is deprecated. Use Values. | ||||
| func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) } | ||||
|  | ||||
| // Values is a helper that converts an array command reply to a []interface{}. | ||||
| // If err is not equal to nil, then Values returns nil, err. Otherwise, Values | ||||
| // converts the reply as follows: | ||||
| // | ||||
| //  Reply type      Result | ||||
| //  array           reply, nil | ||||
| //  nil             nil, ErrNil | ||||
| //  other           nil, error | ||||
| func Values(reply interface{}, err error) ([]interface{}, error) { | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case []interface{}: | ||||
| 		return reply, nil | ||||
| 	case nil: | ||||
| 		return nil, ErrNil | ||||
| 	case Error: | ||||
| 		return nil, reply | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("redigo: unexpected type for Values, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Strings is a helper that converts an array command reply to a []string. If | ||||
| // err is not equal to nil, then Strings returns nil, err. Nil array items are | ||||
| // converted to "" in the output slice. Strings returns an error if an array | ||||
| // item is not a bulk string or nil. | ||||
| func Strings(reply interface{}, err error) ([]string, error) { | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	switch reply := reply.(type) { | ||||
| 	case []interface{}: | ||||
| 		result := make([]string, len(reply)) | ||||
| 		for i := range reply { | ||||
| 			if reply[i] == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			p, ok := reply[i].([]byte) | ||||
| 			if !ok { | ||||
| 				return nil, fmt.Errorf("redigo: unexpected element type for Strings, got type %T", reply[i]) | ||||
| 			} | ||||
| 			result[i] = string(p) | ||||
| 		} | ||||
| 		return result, nil | ||||
| 	case nil: | ||||
| 		return nil, ErrNil | ||||
| 	case Error: | ||||
| 		return nil, reply | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("redigo: unexpected type for Strings, got type %T", reply) | ||||
| } | ||||
|  | ||||
| // Ints is a helper that converts an array command reply to a []int. If | ||||
| // err is not equal to nil, then Ints returns nil, err. | ||||
| func Ints(reply interface{}, err error) ([]int, error) { | ||||
| 	var ints []int | ||||
| 	if reply == nil { | ||||
| 		return ints, ErrNil | ||||
| 	} | ||||
| 	values, err := Values(reply, err) | ||||
| 	if err != nil { | ||||
| 		return ints, err | ||||
| 	} | ||||
| 	if err := ScanSlice(values, &ints); err != nil { | ||||
| 		return ints, err | ||||
| 	} | ||||
| 	return ints, nil | ||||
| } | ||||
|  | ||||
| // StringMap is a helper that converts an array of strings (alternating key, value) | ||||
| // into a map[string]string. The HGETALL and CONFIG GET commands return replies in this format. | ||||
| // Requires an even number of values in result. | ||||
| func StringMap(result interface{}, err error) (map[string]string, error) { | ||||
| 	values, err := Values(result, err) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if len(values)%2 != 0 { | ||||
| 		return nil, errors.New("redigo: StringMap expects even number of values result") | ||||
| 	} | ||||
| 	m := make(map[string]string, len(values)/2) | ||||
| 	for i := 0; i < len(values); i += 2 { | ||||
| 		key, okKey := values[i].([]byte) | ||||
| 		value, okValue := values[i+1].([]byte) | ||||
| 		if !okKey || !okValue { | ||||
| 			return nil, errors.New("redigo: ScanMap key not a bulk string value") | ||||
| 		} | ||||
| 		m[string(key)] = string(value) | ||||
| 	} | ||||
| 	return m, nil | ||||
| } | ||||
							
								
								
									
										513
									
								
								vendor/github.com/garyburd/redigo/redis/scan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								vendor/github.com/garyburd/redigo/redis/scan.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,513 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| ) | ||||
|  | ||||
| func ensureLen(d reflect.Value, n int) { | ||||
| 	if n > d.Cap() { | ||||
| 		d.Set(reflect.MakeSlice(d.Type(), n, n)) | ||||
| 	} else { | ||||
| 		d.SetLen(n) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func cannotConvert(d reflect.Value, s interface{}) error { | ||||
| 	return fmt.Errorf("redigo: Scan cannot convert from %s to %s", | ||||
| 		reflect.TypeOf(s), d.Type()) | ||||
| } | ||||
|  | ||||
| func convertAssignBytes(d reflect.Value, s []byte) (err error) { | ||||
| 	switch d.Type().Kind() { | ||||
| 	case reflect.Float32, reflect.Float64: | ||||
| 		var x float64 | ||||
| 		x, err = strconv.ParseFloat(string(s), d.Type().Bits()) | ||||
| 		d.SetFloat(x) | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		var x int64 | ||||
| 		x, err = strconv.ParseInt(string(s), 10, d.Type().Bits()) | ||||
| 		d.SetInt(x) | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 		var x uint64 | ||||
| 		x, err = strconv.ParseUint(string(s), 10, d.Type().Bits()) | ||||
| 		d.SetUint(x) | ||||
| 	case reflect.Bool: | ||||
| 		var x bool | ||||
| 		x, err = strconv.ParseBool(string(s)) | ||||
| 		d.SetBool(x) | ||||
| 	case reflect.String: | ||||
| 		d.SetString(string(s)) | ||||
| 	case reflect.Slice: | ||||
| 		if d.Type().Elem().Kind() != reflect.Uint8 { | ||||
| 			err = cannotConvert(d, s) | ||||
| 		} else { | ||||
| 			d.SetBytes(s) | ||||
| 		} | ||||
| 	default: | ||||
| 		err = cannotConvert(d, s) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func convertAssignInt(d reflect.Value, s int64) (err error) { | ||||
| 	switch d.Type().Kind() { | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		d.SetInt(s) | ||||
| 		if d.Int() != s { | ||||
| 			err = strconv.ErrRange | ||||
| 			d.SetInt(0) | ||||
| 		} | ||||
| 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: | ||||
| 		if s < 0 { | ||||
| 			err = strconv.ErrRange | ||||
| 		} else { | ||||
| 			x := uint64(s) | ||||
| 			d.SetUint(x) | ||||
| 			if d.Uint() != x { | ||||
| 				err = strconv.ErrRange | ||||
| 				d.SetUint(0) | ||||
| 			} | ||||
| 		} | ||||
| 	case reflect.Bool: | ||||
| 		d.SetBool(s != 0) | ||||
| 	default: | ||||
| 		err = cannotConvert(d, s) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func convertAssignValue(d reflect.Value, s interface{}) (err error) { | ||||
| 	switch s := s.(type) { | ||||
| 	case []byte: | ||||
| 		err = convertAssignBytes(d, s) | ||||
| 	case int64: | ||||
| 		err = convertAssignInt(d, s) | ||||
| 	default: | ||||
| 		err = cannotConvert(d, s) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func convertAssignValues(d reflect.Value, s []interface{}) error { | ||||
| 	if d.Type().Kind() != reflect.Slice { | ||||
| 		return cannotConvert(d, s) | ||||
| 	} | ||||
| 	ensureLen(d, len(s)) | ||||
| 	for i := 0; i < len(s); i++ { | ||||
| 		if err := convertAssignValue(d.Index(i), s[i]); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func convertAssign(d interface{}, s interface{}) (err error) { | ||||
| 	// Handle the most common destination types using type switches and | ||||
| 	// fall back to reflection for all other types. | ||||
| 	switch s := s.(type) { | ||||
| 	case nil: | ||||
| 		// ingore | ||||
| 	case []byte: | ||||
| 		switch d := d.(type) { | ||||
| 		case *string: | ||||
| 			*d = string(s) | ||||
| 		case *int: | ||||
| 			*d, err = strconv.Atoi(string(s)) | ||||
| 		case *bool: | ||||
| 			*d, err = strconv.ParseBool(string(s)) | ||||
| 		case *[]byte: | ||||
| 			*d = s | ||||
| 		case *interface{}: | ||||
| 			*d = s | ||||
| 		case nil: | ||||
| 			// skip value | ||||
| 		default: | ||||
| 			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { | ||||
| 				err = cannotConvert(d, s) | ||||
| 			} else { | ||||
| 				err = convertAssignBytes(d.Elem(), s) | ||||
| 			} | ||||
| 		} | ||||
| 	case int64: | ||||
| 		switch d := d.(type) { | ||||
| 		case *int: | ||||
| 			x := int(s) | ||||
| 			if int64(x) != s { | ||||
| 				err = strconv.ErrRange | ||||
| 				x = 0 | ||||
| 			} | ||||
| 			*d = x | ||||
| 		case *bool: | ||||
| 			*d = s != 0 | ||||
| 		case *interface{}: | ||||
| 			*d = s | ||||
| 		case nil: | ||||
| 			// skip value | ||||
| 		default: | ||||
| 			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { | ||||
| 				err = cannotConvert(d, s) | ||||
| 			} else { | ||||
| 				err = convertAssignInt(d.Elem(), s) | ||||
| 			} | ||||
| 		} | ||||
| 	case []interface{}: | ||||
| 		switch d := d.(type) { | ||||
| 		case *[]interface{}: | ||||
| 			*d = s | ||||
| 		case *interface{}: | ||||
| 			*d = s | ||||
| 		case nil: | ||||
| 			// skip value | ||||
| 		default: | ||||
| 			if d := reflect.ValueOf(d); d.Type().Kind() != reflect.Ptr { | ||||
| 				err = cannotConvert(d, s) | ||||
| 			} else { | ||||
| 				err = convertAssignValues(d.Elem(), s) | ||||
| 			} | ||||
| 		} | ||||
| 	case Error: | ||||
| 		err = s | ||||
| 	default: | ||||
| 		err = cannotConvert(reflect.ValueOf(d), s) | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // Scan copies from src to the values pointed at by dest. | ||||
| // | ||||
| // The values pointed at by dest must be an integer, float, boolean, string, | ||||
| // []byte, interface{} or slices of these types. Scan uses the standard strconv | ||||
| // package to convert bulk strings to numeric and boolean types. | ||||
| // | ||||
| // If a dest value is nil, then the corresponding src value is skipped. | ||||
| // | ||||
| // If a src element is nil, then the corresponding dest value is not modified. | ||||
| // | ||||
| // To enable easy use of Scan in a loop, Scan returns the slice of src | ||||
| // following the copied values. | ||||
| func Scan(src []interface{}, dest ...interface{}) ([]interface{}, error) { | ||||
| 	if len(src) < len(dest) { | ||||
| 		return nil, errors.New("redigo: Scan array short") | ||||
| 	} | ||||
| 	var err error | ||||
| 	for i, d := range dest { | ||||
| 		err = convertAssign(d, src[i]) | ||||
| 		if err != nil { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	return src[len(dest):], err | ||||
| } | ||||
|  | ||||
| type fieldSpec struct { | ||||
| 	name  string | ||||
| 	index []int | ||||
| 	//omitEmpty bool | ||||
| } | ||||
|  | ||||
| type structSpec struct { | ||||
| 	m map[string]*fieldSpec | ||||
| 	l []*fieldSpec | ||||
| } | ||||
|  | ||||
| func (ss *structSpec) fieldSpec(name []byte) *fieldSpec { | ||||
| 	return ss.m[string(name)] | ||||
| } | ||||
|  | ||||
| func compileStructSpec(t reflect.Type, depth map[string]int, index []int, ss *structSpec) { | ||||
| 	for i := 0; i < t.NumField(); i++ { | ||||
| 		f := t.Field(i) | ||||
| 		switch { | ||||
| 		case f.PkgPath != "": | ||||
| 			// Ignore unexported fields. | ||||
| 		case f.Anonymous: | ||||
| 			// TODO: Handle pointers. Requires change to decoder and | ||||
| 			// protection against infinite recursion. | ||||
| 			if f.Type.Kind() == reflect.Struct { | ||||
| 				compileStructSpec(f.Type, depth, append(index, i), ss) | ||||
| 			} | ||||
| 		default: | ||||
| 			fs := &fieldSpec{name: f.Name} | ||||
| 			tag := f.Tag.Get("redis") | ||||
| 			p := strings.Split(tag, ",") | ||||
| 			if len(p) > 0 { | ||||
| 				if p[0] == "-" { | ||||
| 					continue | ||||
| 				} | ||||
| 				if len(p[0]) > 0 { | ||||
| 					fs.name = p[0] | ||||
| 				} | ||||
| 				for _, s := range p[1:] { | ||||
| 					switch s { | ||||
| 					//case "omitempty": | ||||
| 					//  fs.omitempty = true | ||||
| 					default: | ||||
| 						panic(errors.New("redigo: unknown field flag " + s + " for type " + t.Name())) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			d, found := depth[fs.name] | ||||
| 			if !found { | ||||
| 				d = 1 << 30 | ||||
| 			} | ||||
| 			switch { | ||||
| 			case len(index) == d: | ||||
| 				// At same depth, remove from result. | ||||
| 				delete(ss.m, fs.name) | ||||
| 				j := 0 | ||||
| 				for i := 0; i < len(ss.l); i++ { | ||||
| 					if fs.name != ss.l[i].name { | ||||
| 						ss.l[j] = ss.l[i] | ||||
| 						j += 1 | ||||
| 					} | ||||
| 				} | ||||
| 				ss.l = ss.l[:j] | ||||
| 			case len(index) < d: | ||||
| 				fs.index = make([]int, len(index)+1) | ||||
| 				copy(fs.index, index) | ||||
| 				fs.index[len(index)] = i | ||||
| 				depth[fs.name] = len(index) | ||||
| 				ss.m[fs.name] = fs | ||||
| 				ss.l = append(ss.l, fs) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	structSpecMutex  sync.RWMutex | ||||
| 	structSpecCache  = make(map[reflect.Type]*structSpec) | ||||
| 	defaultFieldSpec = &fieldSpec{} | ||||
| ) | ||||
|  | ||||
| func structSpecForType(t reflect.Type) *structSpec { | ||||
|  | ||||
| 	structSpecMutex.RLock() | ||||
| 	ss, found := structSpecCache[t] | ||||
| 	structSpecMutex.RUnlock() | ||||
| 	if found { | ||||
| 		return ss | ||||
| 	} | ||||
|  | ||||
| 	structSpecMutex.Lock() | ||||
| 	defer structSpecMutex.Unlock() | ||||
| 	ss, found = structSpecCache[t] | ||||
| 	if found { | ||||
| 		return ss | ||||
| 	} | ||||
|  | ||||
| 	ss = &structSpec{m: make(map[string]*fieldSpec)} | ||||
| 	compileStructSpec(t, make(map[string]int), nil, ss) | ||||
| 	structSpecCache[t] = ss | ||||
| 	return ss | ||||
| } | ||||
|  | ||||
| var errScanStructValue = errors.New("redigo: ScanStruct value must be non-nil pointer to a struct") | ||||
|  | ||||
| // ScanStruct scans alternating names and values from src to a struct. The | ||||
| // HGETALL and CONFIG GET commands return replies in this format. | ||||
| // | ||||
| // ScanStruct uses exported field names to match values in the response. Use | ||||
| // 'redis' field tag to override the name: | ||||
| // | ||||
| //      Field int `redis:"myName"` | ||||
| // | ||||
| // Fields with the tag redis:"-" are ignored. | ||||
| // | ||||
| // Integer, float, boolean, string and []byte fields are supported. Scan uses the | ||||
| // standard strconv package to convert bulk string values to numeric and | ||||
| // boolean types. | ||||
| // | ||||
| // If a src element is nil, then the corresponding field is not modified. | ||||
| func ScanStruct(src []interface{}, dest interface{}) error { | ||||
| 	d := reflect.ValueOf(dest) | ||||
| 	if d.Kind() != reflect.Ptr || d.IsNil() { | ||||
| 		return errScanStructValue | ||||
| 	} | ||||
| 	d = d.Elem() | ||||
| 	if d.Kind() != reflect.Struct { | ||||
| 		return errScanStructValue | ||||
| 	} | ||||
| 	ss := structSpecForType(d.Type()) | ||||
|  | ||||
| 	if len(src)%2 != 0 { | ||||
| 		return errors.New("redigo: ScanStruct expects even number of values in values") | ||||
| 	} | ||||
|  | ||||
| 	for i := 0; i < len(src); i += 2 { | ||||
| 		s := src[i+1] | ||||
| 		if s == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		name, ok := src[i].([]byte) | ||||
| 		if !ok { | ||||
| 			return errors.New("redigo: ScanStruct key not a bulk string value") | ||||
| 		} | ||||
| 		fs := ss.fieldSpec(name) | ||||
| 		if fs == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	errScanSliceValue = errors.New("redigo: ScanSlice dest must be non-nil pointer to a struct") | ||||
| ) | ||||
|  | ||||
| // ScanSlice scans src to the slice pointed to by dest. The elements the dest | ||||
| // slice must be integer, float, boolean, string, struct or pointer to struct | ||||
| // values. | ||||
| // | ||||
| // Struct fields must be integer, float, boolean or string values. All struct | ||||
| // fields are used unless a subset is specified using fieldNames. | ||||
| func ScanSlice(src []interface{}, dest interface{}, fieldNames ...string) error { | ||||
| 	d := reflect.ValueOf(dest) | ||||
| 	if d.Kind() != reflect.Ptr || d.IsNil() { | ||||
| 		return errScanSliceValue | ||||
| 	} | ||||
| 	d = d.Elem() | ||||
| 	if d.Kind() != reflect.Slice { | ||||
| 		return errScanSliceValue | ||||
| 	} | ||||
|  | ||||
| 	isPtr := false | ||||
| 	t := d.Type().Elem() | ||||
| 	if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { | ||||
| 		isPtr = true | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
|  | ||||
| 	if t.Kind() != reflect.Struct { | ||||
| 		ensureLen(d, len(src)) | ||||
| 		for i, s := range src { | ||||
| 			if s == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if err := convertAssignValue(d.Index(i), s); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	ss := structSpecForType(t) | ||||
| 	fss := ss.l | ||||
| 	if len(fieldNames) > 0 { | ||||
| 		fss = make([]*fieldSpec, len(fieldNames)) | ||||
| 		for i, name := range fieldNames { | ||||
| 			fss[i] = ss.m[name] | ||||
| 			if fss[i] == nil { | ||||
| 				return errors.New("redigo: ScanSlice bad field name " + name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(fss) == 0 { | ||||
| 		return errors.New("redigo: ScanSlice no struct fields") | ||||
| 	} | ||||
|  | ||||
| 	n := len(src) / len(fss) | ||||
| 	if n*len(fss) != len(src) { | ||||
| 		return errors.New("redigo: ScanSlice length not a multiple of struct field count") | ||||
| 	} | ||||
|  | ||||
| 	ensureLen(d, n) | ||||
| 	for i := 0; i < n; i++ { | ||||
| 		d := d.Index(i) | ||||
| 		if isPtr { | ||||
| 			if d.IsNil() { | ||||
| 				d.Set(reflect.New(t)) | ||||
| 			} | ||||
| 			d = d.Elem() | ||||
| 		} | ||||
| 		for j, fs := range fss { | ||||
| 			s := src[i*len(fss)+j] | ||||
| 			if s == nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			if err := convertAssignValue(d.FieldByIndex(fs.index), s); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Args is a helper for constructing command arguments from structured values. | ||||
| type Args []interface{} | ||||
|  | ||||
| // Add returns the result of appending value to args. | ||||
| func (args Args) Add(value ...interface{}) Args { | ||||
| 	return append(args, value...) | ||||
| } | ||||
|  | ||||
| // AddFlat returns the result of appending the flattened value of v to args. | ||||
| // | ||||
| // Maps are flattened by appending the alternating keys and map values to args. | ||||
| // | ||||
| // Slices are flattened by appending the slice elements to args. | ||||
| // | ||||
| // Structs are flattened by appending the alternating names and values of | ||||
| // exported fields to args. If v is a nil struct pointer, then nothing is | ||||
| // appended. The 'redis' field tag overrides struct field names. See ScanStruct | ||||
| // for more information on the use of the 'redis' field tag. | ||||
| // | ||||
| // Other types are appended to args as is. | ||||
| func (args Args) AddFlat(v interface{}) Args { | ||||
| 	rv := reflect.ValueOf(v) | ||||
| 	switch rv.Kind() { | ||||
| 	case reflect.Struct: | ||||
| 		args = flattenStruct(args, rv) | ||||
| 	case reflect.Slice: | ||||
| 		for i := 0; i < rv.Len(); i++ { | ||||
| 			args = append(args, rv.Index(i).Interface()) | ||||
| 		} | ||||
| 	case reflect.Map: | ||||
| 		for _, k := range rv.MapKeys() { | ||||
| 			args = append(args, k.Interface(), rv.MapIndex(k).Interface()) | ||||
| 		} | ||||
| 	case reflect.Ptr: | ||||
| 		if rv.Type().Elem().Kind() == reflect.Struct { | ||||
| 			if !rv.IsNil() { | ||||
| 				args = flattenStruct(args, rv.Elem()) | ||||
| 			} | ||||
| 		} else { | ||||
| 			args = append(args, v) | ||||
| 		} | ||||
| 	default: | ||||
| 		args = append(args, v) | ||||
| 	} | ||||
| 	return args | ||||
| } | ||||
|  | ||||
| func flattenStruct(args Args, v reflect.Value) Args { | ||||
| 	ss := structSpecForType(v.Type()) | ||||
| 	for _, fs := range ss.l { | ||||
| 		fv := v.FieldByIndex(fs.index) | ||||
| 		args = append(args, fs.name, fv.Interface()) | ||||
| 	} | ||||
| 	return args | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/github.com/garyburd/redigo/redis/script.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/garyburd/redigo/redis/script.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| // Copyright 2012 Gary Burd | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package redis | ||||
|  | ||||
| import ( | ||||
| 	"crypto/sha1" | ||||
| 	"encoding/hex" | ||||
| 	"io" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // Script encapsulates the source, hash and key count for a Lua script. See | ||||
| // http://redis.io/commands/eval for information on scripts in Redis. | ||||
| type Script struct { | ||||
| 	keyCount int | ||||
| 	src      string | ||||
| 	hash     string | ||||
| } | ||||
|  | ||||
| // NewScript returns a new script object. If keyCount is greater than or equal | ||||
| // to zero, then the count is automatically inserted in the EVAL command | ||||
| // argument list. If keyCount is less than zero, then the application supplies | ||||
| // the count as the first value in the keysAndArgs argument to the Do, Send and | ||||
| // SendHash methods. | ||||
| func NewScript(keyCount int, src string) *Script { | ||||
| 	h := sha1.New() | ||||
| 	io.WriteString(h, src) | ||||
| 	return &Script{keyCount, src, hex.EncodeToString(h.Sum(nil))} | ||||
| } | ||||
|  | ||||
| func (s *Script) args(spec string, keysAndArgs []interface{}) []interface{} { | ||||
| 	var args []interface{} | ||||
| 	if s.keyCount < 0 { | ||||
| 		args = make([]interface{}, 1+len(keysAndArgs)) | ||||
| 		args[0] = spec | ||||
| 		copy(args[1:], keysAndArgs) | ||||
| 	} else { | ||||
| 		args = make([]interface{}, 2+len(keysAndArgs)) | ||||
| 		args[0] = spec | ||||
| 		args[1] = s.keyCount | ||||
| 		copy(args[2:], keysAndArgs) | ||||
| 	} | ||||
| 	return args | ||||
| } | ||||
|  | ||||
| // Do evaluates the script. Under the covers, Do optimistically evaluates the | ||||
| // script using the EVALSHA command. If the command fails because the script is | ||||
| // not loaded, then Do evaluates the script using the EVAL command (thus | ||||
| // causing the script to load). | ||||
| func (s *Script) Do(c Conn, keysAndArgs ...interface{}) (interface{}, error) { | ||||
| 	v, err := c.Do("EVALSHA", s.args(s.hash, keysAndArgs)...) | ||||
| 	if e, ok := err.(Error); ok && strings.HasPrefix(string(e), "NOSCRIPT ") { | ||||
| 		v, err = c.Do("EVAL", s.args(s.src, keysAndArgs)...) | ||||
| 	} | ||||
| 	return v, err | ||||
| } | ||||
|  | ||||
| // SendHash evaluates the script without waiting for the reply. The script is | ||||
| // evaluated with the EVALSHA command. The application must ensure that the | ||||
| // script is loaded by a previous call to Send, Do or Load methods. | ||||
| func (s *Script) SendHash(c Conn, keysAndArgs ...interface{}) error { | ||||
| 	return c.Send("EVALSHA", s.args(s.hash, keysAndArgs)...) | ||||
| } | ||||
|  | ||||
| // Send evaluates the script without waiting for the reply. | ||||
| func (s *Script) Send(c Conn, keysAndArgs ...interface{}) error { | ||||
| 	return c.Send("EVAL", s.args(s.src, keysAndArgs)...) | ||||
| } | ||||
|  | ||||
| // Load loads the script without evaluating it. | ||||
| func (s *Script) Load(c Conn) error { | ||||
| 	_, err := c.Do("SCRIPT", "LOAD", s.src) | ||||
| 	return err | ||||
| } | ||||
		Reference in New Issue
	
	Block a user