run.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "log"
  6. "os"
  7. "os/signal"
  8. "path"
  9. "path/filepath"
  10. "runtime"
  11. "strings"
  12. "syscall"
  13. "github.com/xtls/xray-core/v1/common/cmdarg"
  14. "github.com/xtls/xray-core/v1/common/platform"
  15. "github.com/xtls/xray-core/v1/core"
  16. "github.com/xtls/xray-core/v1/main/commands/base"
  17. )
  18. var cmdRun = &base.Command{
  19. UsageLine: "{{.Exec}} run [-c config.json] [-confdir dir]",
  20. Short: "Run Xray with config, the default command",
  21. Long: `
  22. Run Xray with config, the default command.
  23. The -config=file, -c=file flags set the config files for
  24. Xray. Multiple assign is accepted.
  25. The -confdir=dir flag sets a dir with multiple json config
  26. The -format=json flag sets the format of config files.
  27. Default "json".
  28. The -test flag tells Xray to test config files only,
  29. without launching the server
  30. `,
  31. }
  32. func init() {
  33. cmdRun.Run = executeRun //break init loop
  34. }
  35. var (
  36. configFiles cmdarg.Arg // "Config file for Xray.", the option is customed type, parse in main
  37. configDir string
  38. test = cmdRun.Flag.Bool("test", false, "Test config file only, without launching Xray server.")
  39. format = cmdRun.Flag.String("format", "json", "Format of input file.")
  40. /* We have to do this here because Golang's Test will also need to parse flag, before
  41. * main func in this file is run.
  42. */
  43. _ = func() bool {
  44. cmdRun.Flag.Var(&configFiles, "config", "Config path for Xray.")
  45. cmdRun.Flag.Var(&configFiles, "c", "Short alias of -config")
  46. cmdRun.Flag.StringVar(&configDir, "confdir", "", "A dir with multiple json config")
  47. return true
  48. }()
  49. )
  50. func executeRun(cmd *base.Command, args []string) {
  51. printVersion()
  52. server, err := startXray()
  53. if err != nil {
  54. base.Fatalf("Filed to start: %s", err)
  55. }
  56. if *test {
  57. fmt.Println("Configuration OK.")
  58. base.SetExitStatus(0)
  59. base.Exit()
  60. }
  61. if err := server.Start(); err != nil {
  62. base.Fatalf("Filed to start: %s", err)
  63. }
  64. defer server.Close()
  65. // Explicitly triggering GC to remove garbage from config loading.
  66. runtime.GC()
  67. {
  68. osSignals := make(chan os.Signal, 1)
  69. signal.Notify(osSignals, os.Interrupt, syscall.SIGTERM)
  70. <-osSignals
  71. }
  72. }
  73. func fileExists(file string) bool {
  74. info, err := os.Stat(file)
  75. return err == nil && !info.IsDir()
  76. }
  77. func dirExists(file string) bool {
  78. if file == "" {
  79. return false
  80. }
  81. info, err := os.Stat(file)
  82. return err == nil && info.IsDir()
  83. }
  84. func readConfDir(dirPath string) {
  85. confs, err := ioutil.ReadDir(dirPath)
  86. if err != nil {
  87. log.Fatalln(err)
  88. }
  89. for _, f := range confs {
  90. if strings.HasSuffix(f.Name(), ".json") {
  91. configFiles.Set(path.Join(dirPath, f.Name()))
  92. }
  93. }
  94. }
  95. func getConfigFilePath() cmdarg.Arg {
  96. if dirExists(configDir) {
  97. log.Println("Using confdir from arg:", configDir)
  98. readConfDir(configDir)
  99. } else if envConfDir := platform.GetConfDirPath(); dirExists(envConfDir) {
  100. log.Println("Using confdir from env:", envConfDir)
  101. readConfDir(envConfDir)
  102. }
  103. if len(configFiles) > 0 {
  104. return configFiles
  105. }
  106. if workingDir, err := os.Getwd(); err == nil {
  107. configFile := filepath.Join(workingDir, "config.json")
  108. if fileExists(configFile) {
  109. log.Println("Using default config: ", configFile)
  110. return cmdarg.Arg{configFile}
  111. }
  112. }
  113. if configFile := platform.GetConfigurationPath(); fileExists(configFile) {
  114. log.Println("Using config from env: ", configFile)
  115. return cmdarg.Arg{configFile}
  116. }
  117. log.Println("Using config from STDIN")
  118. return cmdarg.Arg{"stdin:"}
  119. }
  120. func getConfigFormat() string {
  121. switch strings.ToLower(*format) {
  122. case "pb", "protobuf":
  123. return "protobuf"
  124. default:
  125. return "json"
  126. }
  127. }
  128. func startXray() (core.Server, error) {
  129. configFiles := getConfigFilePath()
  130. config, err := core.LoadConfig(getConfigFormat(), configFiles[0], configFiles)
  131. if err != nil {
  132. return nil, newError("failed to read config files: [", configFiles.String(), "]").Base(err)
  133. }
  134. server, err := core.New(config)
  135. if err != nil {
  136. return nil, newError("failed to create server").Base(err)
  137. }
  138. return server, nil
  139. }