github.com/xraypb/xray-core@v1.6.6/main/run.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "os/signal" 8 "path" 9 "path/filepath" 10 "regexp" 11 "runtime" 12 "runtime/debug" 13 "strings" 14 "syscall" 15 16 "github.com/xraypb/xray-core/common/cmdarg" 17 "github.com/xraypb/xray-core/common/platform" 18 "github.com/xraypb/xray-core/core" 19 "github.com/xraypb/xray-core/main/commands/base" 20 ) 21 22 var cmdRun = &base.Command{ 23 UsageLine: "{{.Exec}} run [-c config.json] [-confdir dir]", 24 Short: "Run Xray with config, the default command", 25 Long: ` 26 Run Xray with config, the default command. 27 28 The -config=file, -c=file flags set the config files for 29 Xray. Multiple assign is accepted. 30 31 The -confdir=dir flag sets a dir with multiple json config 32 33 The -format=json flag sets the format of config files. 34 Default "auto". 35 36 The -test flag tells Xray to test config files only, 37 without launching the server 38 `, 39 } 40 41 func init() { 42 cmdRun.Run = executeRun // break init loop 43 } 44 45 var ( 46 configFiles cmdarg.Arg // "Config file for Xray.", the option is customed type, parse in main 47 configDir string 48 test = cmdRun.Flag.Bool("test", false, "Test config file only, without launching Xray server.") 49 format = cmdRun.Flag.String("format", "auto", "Format of input file.") 50 51 /* We have to do this here because Golang's Test will also need to parse flag, before 52 * main func in this file is run. 53 */ 54 _ = func() bool { 55 cmdRun.Flag.Var(&configFiles, "config", "Config path for Xray.") 56 cmdRun.Flag.Var(&configFiles, "c", "Short alias of -config") 57 cmdRun.Flag.StringVar(&configDir, "confdir", "", "A dir with multiple json config") 58 59 return true 60 }() 61 ) 62 63 func executeRun(cmd *base.Command, args []string) { 64 printVersion() 65 server, err := startXray() 66 if err != nil { 67 fmt.Println("Failed to start:", err) 68 // Configuration error. Exit with a special value to prevent systemd from restarting. 69 os.Exit(23) 70 } 71 72 if *test { 73 fmt.Println("Configuration OK.") 74 os.Exit(0) 75 } 76 77 if err := server.Start(); err != nil { 78 fmt.Println("Failed to start:", err) 79 os.Exit(-1) 80 } 81 defer server.Close() 82 83 /* 84 conf.FileCache = nil 85 conf.IPCache = nil 86 conf.SiteCache = nil 87 */ 88 89 // Explicitly triggering GC to remove garbage from config loading. 90 runtime.GC() 91 debug.FreeOSMemory() 92 93 { 94 osSignals := make(chan os.Signal, 1) 95 signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM) 96 <-osSignals 97 } 98 } 99 100 func fileExists(file string) bool { 101 info, err := os.Stat(file) 102 return err == nil && !info.IsDir() 103 } 104 105 func dirExists(file string) bool { 106 if file == "" { 107 return false 108 } 109 info, err := os.Stat(file) 110 return err == nil && info.IsDir() 111 } 112 113 func getRegepxByFormat() string { 114 switch strings.ToLower(*format) { 115 case "json": 116 return `^.+\.json$` 117 case "toml": 118 return `^.+\.toml$` 119 case "yaml", "yml": 120 return `^.+\.(yaml|yml)$` 121 default: 122 return `^.+\.(json|toml|yaml|yml)$` 123 } 124 } 125 126 func readConfDir(dirPath string) { 127 confs, err := os.ReadDir(dirPath) 128 if err != nil { 129 log.Fatalln(err) 130 } 131 for _, f := range confs { 132 matched, err := regexp.MatchString(getRegepxByFormat(), f.Name()) 133 if err != nil { 134 log.Fatalln(err) 135 } 136 if matched { 137 configFiles.Set(path.Join(dirPath, f.Name())) 138 } 139 } 140 } 141 142 func getConfigFilePath() cmdarg.Arg { 143 if dirExists(configDir) { 144 log.Println("Using confdir from arg:", configDir) 145 readConfDir(configDir) 146 } else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) { 147 log.Println("Using confdir from env:", envConfDir) 148 readConfDir(envConfDir) 149 } 150 151 if len(configFiles) > 0 { 152 return configFiles 153 } 154 155 if workingDir, err := os.Getwd(); err == nil { 156 configFile := filepath.Join(workingDir, "config.json") 157 if fileExists(configFile) { 158 log.Println("Using default config: ", configFile) 159 return cmdarg.Arg{configFile} 160 } 161 } 162 163 if configFile := platform.GetConfigurationPath(); fileExists(configFile) { 164 log.Println("Using config from env: ", configFile) 165 return cmdarg.Arg{configFile} 166 } 167 168 log.Println("Using config from STDIN") 169 return cmdarg.Arg{"stdin:"} 170 } 171 172 func getConfigFormat() string { 173 f := core.GetFormatByExtension(*format) 174 if f == "" { 175 f = "auto" 176 } 177 return f 178 } 179 180 func startXray() (core.Server, error) { 181 configFiles := getConfigFilePath() 182 183 // config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles) 184 185 c, err := core.LoadConfig(getConfigFormat(), configFiles) 186 if err != nil { 187 return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err) 188 } 189 190 server, err := core.New(c) 191 if err != nil { 192 return nil, newError("failed to create server").Base(err) 193 } 194 195 return server, nil 196 }