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