forked from mirror/redis
Add unix socket connection by url stirng. (#1511)
* add unix connectin by url string
This commit is contained in:
parent
3e42145a26
commit
d31cf6c328
67
options.go
67
options.go
|
@ -29,6 +29,7 @@ type Limiter interface {
|
||||||
ReportResult(result error)
|
ReportResult(result error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Options keeps the settings to setup redis connection.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// The network type, either tcp or unix.
|
// The network type, either tcp or unix.
|
||||||
// Default is tcp.
|
// Default is tcp.
|
||||||
|
@ -187,23 +188,32 @@ func (opt *Options) clone() *Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseURL parses an URL into Options that can be used to connect to Redis.
|
// ParseURL parses an URL into Options that can be used to connect to Redis.
|
||||||
|
// Scheme is required.
|
||||||
|
// There are two connection types: by tcp socket and by unix socket.
|
||||||
|
// Tcp connection:
|
||||||
|
// redis://<user>:<password>@<host>:<port>/<db_number>
|
||||||
|
// Unix connection:
|
||||||
|
// unix://<user>:<password>@</path/to/redis.sock>?db=<db_number>
|
||||||
func ParseURL(redisURL string) (*Options, error) {
|
func ParseURL(redisURL string) (*Options, error) {
|
||||||
o := &Options{Network: "tcp"}
|
|
||||||
u, err := url.Parse(redisURL)
|
u, err := url.Parse(redisURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.Scheme != "redis" && u.Scheme != "rediss" {
|
switch u.Scheme {
|
||||||
return nil, errors.New("invalid redis URL scheme: " + u.Scheme)
|
case "redis", "rediss":
|
||||||
|
return setupTCPConn(u)
|
||||||
|
case "unix":
|
||||||
|
return setupUnixConn(u)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid redis URL scheme: %s", u.Scheme)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if u.User != nil {
|
func setupTCPConn(u *url.URL) (*Options, error) {
|
||||||
o.Username = u.User.Username()
|
o := &Options{Network: "tcp"}
|
||||||
if p, ok := u.User.Password(); ok {
|
|
||||||
o.Password = p
|
o.Username, o.Password = getUserPassword(u)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(u.Query()) > 0 {
|
if len(u.Query()) > 0 {
|
||||||
return nil, errors.New("no options supported")
|
return nil, errors.New("no options supported")
|
||||||
|
@ -232,15 +242,52 @@ func ParseURL(redisURL string) (*Options, error) {
|
||||||
return nil, fmt.Errorf("invalid redis database number: %q", f[0])
|
return nil, fmt.Errorf("invalid redis database number: %q", f[0])
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("invalid redis URL path: " + u.Path)
|
return nil, fmt.Errorf("invalid redis URL path: %s", u.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
if u.Scheme == "rediss" {
|
if u.Scheme == "rediss" {
|
||||||
o.TLSConfig = &tls.Config{ServerName: h}
|
o.TLSConfig = &tls.Config{ServerName: h}
|
||||||
}
|
}
|
||||||
|
|
||||||
return o, nil
|
return o, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupUnixConn(u *url.URL) (*Options, error) {
|
||||||
|
o := &Options{
|
||||||
|
Network: "unix",
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.TrimSpace(u.Path) == "" { // path is required with unix connection
|
||||||
|
return nil, errors.New("empty redis unix socket path")
|
||||||
|
}
|
||||||
|
o.Addr = u.Path
|
||||||
|
|
||||||
|
o.Username, o.Password = getUserPassword(u)
|
||||||
|
|
||||||
|
dbStr := u.Query().Get("db")
|
||||||
|
if dbStr == "" {
|
||||||
|
return o, nil // if database is not set, connect to 0 db.
|
||||||
|
}
|
||||||
|
db, err := strconv.Atoi(dbStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid reids database number: %s", err)
|
||||||
|
}
|
||||||
|
o.DB = db
|
||||||
|
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserPassword(u *url.URL) (string, string) {
|
||||||
|
var user, password string
|
||||||
|
if u.User != nil {
|
||||||
|
user = u.User.Username()
|
||||||
|
if p, ok := u.User.Password(); ok {
|
||||||
|
password = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return user, password
|
||||||
|
}
|
||||||
|
|
||||||
func newConnPool(opt *Options) *pool.ConnPool {
|
func newConnPool(opt *Options) *pool.ConnPool {
|
||||||
return pool.NewConnPool(&pool.Options{
|
return pool.NewConnPool(&pool.Options{
|
||||||
Dialer: func(ctx context.Context) (net.Conn, error) {
|
Dialer: func(ctx context.Context) (net.Conn, error) {
|
||||||
|
|
|
@ -66,6 +66,30 @@ func TestParseURL(t *testing.T) {
|
||||||
0, false, nil,
|
0, false, nil,
|
||||||
"foo", "bar",
|
"foo", "bar",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"unix:///tmp/redis.sock",
|
||||||
|
"/tmp/redis.sock",
|
||||||
|
0, false, nil,
|
||||||
|
"", "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unix://foo:bar@/tmp/redis.sock",
|
||||||
|
"/tmp/redis.sock",
|
||||||
|
0, false, nil,
|
||||||
|
"foo", "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unix://foo:bar@/tmp/redis.sock?db=3",
|
||||||
|
"/tmp/redis.sock",
|
||||||
|
3, false, nil,
|
||||||
|
"foo", "bar",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"unix://foo:bar@/tmp/redis.sock?db=test",
|
||||||
|
"/tmp/redis.sock",
|
||||||
|
0, false, errors.New("invalid reids database number: strconv.Atoi: parsing \"test\": invalid syntax"),
|
||||||
|
"", "",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"redis://localhost/?abc=123",
|
"redis://localhost/?abc=123",
|
||||||
"",
|
"",
|
||||||
|
|
Loading…
Reference in New Issue