github.com/gitbundle/modules@v0.0.0-20231025071548-85b91c5c3b01/nosql/redis.go (about)

     1  // Copyright 2023 The GitBundle Inc. All rights reserved.
     2  // Copyright 2017 The Gitea Authors. All rights reserved.
     3  // Use of this source code is governed by a MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package nosql
     7  
     8  import (
     9  	"net/url"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  // The file contains common redis connection functions
    15  
    16  // ToRedisURI converts old style connections to a RedisURI
    17  //
    18  // A RedisURI matches the pattern:
    19  //
    20  // redis://[username:password@]host[:port][/database][?[option=value]*]
    21  // rediss://[username:password@]host[:port][/database][?[option=value]*]
    22  // redis+socket://[username:password@]path[/database][?[option=value]*]
    23  // redis+sentinel://[password@]host1 [: port1][, host2 [:port2]][, hostN [:portN]][/ database][?[option=value]*]
    24  // redis+cluster://[password@]host1 [: port1][, host2 [:port2]][, hostN [:portN]][/ database][?[option=value]*]
    25  //
    26  // We have previously used a URI like:
    27  // addrs=127.0.0.1:6379 db=0
    28  // network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
    29  //
    30  // We need to convert this old style to the new style
    31  func ToRedisURI(connection string) *url.URL {
    32  	uri, err := url.Parse(connection)
    33  	if err == nil && strings.HasPrefix(uri.Scheme, "redis") {
    34  		// OK we're going to assume that this is a reasonable redis URI
    35  		return uri
    36  	}
    37  
    38  	// Let's set a nice default
    39  	uri, _ = url.Parse("redis://127.0.0.1:6379/0")
    40  	network := "tcp"
    41  	query := uri.Query()
    42  
    43  	// OK so there are two types: Space delimited and Comma delimited
    44  	// Let's assume that we have a space delimited string - as this is the most common
    45  	fields := strings.Fields(connection)
    46  	if len(fields) == 1 {
    47  		// It's a comma delimited string, then...
    48  		fields = strings.Split(connection, ",")
    49  	}
    50  	for _, f := range fields {
    51  		items := strings.SplitN(f, "=", 2)
    52  		if len(items) < 2 {
    53  			continue
    54  		}
    55  		switch strings.ToLower(items[0]) {
    56  		case "network":
    57  			if items[1] == "unix" {
    58  				uri.Scheme = "redis+socket"
    59  			}
    60  			network = items[1]
    61  		case "addrs":
    62  			uri.Host = items[1]
    63  			// now we need to handle the clustering
    64  			if strings.Contains(items[1], ",") && network == "tcp" {
    65  				uri.Scheme = "redis+cluster"
    66  			}
    67  		case "addr":
    68  			uri.Host = items[1]
    69  		case "password":
    70  			uri.User = url.UserPassword(uri.User.Username(), items[1])
    71  		case "username":
    72  			password, set := uri.User.Password()
    73  			if !set {
    74  				uri.User = url.User(items[1])
    75  			} else {
    76  				uri.User = url.UserPassword(items[1], password)
    77  			}
    78  		case "db":
    79  			uri.Path = "/" + items[1]
    80  		case "idle_timeout":
    81  			_, err := strconv.Atoi(items[1])
    82  			if err == nil {
    83  				query.Add("idle_timeout", items[1]+"s")
    84  			} else {
    85  				query.Add("idle_timeout", items[1])
    86  			}
    87  		default:
    88  			// Other options become query params
    89  			query.Add(items[0], items[1])
    90  		}
    91  	}
    92  
    93  	// Finally we need to fix up the Host if we have a unix port
    94  	if uri.Scheme == "redis+socket" {
    95  		query.Set("db", uri.Path)
    96  		uri.Path = uri.Host
    97  		uri.Host = ""
    98  	}
    99  	uri.RawQuery = query.Encode()
   100  
   101  	return uri
   102  }