github.com/Uhtred009/v2ray-core-1@v4.31.2+incompatible/config.go (about)

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