main.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "os/signal"
  7. "path/filepath"
  8. "runtime"
  9. "strings"
  10. "syscall"
  11. "github.com/metacubex/mihomo/component/updater"
  12. "github.com/metacubex/mihomo/config"
  13. C "github.com/metacubex/mihomo/constant"
  14. "github.com/metacubex/mihomo/constant/features"
  15. "github.com/metacubex/mihomo/hub"
  16. "github.com/metacubex/mihomo/hub/executor"
  17. "github.com/metacubex/mihomo/log"
  18. "github.com/metacubex/mihomo/rules/provider"
  19. "go.uber.org/automaxprocs/maxprocs"
  20. )
  21. var (
  22. version bool
  23. testConfig bool
  24. geodataMode bool
  25. homeDir string
  26. configFile string
  27. externalUI string
  28. externalController string
  29. externalControllerUnix string
  30. secret string
  31. )
  32. func init() {
  33. flag.StringVar(&homeDir, "d", os.Getenv("CLASH_HOME_DIR"), "set configuration directory")
  34. flag.StringVar(&configFile, "f", os.Getenv("CLASH_CONFIG_FILE"), "specify configuration file")
  35. flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), "override external ui directory")
  36. flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address")
  37. flag.StringVar(&externalControllerUnix, "ext-ctl-unix", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER_UNIX"), "override external controller unix address")
  38. flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API")
  39. flag.BoolVar(&geodataMode, "m", false, "set geodata mode")
  40. flag.BoolVar(&version, "v", false, "show current version of mihomo")
  41. flag.BoolVar(&testConfig, "t", false, "test configuration and exit")
  42. flag.Parse()
  43. }
  44. func main() {
  45. _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {}))
  46. if len(os.Args) > 1 && os.Args[1] == "convert-ruleset" {
  47. provider.ConvertMain(os.Args[2:])
  48. return
  49. }
  50. if version {
  51. fmt.Printf("Mihomo Meta %s %s %s with %s %s\n",
  52. C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime)
  53. if tags := features.Tags(); len(tags) != 0 {
  54. fmt.Printf("Use tags: %s\n", strings.Join(tags, ", "))
  55. }
  56. return
  57. }
  58. if homeDir != "" {
  59. if !filepath.IsAbs(homeDir) {
  60. currentDir, _ := os.Getwd()
  61. homeDir = filepath.Join(currentDir, homeDir)
  62. }
  63. C.SetHomeDir(homeDir)
  64. }
  65. if configFile != "" {
  66. if !filepath.IsAbs(configFile) {
  67. currentDir, _ := os.Getwd()
  68. configFile = filepath.Join(currentDir, configFile)
  69. }
  70. } else {
  71. configFile = filepath.Join(C.Path.HomeDir(), C.Path.Config())
  72. }
  73. C.SetConfig(configFile)
  74. if geodataMode {
  75. C.GeodataMode = true
  76. }
  77. if err := config.Init(C.Path.HomeDir()); err != nil {
  78. log.Fatalln("Initial configuration directory error: %s", err.Error())
  79. }
  80. if testConfig {
  81. if _, err := executor.Parse(); err != nil {
  82. log.Errorln(err.Error())
  83. fmt.Printf("configuration file %s test failed\n", C.Path.Config())
  84. os.Exit(1)
  85. }
  86. fmt.Printf("configuration file %s test is successful\n", C.Path.Config())
  87. return
  88. }
  89. var options []hub.Option
  90. if externalUI != "" {
  91. options = append(options, hub.WithExternalUI(externalUI))
  92. }
  93. if externalController != "" {
  94. options = append(options, hub.WithExternalController(externalController))
  95. }
  96. if externalControllerUnix != "" {
  97. options = append(options, hub.WithExternalControllerUnix(externalControllerUnix))
  98. }
  99. if secret != "" {
  100. options = append(options, hub.WithSecret(secret))
  101. }
  102. if err := hub.Parse(options...); err != nil {
  103. log.Fatalln("Parse config error: %s", err.Error())
  104. }
  105. if C.GeoAutoUpdate {
  106. updater.RegisterGeoUpdater(func() {
  107. cfg, err := executor.ParseWithPath(C.Path.Config())
  108. if err != nil {
  109. log.Errorln("[GEO] update GEO databases failed: %v", err)
  110. return
  111. }
  112. log.Warnln("[GEO] update GEO databases success, applying config")
  113. executor.ApplyConfig(cfg, false)
  114. })
  115. }
  116. defer executor.Shutdown()
  117. termSign := make(chan os.Signal, 1)
  118. hupSign := make(chan os.Signal, 1)
  119. signal.Notify(termSign, syscall.SIGINT, syscall.SIGTERM)
  120. signal.Notify(hupSign, syscall.SIGHUP)
  121. for {
  122. select {
  123. case <-termSign:
  124. return
  125. case <-hupSign:
  126. if cfg, err := executor.ParseWithPath(C.Path.Config()); err == nil {
  127. executor.ApplyConfig(cfg, true)
  128. } else {
  129. log.Errorln("Parse config error: %s", err.Error())
  130. }
  131. }
  132. }
  133. }