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