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 8.4 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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/discovery"
  32. "github.com/seata/seata-go/pkg/datasource/sql"
  33. "github.com/seata/seata-go/pkg/datasource/sql/undo"
  34. remoteConfig "github.com/seata/seata-go/pkg/remoting/config"
  35. "github.com/seata/seata-go/pkg/rm"
  36. "github.com/seata/seata-go/pkg/rm/tcc"
  37. "github.com/seata/seata-go/pkg/tm"
  38. "github.com/seata/seata-go/pkg/util/flagext"
  39. )
  40. const (
  41. configFileEnvKey = "SEATA_GO_CONFIG_PATH"
  42. configPrefix = "seata"
  43. )
  44. const (
  45. jsonSuffix = "json"
  46. tomlSuffix = "toml"
  47. yamlSuffix = "yaml"
  48. ymlSuffix = "yml"
  49. )
  50. type ClientConfig struct {
  51. TmConfig tm.TmConfig `yaml:"tm" json:"tm,omitempty" koanf:"tm"`
  52. RmConfig rm.Config `yaml:"rm" json:"rm,omitempty" koanf:"rm"`
  53. UndoConfig undo.Config `yaml:"undo" json:"undo,omitempty" koanf:"undo"`
  54. XaConfig sql.XAConfig `yaml:"xa" json:"xa" koanf:"xa"`
  55. }
  56. func (c *ClientConfig) RegisterFlagsWithPrefix(prefix string, f *flag.FlagSet) {
  57. c.TmConfig.RegisterFlagsWithPrefix(prefix+".tm", f)
  58. c.RmConfig.RegisterFlagsWithPrefix(prefix+".rm", f)
  59. c.UndoConfig.RegisterFlagsWithPrefix(prefix+".undo", f)
  60. c.XaConfig.RegisterFlagsWithPrefix(prefix+".xa", f)
  61. }
  62. type Config struct {
  63. Enabled bool `yaml:"enabled" json:"enabled,omitempty" koanf:"enabled"`
  64. ApplicationID string `yaml:"application-id" json:"application-id,omitempty" koanf:"application-id"`
  65. TxServiceGroup string `yaml:"tx-service-group" json:"tx-service-group,omitempty" koanf:"tx-service-group"`
  66. AccessKey string `yaml:"access-key" json:"access-key,omitempty" koanf:"access-key"`
  67. SecretKey string `yaml:"secret-key" json:"secret-key,omitempty" koanf:"secret-key"`
  68. EnableAutoDataSourceProxy bool `yaml:"enable-auto-data-source-proxy" json:"enable-auto-data-source-proxy,omitempty" koanf:"enable-auto-data-source-proxy"`
  69. DataSourceProxyMode string `yaml:"data-source-proxy-mode" json:"data-source-proxy-mode,omitempty" koanf:"data-source-proxy-mode"`
  70. AsyncWorkerConfig sql.AsyncWorkerConfig `yaml:"async" json:"async" koanf:"async"`
  71. TCCConfig tcc.Config `yaml:"tcc" json:"tcc" koanf:"tcc"`
  72. ClientConfig ClientConfig `yaml:"client" json:"client" koanf:"client"`
  73. GettyConfig remoteConfig.Config `yaml:"getty" json:"getty" koanf:"getty"`
  74. TransportConfig remoteConfig.TransportConfig `yaml:"transport" json:"transport" koanf:"transport"`
  75. ServiceConfig discovery.ServiceConfig `yaml:"service" json:"service" koanf:"service"`
  76. RegistryConfig discovery.RegistryConfig `yaml:"registry" json:"registry" koanf:"registry"`
  77. }
  78. func (c *Config) RegisterFlags(f *flag.FlagSet) {
  79. f.BoolVar(&c.Enabled, "enabled", true, "Whether enable auto configuration.")
  80. f.StringVar(&c.ApplicationID, "application-id", "seata-go", "Application id.")
  81. f.StringVar(&c.TxServiceGroup, "tx-service-group", "default_tx_group", "Transaction service group.")
  82. f.StringVar(&c.AccessKey, "access-key", "", "Used for aliyun accessKey.")
  83. f.StringVar(&c.SecretKey, "secret-key", "", "Used for aliyun secretKey.")
  84. f.BoolVar(&c.EnableAutoDataSourceProxy, "enable-auto-data-source-proxy", true, "Whether enable auto proxying of datasource bean.")
  85. f.StringVar(&c.DataSourceProxyMode, "data-source-proxy-mode", "AT", "Data source proxy mode.")
  86. c.AsyncWorkerConfig.RegisterFlagsWithPrefix("async-worker", f)
  87. c.TCCConfig.RegisterFlagsWithPrefix("tcc", f)
  88. c.ClientConfig.RegisterFlagsWithPrefix("client", f)
  89. c.GettyConfig.RegisterFlagsWithPrefix("getty", f)
  90. c.TransportConfig.RegisterFlagsWithPrefix("transport", f)
  91. c.RegistryConfig.RegisterFlagsWithPrefix("registry", f)
  92. c.ServiceConfig.RegisterFlagsWithPrefix("service", f)
  93. }
  94. type loaderConf struct {
  95. suffix string // loaderConf file extension default yaml
  96. path string // loaderConf file path default ./conf/seatago.yaml
  97. delim string // loaderConf file delim default .
  98. bytes []byte // config bytes
  99. name string // config file name
  100. }
  101. // Load parse config from user config path
  102. func LoadPath(configFilePath string) *Config {
  103. if configFilePath == "" {
  104. configFilePath = os.Getenv(configFileEnvKey)
  105. if configFilePath == "" {
  106. panic("system variable SEATA_GO_CONFIG_PATH is empty")
  107. }
  108. }
  109. var cfg Config
  110. // This sets default values from flags to the config.
  111. // It needs to be called before parsing the config file!
  112. flagext.RegisterFlags(&cfg)
  113. conf := newLoaderConf(configFilePath)
  114. koan := getConfigResolver(conf)
  115. if err := koan.UnmarshalWithConf(configPrefix, &cfg, koanf.UnmarshalConf{Tag: yamlSuffix}); err != nil {
  116. panic(err)
  117. }
  118. return &cfg
  119. }
  120. // Load parse config from json bytes
  121. func LoadJson(bytes []byte) *Config {
  122. var cfg Config
  123. // This sets default values from flags to the config.
  124. // It needs to be called before parsing the config file!
  125. flagext.RegisterFlags(&cfg)
  126. koan := getJsonConfigResolver(bytes)
  127. if err := koan.Unmarshal("", &cfg); err != nil {
  128. panic(err)
  129. }
  130. return &cfg
  131. }
  132. // getJsonConfigResolver get json config resolver
  133. func getJsonConfigResolver(bytes []byte) *koanf.Koanf {
  134. k := koanf.New(".")
  135. if err := k.Load(rawbytes.Provider(bytes), json.Parser()); err != nil {
  136. panic(err)
  137. }
  138. return k
  139. }
  140. // resolverFilePath resolver file path
  141. // eg: give a ./conf/seatago.yaml return seatago and yaml
  142. func resolverFilePath(path string) (name, suffix string) {
  143. paths := strings.Split(path, "/")
  144. fileName := strings.Split(paths[len(paths)-1], ".")
  145. if len(fileName) < 2 {
  146. return fileName[0], yamlSuffix
  147. }
  148. return fileName[0], fileName[1]
  149. }
  150. // getConfigResolver get config resolver
  151. func getConfigResolver(conf *loaderConf) *koanf.Koanf {
  152. var (
  153. k *koanf.Koanf
  154. err error
  155. )
  156. if len(conf.suffix) <= 0 {
  157. conf.suffix = yamlSuffix
  158. }
  159. if len(conf.delim) <= 0 {
  160. conf.delim = "."
  161. }
  162. bytes := conf.bytes
  163. if len(bytes) <= 0 {
  164. panic(fmt.Errorf("bytes is nil,please set bytes or file path"))
  165. }
  166. k = koanf.New(conf.delim)
  167. switch conf.suffix {
  168. case yamlSuffix, ymlSuffix:
  169. err = k.Load(rawbytes.Provider(bytes), yaml.Parser())
  170. case jsonSuffix:
  171. err = k.Load(rawbytes.Provider(bytes), json.Parser())
  172. case tomlSuffix:
  173. err = k.Load(rawbytes.Provider(bytes), toml.Parser())
  174. default:
  175. err = fmt.Errorf("no support %s file suffix", conf.suffix)
  176. }
  177. if err != nil {
  178. panic(err)
  179. }
  180. return k
  181. }
  182. func newLoaderConf(configFilePath string) *loaderConf {
  183. name, suffix := resolverFilePath(configFilePath)
  184. conf := &loaderConf{
  185. suffix: suffix,
  186. path: absolutePath(configFilePath),
  187. delim: ".",
  188. name: name,
  189. }
  190. if len(conf.bytes) <= 0 {
  191. if bytes, err := ioutil.ReadFile(conf.path); err != nil {
  192. panic(err)
  193. } else {
  194. conf.bytes = bytes
  195. }
  196. }
  197. return conf
  198. }
  199. // absolutePath get absolut path
  200. func absolutePath(inPath string) string {
  201. if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
  202. inPath = userHomeDir() + inPath[5:]
  203. }
  204. if filepath.IsAbs(inPath) {
  205. return filepath.Clean(inPath)
  206. }
  207. p, err := filepath.Abs(inPath)
  208. if err == nil {
  209. return filepath.Clean(p)
  210. }
  211. return ""
  212. }
  213. // userHomeDir get gopath
  214. func userHomeDir() string {
  215. if runtime.GOOS == "windows" {
  216. home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
  217. if home == "" {
  218. home = os.Getenv("USERPROFILE")
  219. }
  220. return home
  221. }
  222. return os.Getenv("HOME")
  223. }