gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
  69. 69
  70. 70
  71. 71
  72. 72
  73. 73
  74. 74
  75. 75
  76. 76
  77. 77
  78. 78
  79. 79
  80. 80
  81. 81
  82. 82
  83. 83
  84. 84
  85. 85
  86. 86
  87. 87
  88. 88
  89. 89
  90. 90
  91. 91
  92. 92
  93. 93
  94. 94
  95. 95
  96. 96
  97. 97
  98. 98
  99. 99
  100. 100
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package nosql

import (
	"net/url"
	"strconv"
	"strings"
)

// The file contains common redis connection functions

// ToRedisURI converts old style connections to a RedisURI
//
// A RedisURI matches the pattern:
//
// redis://[username:password@]host[:port][/database][?[option=value]*]
// rediss://[username:password@]host[:port][/database][?[option=value]*]
// redis+socket://[username:password@]path[/database][?[option=value]*]
// redis+sentinel://[password@]host1 [: port1][, host2 [:port2]][, hostN [:portN]][/ database][?[option=value]*]
// redis+cluster://[password@]host1 [: port1][, host2 [:port2]][, hostN [:portN]][/ database][?[option=value]*]
//
// We have previously used a URI like:
// addrs=127.0.0.1:6379 db=0
// network=tcp,addr=127.0.0.1:6379,password=macaron,db=0,pool_size=100,idle_timeout=180
//
// We need to convert this old style to the new style
func ToRedisURI(connection string) *url.URL {
	uri, err := url.Parse(connection)
	if err == nil && strings.HasPrefix(uri.Scheme, "redis") {
		// OK we're going to assume that this is a reasonable redis URI
		return uri
	}

	// Let's set a nice default
	uri, _ = url.Parse("redis://127.0.0.1:6379/0")
	network := "tcp"
	query := uri.Query()

	// OK so there are two types: Space delimited and Comma delimited
	// Let's assume that we have a space delimited string - as this is the most common
	fields := strings.Fields(connection)
	if len(fields) == 1 {
		// It's a comma delimited string, then...
		fields = strings.Split(connection, ",")
	}
	for _, f := range fields {
		items := strings.SplitN(f, "=", 2)
		if len(items) < 2 {
			continue
		}
		switch strings.ToLower(items[0]) {
		case "network":
			if items[1] == "unix" {
				uri.Scheme = "redis+socket"
			}
			network = items[1]
		case "addrs":
			uri.Host = items[1]
			// now we need to handle the clustering
			if strings.Contains(items[1], ",") && network == "tcp" {
				uri.Scheme = "redis+cluster"
			}
		case "addr":
			uri.Host = items[1]
		case "password":
			uri.User = url.UserPassword(uri.User.Username(), items[1])
		case "username":
			password, set := uri.User.Password()
			if !set {
				uri.User = url.User(items[1])
			} else {
				uri.User = url.UserPassword(items[1], password)
			}
		case "db":
			uri.Path = "/" + items[1]
		case "idle_timeout":
			_, err := strconv.Atoi(items[1])
			if err == nil {
				query.Add("idle_timeout", items[1]+"s")
			} else {
				query.Add("idle_timeout", items[1])
			}
		default:
			// Other options become query params
			query.Add(items[0], items[1])
		}
	}

	// Finally we need to fix up the Host if we have a unix port
	if uri.Scheme == "redis+socket" {
		query.Set("db", uri.Path)
		uri.Path = uri.Host
		uri.Host = ""
	}
	uri.RawQuery = query.Encode()

	return uri
}