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.1 kB

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