github.com/igoogolx/clash@v1.19.8/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "os" 7 "os/signal" 8 "path/filepath" 9 "runtime" 10 "syscall" 11 _ "time/tzdata" 12 13 "github.com/igoogolx/clash/config" 14 C "github.com/igoogolx/clash/constant" 15 "github.com/igoogolx/clash/hub" 16 "github.com/igoogolx/clash/hub/executor" 17 "github.com/igoogolx/clash/log" 18 19 "go.uber.org/automaxprocs/maxprocs" 20 ) 21 22 var ( 23 version bool 24 testConfig bool 25 homeDir string 26 configFile string 27 externalUI string 28 externalController string 29 secret string 30 ) 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(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API") 38 flag.BoolVar(&version, "v", false, "show current version of clash") 39 flag.BoolVar(&testConfig, "t", false, "test configuration and exit") 40 flag.Parse() 41 } 42 43 func main() { 44 maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) 45 if version { 46 fmt.Printf("Clash %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) 47 return 48 } 49 50 if homeDir != "" { 51 if !filepath.IsAbs(homeDir) { 52 currentDir, _ := os.Getwd() 53 homeDir = filepath.Join(currentDir, homeDir) 54 } 55 C.SetHomeDir(homeDir) 56 } 57 58 if configFile != "" { 59 if !filepath.IsAbs(configFile) { 60 currentDir, _ := os.Getwd() 61 configFile = filepath.Join(currentDir, configFile) 62 } 63 C.SetConfig(configFile) 64 } else { 65 configFile := filepath.Join(C.Path.HomeDir(), C.Path.Config()) 66 C.SetConfig(configFile) 67 } 68 69 if err := config.Init(C.Path.HomeDir()); err != nil { 70 log.Fatalln("Initial configuration directory error: %s", err.Error()) 71 } 72 73 if testConfig { 74 if _, err := executor.Parse(); err != nil { 75 log.Errorln(err.Error()) 76 fmt.Printf("configuration file %s test failed\n", C.Path.Config()) 77 os.Exit(1) 78 } 79 fmt.Printf("configuration file %s test is successful\n", C.Path.Config()) 80 return 81 } 82 83 var options []hub.Option 84 if externalUI != "" { 85 options = append(options, hub.WithExternalUI(externalUI)) 86 } 87 if externalController != "" { 88 options = append(options, hub.WithExternalController(externalController)) 89 } 90 if secret != "" { 91 options = append(options, hub.WithSecret(secret)) 92 } 93 94 if err := hub.Parse(options...); err != nil { 95 log.Fatalln("Parse config error: %s", err.Error()) 96 } 97 98 termSign := make(chan os.Signal, 1) 99 hupSign := make(chan os.Signal, 1) 100 signal.Notify(termSign, syscall.SIGINT, syscall.SIGTERM) 101 signal.Notify(hupSign, syscall.SIGHUP) 102 for { 103 select { 104 case <-termSign: 105 return 106 case <-hupSign: 107 if cfg, err := executor.ParseWithPath(C.Path.Config()); err == nil { 108 executor.ApplyConfig(cfg, true) 109 } else { 110 log.Errorln("Parse config error: %s", err.Error()) 111 } 112 } 113 } 114 }