diff --git a/cmd/npc/npc.go b/cmd/npc/npc.go index fe5b3f5..7de5850 100644 --- a/cmd/npc/npc.go +++ b/cmd/npc/npc.go @@ -3,18 +3,18 @@ package main import ( "flag" "fmt" - "os" - "strings" - "time" - "github.com/astaxie/beego/logs" "github.com/ccding/go-stun/stun" "github.com/cnlh/nps/client" "github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/config" - "github.com/cnlh/nps/lib/daemon" "github.com/cnlh/nps/lib/file" "github.com/cnlh/nps/lib/version" + "github.com/kardianos/service" + "os" + "runtime" + "strings" + "time" ) var ( @@ -30,11 +30,56 @@ var ( password = flag.String("password", "", "p2p password flag") target = flag.String("target", "", "p2p target") localType = flag.String("local_type", "p2p", "p2p target") - logPath = flag.String("log_path", "npc.log", "npc log path") + logPath = flag.String("log_path", "", "npc log path") + debug = flag.Bool("debug", false, "npc debug") + srv = flag.String("service", "", "npc debug") ) func main() { flag.Parse() + logs.Reset() + logs.EnableFuncCallDepth(true) + logs.SetLogFuncCallDepth(3) + if *logPath == "" { + *logPath = common.GetNpcLogPath() + } + if common.IsWindows() { + *logPath = strings.Replace(*logPath, "\\", "\\\\", -1) + } + if *debug { + logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`) + } else { + logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`) + } + + // init service + options := make(service.KeyValue) + options["Restart"] = "on-success" + options["SuccessExitStatus"] = "1 2 8 SIGKILL" + svcConfig := &service.Config{ + Name: "Npc", + DisplayName: "nps内网穿透客户端", + Description: "一款轻量级、功能强大的内网穿透代理服务器。支持tcp、udp流量转发,支持内网http代理、内网socks5代理,同时支持snappy压缩、站点保护、加密传输、多路复用、header修改等。支持web图形化管理,集成多用户模式。", + Option: options, + } + if !common.IsWindows() { + svcConfig.Dependencies = []string{ + "Requires=network.target", + "After=network-online.target syslog.target"} + } + for _, v := range os.Args[1:] { + if !strings.Contains(v, "-service=") { + svcConfig.Arguments = append(svcConfig.Arguments, v) + } + } + prg := &npc{ + exit: make(chan struct{}), + } + s, err := service.New(prg, svcConfig) + if err != nil { + logs.Error(err) + return + } if len(os.Args) >= 2 { switch os.Args[1] { case "status": @@ -55,14 +100,42 @@ func main() { os.Exit(0) } } - daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath()) - logs.EnableFuncCallDepth(true) - logs.SetLogFuncCallDepth(3) - if *logType == "stdout" { - logs.SetLogger(logs.AdapterConsole, `{"level":`+*logLevel+`,"color":true}`) - } else { - logs.SetLogger(logs.AdapterFile, `{"level":`+*logLevel+`,"filename":"`+*logPath+`","daily":false,"maxlines":100000,"color":true}`) + + if *srv != "" { + err := service.Control(s, *srv) + if err != nil { + logs.Error("Valid actions: %q\n", service.ControlAction, err.Error()) + } + return } + s.Run() +} + +type npc struct { + exit chan struct{} +} + +func (p *npc) Start(s service.Service) error { + p.run() + return nil +} +func (p *npc) Stop(s service.Service) error { + close(p.exit) + if service.Interactive() { + os.Exit(0) + } + return nil +} + +func (p *npc) run() error { + defer func() { + if err := recover(); err != nil { + const size = 64 << 10 + buf := make([]byte, size) + buf = buf[:runtime.Stack(buf, false)] + logs.Warning("npc: panic serving %v: %v\n%s", err, string(buf)) + } + }() //p2p or secret command if *password != "" { commonConfig := new(config.CommonConfig) @@ -76,8 +149,8 @@ func main() { localServer.Port = *localPort commonConfig.Client = new(file.Client) commonConfig.Client.Cnf = new(file.Config) - client.StartLocalServer(localServer, commonConfig) - return + go client.StartLocalServer(localServer, commonConfig) + return nil } env := common.GetEnvMap() if *serverAddr == "" { @@ -88,15 +161,22 @@ func main() { } logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion()) if *verifyKey != "" && *serverAddr != "" && *configPath == "" { - for { - client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start() - logs.Info("It will be reconnected in five seconds") - time.Sleep(time.Second * 5) - } + go func() { + for { + client.NewRPClient(*serverAddr, *verifyKey, *connType, *proxyUrl, nil).Start() + logs.Info("It will be reconnected in five seconds") + time.Sleep(time.Second * 5) + } + }() } else { if *configPath == "" { - *configPath = "npc.conf" + *configPath = "conf/npc.conf" } - client.StartFromFile(*configPath) + go client.StartFromFile(*configPath) } + select { + case <-p.exit: + logs.Warning("stop...") + } + return nil } diff --git a/lib/common/run.go b/lib/common/run.go index bfc4858..569ff5c 100644 --- a/lib/common/run.go +++ b/lib/common/run.go @@ -55,6 +55,17 @@ func GetLogPath() string { return path } +//interface npc log file path +func GetNpcLogPath() string { + var path string + if IsWindows() { + path = filepath.Join(GetAppPath(), "npc.log") + } else { + path = "/var/log/npc.log" + } + return path +} + //interface pid file path func GetTmpPath() string { var path string