| 
									
										
										
										
											2019-02-01 20:08:21 +01:00
										 |  |  | // +build !confonly | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | package core | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-14 07:44:47 +08:00
										 |  |  | 	"google.golang.org/protobuf/proto" | 
					
						
							| 
									
										
										
										
											2021-02-17 04:31:50 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/v2fly/v2ray-core/v4/common" | 
					
						
							|  |  |  | 	"github.com/v2fly/v2ray-core/v4/common/buf" | 
					
						
							|  |  |  | 	"github.com/v2fly/v2ray-core/v4/common/cmdarg" | 
					
						
							|  |  |  | 	"github.com/v2fly/v2ray-core/v4/main/confloader" | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-16 14:04:02 +01:00
										 |  |  | // ConfigFormat is a configurable format of V2Ray config file. | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | type ConfigFormat struct { | 
					
						
							|  |  |  | 	Name      string | 
					
						
							|  |  |  | 	Extension []string | 
					
						
							|  |  |  | 	Loader    ConfigLoader | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-02 15:52:16 +08:00
										 |  |  | // ConfigLoader is a utility to load V2Ray config from external source. | 
					
						
							| 
									
										
										
										
											2020-01-03 09:26:48 +08:00
										 |  |  | type ConfigLoader func(input interface{}) (*Config, error) | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							|  |  |  | 	configLoaderByName = make(map[string]*ConfigFormat) | 
					
						
							|  |  |  | 	configLoaderByExt  = make(map[string]*ConfigFormat) | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RegisterConfigLoader add a new ConfigLoader. | 
					
						
							|  |  |  | func RegisterConfigLoader(format *ConfigFormat) error { | 
					
						
							|  |  |  | 	name := strings.ToLower(format.Name) | 
					
						
							|  |  |  | 	if _, found := configLoaderByName[name]; found { | 
					
						
							|  |  |  | 		return newError(format.Name, " already registered.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	configLoaderByName[name] = format | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for _, ext := range format.Extension { | 
					
						
							|  |  |  | 		lext := strings.ToLower(ext) | 
					
						
							|  |  |  | 		if f, found := configLoaderByExt[lext]; found { | 
					
						
							|  |  |  | 			return newError(ext, " already registered to ", f.Name) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		configLoaderByExt[lext] = format | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func getExtension(filename string) string { | 
					
						
							|  |  |  | 	idx := strings.LastIndexByte(filename, '.') | 
					
						
							|  |  |  | 	if idx == -1 { | 
					
						
							|  |  |  | 		return "" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return filename[idx+1:] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LoadConfig loads config with given format from given source. | 
					
						
							| 
									
										
										
										
											2020-01-03 09:26:48 +08:00
										 |  |  | // input accepts 2 different types: | 
					
						
							|  |  |  | // * []string slice of multiple filename/url(s) to open to read | 
					
						
							|  |  |  | // * io.Reader that reads a config content (the original way) | 
					
						
							|  |  |  | func LoadConfig(formatName string, filename string, input interface{}) (*Config, error) { | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | 	ext := getExtension(filename) | 
					
						
							|  |  |  | 	if len(ext) > 0 { | 
					
						
							|  |  |  | 		if f, found := configLoaderByExt[ext]; found { | 
					
						
							|  |  |  | 			return f.Loader(input) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if f, found := configLoaderByName[formatName]; found { | 
					
						
							|  |  |  | 		return f.Loader(input) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return nil, newError("Unable to load config in ", formatName).AtWarning() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-03 09:26:48 +08:00
										 |  |  | func loadProtobufConfig(data []byte) (*Config, error) { | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | 	config := new(Config) | 
					
						
							|  |  |  | 	if err := proto.Unmarshal(data, config); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return config, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	common.Must(RegisterConfigLoader(&ConfigFormat{ | 
					
						
							|  |  |  | 		Name:      "Protobuf", | 
					
						
							|  |  |  | 		Extension: []string{"pb"}, | 
					
						
							| 
									
										
										
										
											2020-01-03 09:26:48 +08:00
										 |  |  | 		Loader: func(input interface{}) (*Config, error) { | 
					
						
							|  |  |  | 			switch v := input.(type) { | 
					
						
							|  |  |  | 			case cmdarg.Arg: | 
					
						
							|  |  |  | 				r, err := confloader.LoadConfig(v[0]) | 
					
						
							|  |  |  | 				common.Must(err) | 
					
						
							|  |  |  | 				data, err := buf.ReadAllToBytes(r) | 
					
						
							|  |  |  | 				common.Must(err) | 
					
						
							|  |  |  | 				return loadProtobufConfig(data) | 
					
						
							|  |  |  | 			case io.Reader: | 
					
						
							|  |  |  | 				data, err := buf.ReadAllToBytes(v) | 
					
						
							|  |  |  | 				common.Must(err) | 
					
						
							|  |  |  | 				return loadProtobufConfig(data) | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				return nil, newError("unknow type") | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2018-02-14 23:57:40 +01:00
										 |  |  | 	})) | 
					
						
							|  |  |  | } |