code.gitea.io/gitea@v1.19.3/modules/nosql/redis.go (about)

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