config.go 2.6 KB

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