github.com/imannamdari/v2ray-core/v5@v5.0.5/main/commands/run.go (about) 1 package commands 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "log" 7 "os" 8 "os/signal" 9 "path/filepath" 10 "runtime" 11 "strings" 12 "syscall" 13 14 core "github.com/imannamdari/v2ray-core/v5" 15 "github.com/imannamdari/v2ray-core/v5/common/cmdarg" 16 "github.com/imannamdari/v2ray-core/v5/common/platform" 17 "github.com/imannamdari/v2ray-core/v5/main/commands/base" 18 ) 19 20 // CmdRun runs V2Ray with config 21 var CmdRun = &base.Command{ 22 CustomFlags: true, 23 UsageLine: "{{.Exec}} run [-c config.json] [-d dir]", 24 Short: "run V2Ray with config", 25 Long: ` 26 Run V2Ray with config. 27 28 {{.Exec}} will also use the config directory specified by environment 29 variable "v2ray.location.confdir". If no config found, it tries 30 to load config from one of below: 31 32 1. The default "config.json" in the current directory 33 2. The config file from ENV "v2ray.location.config" 34 3. The stdin if all failed above 35 36 Arguments: 37 38 -c, -config <file> 39 Config file for V2Ray. Multiple assign is accepted. 40 41 -d, -confdir <dir> 42 A directory with config files. Multiple assign is accepted. 43 44 -r 45 Load confdir recursively. 46 47 -format <format> 48 Format of config input. (default "auto") 49 50 Examples: 51 52 {{.Exec}} {{.LongName}} -c config.json 53 {{.Exec}} {{.LongName}} -d path/to/dir 54 55 Use "{{.Exec}} help format-loader" for more information about format. 56 `, 57 Run: executeRun, 58 } 59 60 var ( 61 configFiles cmdarg.Arg 62 configDirs cmdarg.Arg 63 configFormat *string 64 configDirRecursively *bool 65 ) 66 67 func setConfigFlags(cmd *base.Command) { 68 configFormat = cmd.Flag.String("format", core.FormatAuto, "") 69 configDirRecursively = cmd.Flag.Bool("r", false, "") 70 71 cmd.Flag.Var(&configFiles, "config", "") 72 cmd.Flag.Var(&configFiles, "c", "") 73 cmd.Flag.Var(&configDirs, "confdir", "") 74 cmd.Flag.Var(&configDirs, "d", "") 75 } 76 77 func executeRun(cmd *base.Command, args []string) { 78 setConfigFlags(cmd) 79 cmd.Flag.Parse(args) 80 printVersion() 81 configFiles = getConfigFilePath() 82 server, err := startV2Ray() 83 if err != nil { 84 base.Fatalf("Failed to start: %s", err) 85 } 86 87 if err := server.Start(); err != nil { 88 base.Fatalf("Failed to start: %s", err) 89 } 90 defer server.Close() 91 92 // Explicitly triggering GC to remove garbage from config loading. 93 runtime.GC() 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 readConfDir(dirPath string, extension []string) cmdarg.Arg { 116 confs, err := ioutil.ReadDir(dirPath) 117 if err != nil { 118 base.Fatalf("failed to read dir %s: %s", dirPath, err) 119 } 120 files := make(cmdarg.Arg, 0) 121 for _, f := range confs { 122 ext := filepath.Ext(f.Name()) 123 for _, e := range extension { 124 if strings.EqualFold(e, ext) { 125 files.Set(filepath.Join(dirPath, f.Name())) 126 break 127 } 128 } 129 } 130 return files 131 } 132 133 // getFolderFiles get files in the folder and it's children 134 func readConfDirRecursively(dirPath string, extension []string) cmdarg.Arg { 135 files := make(cmdarg.Arg, 0) 136 err := filepath.Walk(dirPath, func(path string, info os.FileInfo, err error) error { 137 ext := filepath.Ext(path) 138 for _, e := range extension { 139 if strings.EqualFold(e, ext) { 140 files.Set(path) 141 break 142 } 143 } 144 return nil 145 }) 146 if err != nil { 147 base.Fatalf("failed to read dir %s: %s", dirPath, err) 148 } 149 return files 150 } 151 152 func getConfigFilePath() cmdarg.Arg { 153 extension, err := core.GetLoaderExtensions(*configFormat) 154 if err != nil { 155 base.Fatalf(err.Error()) 156 } 157 dirReader := readConfDir 158 if *configDirRecursively { 159 dirReader = readConfDirRecursively 160 } 161 if len(configDirs) > 0 { 162 for _, d := range configDirs { 163 log.Println("Using confdir from arg:", d) 164 configFiles = append(configFiles, dirReader(d, extension)...) 165 } 166 } else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) { 167 log.Println("Using confdir from env:", envConfDir) 168 configFiles = append(configFiles, dirReader(envConfDir, extension)...) 169 } 170 if len(configFiles) > 0 { 171 return configFiles 172 } 173 174 if len(configFiles) == 0 && len(configDirs) > 0 { 175 base.Fatalf("no config file found with extension: %s", extension) 176 } 177 178 if workingDir, err := os.Getwd(); err == nil { 179 configFile := filepath.Join(workingDir, "config.json") 180 if fileExists(configFile) { 181 log.Println("Using default config: ", configFile) 182 return cmdarg.Arg{configFile} 183 } 184 } 185 186 if configFile := platform.GetConfigurationPath(); fileExists(configFile) { 187 log.Println("Using config from env: ", configFile) 188 return cmdarg.Arg{configFile} 189 } 190 191 return nil 192 } 193 194 func startV2Ray() (core.Server, error) { 195 config, err := core.LoadConfig(*configFormat, configFiles) 196 if err != nil { 197 if len(configFiles) == 0 { 198 err = newError("failed to load config").Base(err) 199 } else { 200 err = newError(fmt.Sprintf("failed to load config: %s", configFiles)).Base(err) 201 } 202 return nil, err 203 } 204 205 server, err := core.New(config) 206 if err != nil { 207 return nil, newError("failed to create server").Base(err) 208 } 209 210 return server, nil 211 }