github.com/v2fly/v2ray-core/v4@v4.45.2/main/main.go (about)

     1  package main
     2  
     3  //go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
     4  
     5  import (
     6  	"flag"
     7  	"fmt"
     8  	"log"
     9  	"os"
    10  	"os/signal"
    11  	"path"
    12  	"path/filepath"
    13  	"runtime"
    14  	"strings"
    15  	"syscall"
    16  
    17  	core "github.com/v2fly/v2ray-core/v4"
    18  	"github.com/v2fly/v2ray-core/v4/common/cmdarg"
    19  	"github.com/v2fly/v2ray-core/v4/common/platform"
    20  	_ "github.com/v2fly/v2ray-core/v4/main/distro/all"
    21  )
    22  
    23  var (
    24  	configFiles cmdarg.Arg // "Config file for V2Ray.", the option is customed type, parse in main
    25  	configDir   string
    26  	version     = flag.Bool("version", false, "Show current version of V2Ray.")
    27  	test        = flag.Bool("test", false, "Test config file only, without launching V2Ray server.")
    28  	format      = flag.String("format", "json", "Format of input file.")
    29  
    30  	/* We have to do this here because Golang's Test will also need to parse flag, before
    31  	 * main func in this file is run.
    32  	 */
    33  	_ = func() error { // nolint: unparam
    34  		flag.Var(&configFiles, "config", "Config file for V2Ray. Multiple assign is accepted (only json). Latter ones overrides the former ones.")
    35  		flag.Var(&configFiles, "c", "Short alias of -config")
    36  		flag.StringVar(&configDir, "confdir", "", "A dir with multiple json config")
    37  
    38  		return nil
    39  	}()
    40  )
    41  
    42  func fileExists(file string) bool {
    43  	info, err := os.Stat(file)
    44  	return err == nil && !info.IsDir()
    45  }
    46  
    47  func dirExists(file string) bool {
    48  	if file == "" {
    49  		return false
    50  	}
    51  	info, err := os.Stat(file)
    52  	return err == nil && info.IsDir()
    53  }
    54  
    55  func readConfDir(dirPath string) {
    56  	confs, err := os.ReadDir(dirPath)
    57  	if err != nil {
    58  		log.Fatalln(err)
    59  	}
    60  	for _, f := range confs {
    61  		if strings.HasSuffix(f.Name(), ".json") {
    62  			configFiles.Set(path.Join(dirPath, f.Name()))
    63  		}
    64  	}
    65  }
    66  
    67  func getConfigFilePath() cmdarg.Arg {
    68  	if dirExists(configDir) {
    69  		log.Println("Using confdir from arg:", configDir)
    70  		readConfDir(configDir)
    71  	} else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {
    72  		log.Println("Using confdir from env:", envConfDir)
    73  		readConfDir(envConfDir)
    74  	}
    75  
    76  	if len(configFiles) > 0 {
    77  		return configFiles
    78  	}
    79  
    80  	if workingDir, err := os.Getwd(); err == nil {
    81  		configFile := filepath.Join(workingDir, "config.json")
    82  		if fileExists(configFile) {
    83  			log.Println("Using default config: ", configFile)
    84  			return cmdarg.Arg{configFile}
    85  		}
    86  	}
    87  
    88  	if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
    89  		log.Println("Using config from env: ", configFile)
    90  		return cmdarg.Arg{configFile}
    91  	}
    92  
    93  	log.Println("Using config from STDIN")
    94  	return cmdarg.Arg{"stdin:"}
    95  }
    96  
    97  func GetConfigFormat() string {
    98  	switch strings.ToLower(*format) {
    99  	case "pb", "protobuf":
   100  		return "protobuf"
   101  	default:
   102  		return "json"
   103  	}
   104  }
   105  
   106  func startV2Ray() (core.Server, error) {
   107  	configFiles := getConfigFilePath()
   108  
   109  	config, err := core.LoadConfig(GetConfigFormat(), configFiles[0], configFiles)
   110  	if err != nil {
   111  		return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)
   112  	}
   113  
   114  	server, err := core.New(config)
   115  	if err != nil {
   116  		return nil, newError("failed to create server").Base(err)
   117  	}
   118  
   119  	return server, nil
   120  }
   121  
   122  func printVersion() {
   123  	version := core.VersionStatement()
   124  	for _, s := range version {
   125  		fmt.Println(s)
   126  	}
   127  }
   128  
   129  func main() {
   130  	flag.Parse()
   131  
   132  	printVersion()
   133  
   134  	if *version {
   135  		return
   136  	}
   137  
   138  	server, err := startV2Ray()
   139  	if err != nil {
   140  		fmt.Println(err)
   141  		// Configuration error. Exit with a special value to prevent systemd from restarting.
   142  		os.Exit(23)
   143  	}
   144  
   145  	if *test {
   146  		fmt.Println("Configuration OK.")
   147  		os.Exit(0)
   148  	}
   149  
   150  	if err := server.Start(); err != nil {
   151  		fmt.Println("Failed to start", err)
   152  		os.Exit(-1)
   153  	}
   154  	defer server.Close()
   155  
   156  	// Explicitly triggering GC to remove garbage from config loading.
   157  	runtime.GC()
   158  
   159  	{
   160  		osSignals := make(chan os.Signal, 1)
   161  		signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)
   162  		<-osSignals
   163  	}
   164  }