github.com/yaling888/clash@v1.53.0/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/phuslu/log" 14 "go.uber.org/automaxprocs/maxprocs" 15 16 "github.com/yaling888/clash/config" 17 C "github.com/yaling888/clash/constant" 18 "github.com/yaling888/clash/hub" 19 "github.com/yaling888/clash/hub/executor" 20 cLog "github.com/yaling888/clash/log" 21 ) 22 23 var ( 24 version bool 25 testConfig bool 26 homeDir string 27 configFile string 28 externalUI string 29 externalController string 30 secret string 31 ) 32 33 func init() { 34 flag.StringVar(&homeDir, "d", os.Getenv("CLASH_HOME_DIR"), "set configuration directory") 35 flag.StringVar(&configFile, "f", os.Getenv("CLASH_CONFIG_FILE"), "specify configuration file") 36 flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), 37 "override external ui directory") 38 flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), 39 "override external controller address") 40 flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), 41 "override secret for RESTful API") 42 flag.BoolVar(&version, "v", false, "show current version of clash") 43 flag.BoolVar(&testConfig, "t", false, "test configuration and exit") 44 flag.Parse() 45 } 46 47 func main() { 48 _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) 49 if version { 50 fmt.Printf("Clash Plus Pro %s %s %s with %s %s\n", 51 C.Version, 52 runtime.GOOS, 53 runtime.GOARCH, 54 runtime.Version(), 55 C.BuildTime, 56 ) 57 return 58 } 59 60 if homeDir != "" { 61 if !filepath.IsAbs(homeDir) { 62 currentDir, _ := os.Getwd() 63 homeDir = filepath.Join(currentDir, homeDir) 64 } 65 C.SetHomeDir(homeDir) 66 } 67 68 if configFile != "" { 69 if !filepath.IsAbs(configFile) { 70 currentDir, _ := os.Getwd() 71 configFile = filepath.Join(currentDir, configFile) 72 } 73 C.SetConfig(configFile) 74 } else { 75 configFile = filepath.Join(C.Path.HomeDir(), C.Path.Config()) 76 C.SetConfig(configFile) 77 } 78 79 if err := config.Init(C.Path.HomeDir()); err != nil { 80 log.Fatal(). 81 Err(err). 82 Str("dir", C.Path.HomeDir()). 83 Str("path", C.Path.Config()). 84 Msg("[Config] initial configuration failed") 85 } 86 87 if testConfig { 88 if _, err := executor.Parse(); err != nil { 89 log.Fatal(). 90 Err(err). 91 Str("path", C.Path.Config()). 92 Msg("[Config] configuration file test failed") 93 } 94 log.Info(). 95 Str("path", C.Path.Config()). 96 Msg("[Config] configuration file test is successful") 97 return 98 } 99 100 var options []hub.Option 101 if externalUI != "" { 102 options = append(options, hub.WithExternalUI(externalUI)) 103 } 104 if externalController != "" { 105 options = append(options, hub.WithExternalController(externalController)) 106 } 107 if secret != "" { 108 options = append(options, hub.WithSecret(secret)) 109 } 110 111 if err := hub.Parse(options...); err != nil { 112 log.Fatal(). 113 Err(err). 114 Str("path", C.Path.Config()). 115 Msg("[Config] parse config failed") 116 } 117 118 oldLevel := cLog.Level() 119 cLog.SetLevel(cLog.INFO) 120 log.Info(). 121 Str("version", fmt.Sprintf("%s %s %s with %s %s", 122 C.Version, 123 runtime.GOOS, 124 runtime.GOARCH, 125 runtime.Version(), 126 C.BuildTime, 127 )). 128 Msg("[Main] Clash Plus started") 129 cLog.SetLevel(oldLevel) 130 131 defer executor.Shutdown() 132 133 sigCh := make(chan os.Signal, 1) 134 signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP) 135 for { 136 s := <-sigCh 137 switch s { 138 case syscall.SIGHUP: 139 level := cLog.Level() 140 cLog.SetLevel(cLog.INFO) 141 142 log.Info().Str("path", C.Path.Config()).Msg("[Main] configuration file reloading...") 143 144 if conf, err := executor.Parse(); err == nil { 145 executor.ApplyConfig(conf, true) 146 147 level = cLog.Level() 148 cLog.SetLevel(cLog.INFO) 149 150 log.Info().Str("path", C.Path.Config()).Msg("[Main] configuration file reloaded") 151 } else { 152 log.Error(). 153 Err(err). 154 Str("path", C.Path.Config()). 155 Msg("[Main] reload config failed") 156 } 157 cLog.SetLevel(level) 158 default: 159 return 160 } 161 } 162 }