config.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package core
  2. import (
  3. "io"
  4. "path/filepath"
  5. "strings"
  6. "google.golang.org/protobuf/proto"
  7. "github.com/v2fly/v2ray-core/v4/common"
  8. "github.com/v2fly/v2ray-core/v4/common/buf"
  9. "github.com/v2fly/v2ray-core/v4/common/cmdarg"
  10. )
  11. // ConfigFormat is a configurable format of V2Ray config file.
  12. type ConfigFormat struct {
  13. Name []string
  14. Extension []string
  15. Loader ConfigLoader
  16. }
  17. // ConfigLoader is a utility to load V2Ray config from external source.
  18. type ConfigLoader func(input interface{}) (*Config, error)
  19. var (
  20. configLoaderByName = make(map[string]*ConfigFormat)
  21. configLoaderByExt = make(map[string]*ConfigFormat)
  22. )
  23. // RegisterConfigLoader add a new ConfigLoader.
  24. func RegisterConfigLoader(format *ConfigFormat) error {
  25. for _, name := range format.Name {
  26. lname := strings.ToLower(name)
  27. if _, found := configLoaderByName[lname]; found {
  28. return newError(name, " already registered.")
  29. }
  30. configLoaderByName[lname] = format
  31. }
  32. for _, ext := range format.Extension {
  33. lext := strings.ToLower(ext)
  34. if f, found := configLoaderByExt[lext]; found {
  35. return newError(ext, " already registered to ", f.Name)
  36. }
  37. configLoaderByExt[lext] = format
  38. }
  39. return nil
  40. }
  41. func getExtension(filename string) string {
  42. ext := filepath.Ext(filename)
  43. return strings.ToLower(ext)
  44. }
  45. // GetConfigLoader get config loader by name and filename.
  46. // Specify formatName to explicitly select a loader.
  47. // Specify filename to choose loader by detect its extension.
  48. // Leave formatName and filename blank for default loader
  49. func GetConfigLoader(formatName string, filename string) (*ConfigFormat, error) {
  50. if formatName != "" {
  51. // if explicitly specified, we can safely assume that user knows what they are
  52. if f, found := configLoaderByName[formatName]; found {
  53. return f, nil
  54. }
  55. return nil, newError("Unable to load config in ", formatName).AtWarning()
  56. }
  57. // no explicitly specified loader, extenstion detect first
  58. if ext := getExtension(filename); len(ext) > 0 {
  59. if f, found := configLoaderByExt[ext]; found {
  60. return f, nil
  61. }
  62. }
  63. // default loader
  64. if f, found := configLoaderByName["json"]; found {
  65. return f, nil
  66. }
  67. panic("default loader not found")
  68. }
  69. // LoadConfig loads config with given format from given source.
  70. // input accepts 2 different types:
  71. // * []string slice of multiple filename/url(s) to open to read
  72. // * io.Reader that reads a config content (the original way)
  73. func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {
  74. f, err := GetConfigLoader(formatName, filename)
  75. if err != nil {
  76. return nil, err
  77. }
  78. return f.Loader(input)
  79. }
  80. func loadProtobufConfig(data []byte) (*Config, error) {
  81. config := new(Config)
  82. if err := proto.Unmarshal(data, config); err != nil {
  83. return nil, err
  84. }
  85. return config, nil
  86. }
  87. func init() {
  88. common.Must(RegisterConfigLoader(&ConfigFormat{
  89. Name: []string{"Protobuf", "pb"},
  90. Extension: []string{".pb"},
  91. Loader: func(input interface{}) (*Config, error) {
  92. switch v := input.(type) {
  93. case cmdarg.Arg:
  94. r, err := cmdarg.LoadArg(v[0])
  95. if err != nil {
  96. return nil, err
  97. }
  98. data, err := buf.ReadAllToBytes(r)
  99. if err != nil {
  100. return nil, err
  101. }
  102. return loadProtobufConfig(data)
  103. case io.Reader:
  104. data, err := buf.ReadAllToBytes(v)
  105. if err != nil {
  106. return nil, err
  107. }
  108. return loadProtobufConfig(data)
  109. default:
  110. return nil, newError("unknow type")
  111. }
  112. },
  113. }))
  114. }