config.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. //go:build !confonly
  2. // +build !confonly
  3. package core
  4. import (
  5. "io"
  6. "strings"
  7. "google.golang.org/protobuf/proto"
  8. "github.com/v2fly/v2ray-core/v4/common"
  9. "github.com/v2fly/v2ray-core/v4/common/buf"
  10. "github.com/v2fly/v2ray-core/v4/common/cmdarg"
  11. "github.com/v2fly/v2ray-core/v4/main/confloader"
  12. )
  13. // ConfigFormat is a configurable format of V2Ray config file.
  14. type ConfigFormat struct {
  15. Name string
  16. Extension []string
  17. Loader ConfigLoader
  18. }
  19. // ConfigLoader is a utility to load V2Ray config from external source.
  20. type ConfigLoader func(input interface{}) (*Config, error)
  21. var (
  22. configLoaderByName = make(map[string]*ConfigFormat)
  23. configLoaderByExt = make(map[string]*ConfigFormat)
  24. )
  25. // RegisterConfigLoader add a new ConfigLoader.
  26. func RegisterConfigLoader(format *ConfigFormat) error {
  27. name := strings.ToLower(format.Name)
  28. if _, found := configLoaderByName[name]; found {
  29. return newError(format.Name, " already registered.")
  30. }
  31. configLoaderByName[name] = format
  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. idx := strings.LastIndexByte(filename, '.')
  43. if idx == -1 {
  44. return ""
  45. }
  46. return filename[idx+1:]
  47. }
  48. // LoadConfig loads config with given format from given source.
  49. // input accepts 2 different types:
  50. // * []string slice of multiple filename/url(s) to open to read
  51. // * io.Reader that reads a config content (the original way)
  52. func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) {
  53. ext := getExtension(filename)
  54. if len(ext) > 0 {
  55. if f, found := configLoaderByExt[ext]; found {
  56. return f.Loader(input)
  57. }
  58. }
  59. if f, found := configLoaderByName[formatName]; found {
  60. return f.Loader(input)
  61. }
  62. return nil, newError("Unable to load config in ", formatName).AtWarning()
  63. }
  64. func loadProtobufConfig(data []byte) (*Config, error) {
  65. config := new(Config)
  66. if err := proto.Unmarshal(data, config); err != nil {
  67. return nil, err
  68. }
  69. return config, nil
  70. }
  71. func init() {
  72. common.Must(RegisterConfigLoader(&ConfigFormat{
  73. Name: "Protobuf",
  74. Extension: []string{"pb"},
  75. Loader: func(input interface{}) (*Config, error) {
  76. switch v := input.(type) {
  77. case cmdarg.Arg:
  78. r, err := confloader.LoadConfig(v[0])
  79. common.Must(err)
  80. data, err := buf.ReadAllToBytes(r)
  81. common.Must(err)
  82. return loadProtobufConfig(data)
  83. case io.Reader:
  84. data, err := buf.ReadAllToBytes(v)
  85. common.Must(err)
  86. return loadProtobufConfig(data)
  87. default:
  88. return nil, newError("unknow type")
  89. }
  90. },
  91. }))
  92. }