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  }