You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

config.go 7.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package client
  18. import (
  19. "flag"
  20. "fmt"
  21. "io/ioutil"
  22. "os"
  23. "path/filepath"
  24. "runtime"
  25. "strings"
  26. "github.com/knadh/koanf"
  27. "github.com/knadh/koanf/parsers/json"
  28. "github.com/knadh/koanf/parsers/toml"
  29. "github.com/knadh/koanf/parsers/yaml"
  30. "github.com/knadh/koanf/providers/rawbytes"
  31. "github.com/seata/seata-go/pkg/remoting/getty"
  32. "github.com/seata/seata-go/pkg/rm"
  33. "github.com/seata/seata-go/pkg/rm/tcc"
  34. "github.com/seata/seata-go/pkg/tm"
  35. "github.com/seata/seata-go/pkg/util/flagext"
  36. )
  37. const (
  38. configFileEnvKey = "SEATA_GO_CONFIG_PATH"
  39. configPrefix = "seata"
  40. )
  41. const (
  42. jsonSuffix = "json"
  43. tomlSuffix = "toml"
  44. yamlSuffix = "yaml"
  45. ymlSuffix = "yml"
  46. )
  47. type ClientConfig struct {
  48. TmConfig tm.TmConfig `yaml:"tm" json:"tm,omitempty" koanf:"tm"`
  49. RmConfig rm.Config `yaml:"rm" json:"rm,omitempty" koanf:"rm"`
  50. }
  51. func (c *ClientConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
  52. // TODO: Undo RegisterFlagsWithPrefix
  53. // TODO: LoadBalance RegisterFlagsWithPrefix
  54. c.TmConfig.RegisterFlagsWithPrefix(prefix+".tm", f)
  55. c.RmConfig.RegisterFlagsWithPrefix(prefix+".rm", f)
  56. }
  57. type Config struct {
  58. Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled"`
  59. ApplicationID string `yaml:"application-id" json:"application-id,omitempty" koanf:"application-id"`
  60. TxServiceGroup string `yaml:"tx-service-group" json:"tx-service-group,omitempty" koanf:"tx-service-group"`
  61. AccessKey string `yaml:"access-key" json:"access-key,omitempty" koanf:"access-key"`
  62. SecretKey string `yaml:"secret-key" json:"secret-key,omitempty" koanf:"secret-key"`
  63. EnableAutoDataSourceProxy bool `yaml:"enable-auto-data-source-proxy" json:"enable-auto-data-source-proxy,omitempty" koanf:"enable-auto-data-source-proxy"`
  64. DataSourceProxyMode string `yaml:"data-source-proxy-mode" json:"data-source-proxy-mode,omitempty" koanf:"data-source-proxy-mode"`
  65. TCCConfig tcc.Config `yaml:"tcc" json:"tcc" koanf:"tcc"`
  66. ClientConfig ClientConfig `yaml:"client" json:"client" koanf:"client"`
  67. GettyConfig getty.Config `yaml:"getty" json:"getty" koanf:"getty"`
  68. TransportConfig getty.TransportConfig `yaml:"transport" json:"transport" koanf:"transport"`
  69. ServiceConfig tm.ServiceConfig `yaml:"service" json:"service" koanf:"service"`
  70. }
  71. func (c *Config) RegisterFlags(f *flag.FlagSet) {
  72. f.BoolVar(&c.Enabled, "enabled", true, "Whether enable auto configuration.")
  73. f.StringVar(&c.ApplicationID, "application-id", "seata-go", "Application id.")
  74. f.StringVar(&c.TxServiceGroup, "tx-service-group", "default_tx_group", "Transaction service group.")
  75. f.StringVar(&c.AccessKey, "access-key", "", "Used for aliyun accessKey.")
  76. f.StringVar(&c.SecretKey, "secret-key", "", "Used for aliyun secretKey.")
  77. f.BoolVar(&c.EnableAutoDataSourceProxy, "enable-auto-data-source-proxy", true, "Whether enable auto proxying of datasource bean.")
  78. f.StringVar(&c.DataSourceProxyMode, "data-source-proxy-mode", "AT", "Data source proxy mode.")
  79. c.TCCConfig.FenceConfig.RegisterFlagsWithPrefix("tcc", f)
  80. c.ClientConfig.RegisterFlagsWithPrefix("client", f)
  81. c.GettyConfig.RegisterFlagsWithPrefix("getty", f)
  82. c.TransportConfig.RegisterFlagsWithPrefix("transport", f)
  83. c.ServiceConfig.RegisterFlagsWithPrefix("service", f)
  84. }
  85. type loaderConf struct {
  86. suffix string // loaderConf file extension default yaml
  87. path string // loaderConf file path default ./conf/seatago.yaml
  88. delim string // loaderConf file delim default .
  89. bytes []byte // config bytes
  90. name string // config file name
  91. }
  92. // Load parse config from user config path
  93. func LoadPath(configFilePath string) *Config {
  94. if configFilePath == "" {
  95. configFilePath = os.Getenv(configFileEnvKey)
  96. if configFilePath == "" {
  97. panic("system variable SEATA_GO_CONFIG_PATH is empty")
  98. }
  99. }
  100. var cfg Config
  101. // This sets default values from flags to the config.
  102. // It needs to be called before parsing the config file!
  103. flagext.RegisterFlags(&cfg)
  104. conf := newLoaderConf(configFilePath)
  105. koan := getConfigResolver(conf)
  106. if err := koan.UnmarshalWithConf(configPrefix, &cfg, koanf.UnmarshalConf{Tag: yamlSuffix}); err != nil {
  107. panic(err)
  108. }
  109. return &cfg
  110. }
  111. // Load parse config from json bytes
  112. func LoadJson(bytes []byte) *Config {
  113. var cfg Config
  114. // This sets default values from flags to the config.
  115. // It needs to be called before parsing the config file!
  116. flagext.RegisterFlags(&cfg)
  117. koan := getJsonConfigResolver(bytes)
  118. if err := koan.Unmarshal("", &cfg); err != nil {
  119. panic(err)
  120. }
  121. return &cfg
  122. }
  123. // getJsonConfigResolver get json config resolver
  124. func getJsonConfigResolver(bytes []byte) *koanf.Koanf {
  125. k := koanf.New(".")
  126. if err := k.Load(rawbytes.Provider(bytes), json.Parser()); err != nil {
  127. panic(err)
  128. }
  129. return k
  130. }
  131. // resolverFilePath resolver file path
  132. // eg: give a ./conf/seatago.yaml return seatago and yaml
  133. func resolverFilePath(path string) (name, suffix string) {
  134. paths := strings.Split(path, "/")
  135. fileName := strings.Split(paths[len(paths)-1], ".")
  136. if len(fileName) < 2 {
  137. return fileName[0], yamlSuffix
  138. }
  139. return fileName[0], fileName[1]
  140. }
  141. // getConfigResolver get config resolver
  142. func getConfigResolver(conf *loaderConf) *koanf.Koanf {
  143. var (
  144. k *koanf.Koanf
  145. err error
  146. )
  147. if len(conf.suffix) <= 0 {
  148. conf.suffix = yamlSuffix
  149. }
  150. if len(conf.delim) <= 0 {
  151. conf.delim = "."
  152. }
  153. bytes := conf.bytes
  154. if len(bytes) <= 0 {
  155. panic(fmt.Errorf("bytes is nil,please set bytes or file path"))
  156. }
  157. k = koanf.New(conf.delim)
  158. switch conf.suffix {
  159. case yamlSuffix, ymlSuffix:
  160. err = k.Load(rawbytes.Provider(bytes), yaml.Parser())
  161. case jsonSuffix:
  162. err = k.Load(rawbytes.Provider(bytes), json.Parser())
  163. case tomlSuffix:
  164. err = k.Load(rawbytes.Provider(bytes), toml.Parser())
  165. default:
  166. err = fmt.Errorf("no support %s file suffix", conf.suffix)
  167. }
  168. if err != nil {
  169. panic(err)
  170. }
  171. return k
  172. }
  173. func newLoaderConf(configFilePath string) *loaderConf {
  174. name, suffix := resolverFilePath(configFilePath)
  175. conf := &loaderConf{
  176. suffix: suffix,
  177. path: absolutePath(configFilePath),
  178. delim: ".",
  179. name: name,
  180. }
  181. if len(conf.bytes) <= 0 {
  182. if bytes, err := ioutil.ReadFile(conf.path); err != nil {
  183. panic(err)
  184. } else {
  185. conf.bytes = bytes
  186. }
  187. }
  188. return conf
  189. }
  190. // absolutePath get absolut path
  191. func absolutePath(inPath string) string {
  192. if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
  193. inPath = userHomeDir() + inPath[5:]
  194. }
  195. if filepath.IsAbs(inPath) {
  196. return filepath.Clean(inPath)
  197. }
  198. p, err := filepath.Abs(inPath)
  199. if err == nil {
  200. return filepath.Clean(p)
  201. }
  202. return ""
  203. }
  204. // userHomeDir get gopath
  205. func userHomeDir() string {
  206. if runtime.GOOS == "windows" {
  207. home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  208. if home == "" {
  209. home = os.Getenv("USERPROFILE")
  210. }
  211. return home
  212. }
  213. return os.Getenv("HOME")
  214. }