Explorar el Código

Merge pull request #310 from cnlh/dev

dev to master
ffdfgdfg hace 5 años
padre
commit
90a3409aac
Se han modificado 30 ficheros con 846 adiciones y 428 borrados
  1. 8 7
      .travis.yml
  2. 23 10
      README.md
  3. 17 0
      build.android.sh
  4. 0 136
      build.bash
  5. 8 7
      build.sh
  6. 111 22
      cmd/npc/npc.go
  7. 108 21
      cmd/nps/nps.go
  8. 4 1
      conf/nps.conf
  9. 2 1
      docs/_sidebar.md
  10. 3 0
      docs/description.md
  11. 2 2
      docs/example.md
  12. 8 2
      docs/index.html
  13. BIN
      docs/logo.png
  14. 23 0
      docs/npc_sdk.md
  15. 2 1
      docs/nps_extend.md
  16. 24 38
      docs/nps_use.md
  17. 24 11
      docs/run.md
  18. 33 22
      docs/use.md
  19. 10 6
      go.mod
  20. 56 18
      go.sum
  21. 173 0
      gui/npc/npc.go
  22. 10 2
      lib/common/netpackager.go
  23. 13 2
      lib/common/run.go
  24. 4 1
      lib/common/util.go
  25. 117 58
      lib/install/install.go
  26. 7 6
      lib/mux/conn.go
  27. 1 1
      lib/version/version.go
  28. 11 3
      server/proxy/tcp.go
  29. 0 50
      update.sh
  30. 44 0
      web/controllers/login.go

+ 8 - 7
.travis.yml

@@ -10,7 +10,7 @@ script:
 os:
 os:
   - linux
   - linux
 before_deploy:
 before_deploy:
-  - chmod +x ./build.sh && ./build.sh
+  - chmod +x ./build.sh && chmod +x ./build.android.sh && ./build.sh
 
 
 deploy:
 deploy:
   provider: releases
   provider: releases
@@ -44,14 +44,15 @@ deploy:
   - linux_mipsle_server.tar.gz
   - linux_mipsle_server.tar.gz
   - linux_mips_client.tar.gz
   - linux_mips_client.tar.gz
   - linux_mips_server.tar.gz
   - linux_mips_server.tar.gz
-  - macos_client.tar.gz
-  - macos_server.tar.gz
-  - win_386_client.tar.gz
-  - win_386_server.tar.gz
-  - win_amd64_client.tar.gz
-  - win_amd64_server.tar.gz
+  - darwin_amd64_client.tar.gz
+  - darwin_amd64_server.tar.gz
+  - windows_386_client.tar.gz
+  - windows_386_server.tar.gz
+  - windows_amd64_client.tar.gz
+  - windows_amd64_server.tar.gz
   - npc_syno.spk
   - npc_syno.spk
   - npc_sdk.tar.gz
   - npc_sdk.tar.gz
+  - android_client.apk
   on:
   on:
     tags: true
     tags: true
     all_branches: true
     all_branches: true

+ 23 - 10
README.md

@@ -28,19 +28,32 @@ nps是一款轻量级、高性能、功能强大的**内网穿透**代理服务
 下载对应的系统版本即可,服务端和客户端是单独的
 下载对应的系统版本即可,服务端和客户端是单独的
 
 
 ### 服务端启动
 ### 服务端启动
-1. 进入服务端启动
-```shell
- ./nps
-```
-如有错误修改配置文件相应端口,无错误可继续进行下去
+下载完服务器压缩包后,解压,然后进入解压后的文件夹
 
 
-2. 访问服务端ip:web服务端口(默认为8024)
-3. 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
-4. 在web中创建客户端
+- 执行安装命令
+
+对于linux|darwin ```sudo ./nps install```
+
+对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
+
+- 启动
+
+对于linux|darwin ```sudo nps start```
+
+对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
+
+停止和重启可用,stop和restart
+
+**如果发现没有启动成功,可以查看日志(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)**
+- 访问服务端ip:web服务端口(默认为8080)
+- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
+- 创建客户端
 
 
 ### 客户端连接
 ### 客户端连接
-1. 点击web管理中客户端前的+号,复制启动命令
-2. 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
+- 点击web管理中客户端前的+号,复制启动命令
+- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
+
+如果需要注册到系统服务可查看[注册到系统服务](https://cnlh.github.io/nps/#/use?id=注册到系统服务)
 
 
 ### 配置
 ### 配置
 - 客户端连接后,在web中配置对应穿透服务即可
 - 客户端连接后,在web中配置对应穿透服务即可

+ 17 - 0
build.android.sh

@@ -0,0 +1,17 @@
+#/bin/bash
+#sudo apt-get install libgl1-mesa-dev xorg-dev
+#go get github.com/ffdfgdfg/fyne-cross
+#fyne-cross --targets=linux/amd64,windows/amd64,darwin/amd64 gui/npc/npc.go
+
+mkdir -p /go/src/github.com/cnlh/nps
+cp -R * /go/src/github.com/cnlh/nps
+cd /go/src/github.com/cnlh/nps
+go get -u fyne.io/fyne fyne.io/fyne/cmd/fyne
+go mod vendor
+cd vendor
+cp -R * /go/src
+cd ..
+rm -rf vendor
+cd gui/npc
+fyne package -os android -appID org.nps.client -icon ../../docs/logo.png
+mv npc.apk /app/android_client.apk

+ 0 - 136
build.bash

@@ -1,136 +0,0 @@
-#!/bin/bash
-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static"  ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_amd64_client.tar.gz npc conf/npc.conf
-
-CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_386_client.tar.gz npc conf/npc.conf
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf freebsd_386_client.tar.gz npc conf/npc.conf
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf freebsd_amd64_client.tar.gz npc conf/npc.conf
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf freebsd_arm_client.tar.gz npc conf/npc.conf
-
-CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_arm_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_arm64_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_mips64_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_mips64le_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_mipsle_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf linux_mips_client.tar.gz npc conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf win_386_client.tar.gz npc.exe conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf win_amd64_client.tar.gz npc.exe conf/npc.conf
-
-
-CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
-upx npc
-tar -czvf macos_client.tar.gz npc conf/npc.conf
-
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-CGO_ENABLED=0 GOOS=linux GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_arm64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=arm go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf freebsd_arm_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf freebsd_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=freebsd GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf freebsd_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_mips_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_mips64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mips64le go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_mips64le_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=linux GOARCH=mipsle go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-
-CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps
-tar -czvf macos_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
-
-
-CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps.exe
-tar -czvf win_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
-
-
-CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
-upx nps.exe
-tar -czvf win_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
-

+ 8 - 7
build.sh

@@ -1,5 +1,5 @@
 #/bash/sh
 #/bash/sh
-export VERSION=0.25.1
+export VERSION=0.25.2
 
 
 sudo apt-get install gcc-mingw-w64-i686
 sudo apt-get install gcc-mingw-w64-i686
 env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
 env GOOS=windows GOARCH=386 CGO_ENABLED=1 CC=i686-w64-mingw32-gcc go build -ldflags "-s -w -extldflags -static -extldflags -static" -buildmode=c-shared -o npc_sdk.dll cmd/npc/sdk.go
@@ -69,17 +69,17 @@ tar -czvf linux_mips_client.tar.gz npc conf/npc.conf conf/multi_account.conf
 
 
 CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 
 
-tar -czvf win_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
+tar -czvf windows_386_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
 
 
 
 
 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 
 
-tar -czvf win_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
+tar -czvf windows_amd64_client.tar.gz npc.exe conf/npc.conf conf/multi_account.conf
 
 
 
 
 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/npc/npc.go
 
 
-tar -czvf macos_client.tar.gz npc conf/npc.conf conf/multi_account.conf
+tar -czvf darwin_amd64_client.tar.gz npc conf/npc.conf conf/multi_account.conf
 
 
 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 
 
@@ -146,23 +146,24 @@ tar -czvf linux_mipsle_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.
 
 
 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 
 
-tar -czvf macos_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
+tar -czvf darwin_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps
 
 
 
 
 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 
 
-tar -czvf win_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
+tar -czvf windows_amd64_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
 
 
 
 
 CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags "-s -w -extldflags -static -extldflags -static" ./cmd/nps/nps.go
 
 
-tar -czvf win_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
+tar -czvf windows_386_server.tar.gz conf/nps.conf conf/tasks.json conf/clients.json conf/hosts.json conf/server.key  conf/server.pem web/views web/static nps.exe
 
 
 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
 sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
 sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
 sudo apt-get update
 sudo apt-get update
 sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
 sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
 docker --version
 docker --version
+docker run --rm -i -w /app -v $(pwd):/app -e ANDROID_HOME=/usr/local/android_sdk ffdfgdfg/fyne-cross:android /app/build.android.sh
 git clone https://github.com/cnlh/spksrc.git ~/spksrc
 git clone https://github.com/cnlh/spksrc.git ~/spksrc
 mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
 mkdir ~/spksrc/nps && cp -rf ./* ~/spksrc/nps/
 docker run -itd --name spksrc --env VERSION=$VERSION  -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
 docker run -itd --name spksrc --env VERSION=$VERSION  -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash

+ 111 - 22
cmd/npc/npc.go

@@ -3,18 +3,19 @@ package main
 import (
 import (
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
-	"os"
-	"strings"
-	"time"
-
 	"github.com/astaxie/beego/logs"
 	"github.com/astaxie/beego/logs"
 	"github.com/ccding/go-stun/stun"
 	"github.com/ccding/go-stun/stun"
 	"github.com/cnlh/nps/client"
 	"github.com/cnlh/nps/client"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/common"
 	"github.com/cnlh/nps/lib/config"
 	"github.com/cnlh/nps/lib/config"
-	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
+	"github.com/cnlh/nps/lib/install"
 	"github.com/cnlh/nps/lib/version"
 	"github.com/cnlh/nps/lib/version"
+	"github.com/kardianos/service"
+	"os"
+	"runtime"
+	"strings"
+	"time"
 )
 )
 
 
 var (
 var (
@@ -30,11 +31,60 @@ var (
 	password     = flag.String("password", "", "p2p password flag")
 	password     = flag.String("password", "", "p2p password flag")
 	target       = flag.String("target", "", "p2p target")
 	target       = flag.String("target", "", "p2p target")
 	localType    = flag.String("local_type", "p2p", "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", true, "npc debug")
 )
 )
 
 
 func main() {
 func main() {
 	flag.Parse()
 	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:] {
+		switch v {
+		case "install", "start", "stop", "uninstall", "restart":
+			continue
+		}
+		if !strings.Contains(v, "-service=") && !strings.Contains(v, "-debug=") {
+			svcConfig.Arguments = append(svcConfig.Arguments, v)
+		}
+	}
+	svcConfig.Arguments = append(svcConfig.Arguments, "-debug=false")
+	prg := &npc{
+		exit: make(chan struct{}),
+	}
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		logs.Error(err)
+		return
+	}
 	if len(os.Args) >= 2 {
 	if len(os.Args) >= 2 {
 		switch os.Args[1] {
 		switch os.Args[1] {
 		case "status":
 		case "status":
@@ -45,6 +95,9 @@ func main() {
 		case "register":
 		case "register":
 			flag.CommandLine.Parse(os.Args[2:])
 			flag.CommandLine.Parse(os.Args[2:])
 			client.RegisterLocalIp(*serverAddr, *verifyKey, *connType, *proxyUrl, *registerTime)
 			client.RegisterLocalIp(*serverAddr, *verifyKey, *connType, *proxyUrl, *registerTime)
+		case "update":
+			install.UpdateNpc()
+			return
 		case "nat":
 		case "nat":
 			nat, host, err := stun.NewClient().Discover()
 			nat, host, err := stun.NewClient().Discover()
 			if err != nil || host == nil {
 			if err != nil || host == nil {
@@ -53,16 +106,45 @@ func main() {
 			}
 			}
 			fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String())
 			fmt.Printf("nat type: %s \npublic address: %s\n", nat.String(), host.String())
 			os.Exit(0)
 			os.Exit(0)
+		case "install", "start", "stop", "uninstall", "restart":
+			if os.Args[1] == "install" {
+				install.InstallNpc()
+			}
+			err := service.Control(s, os.Args[1])
+			if err != nil {
+				logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
+			}
+			return
 		}
 		}
 	}
 	}
-	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}`)
+	s.Run()
+}
+
+type npc struct {
+	exit chan struct{}
+}
+
+func (p *npc) Start(s service.Service) error {
+	go 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
 	//p2p or secret command
 	if *password != "" {
 	if *password != "" {
 		commonConfig := new(config.CommonConfig)
 		commonConfig := new(config.CommonConfig)
@@ -76,8 +158,8 @@ func main() {
 		localServer.Port = *localPort
 		localServer.Port = *localPort
 		commonConfig.Client = new(file.Client)
 		commonConfig.Client = new(file.Client)
 		commonConfig.Client.Cnf = new(file.Config)
 		commonConfig.Client.Cnf = new(file.Config)
-		client.StartLocalServer(localServer, commonConfig)
-		return
+		go client.StartLocalServer(localServer, commonConfig)
+		return nil
 	}
 	}
 	env := common.GetEnvMap()
 	env := common.GetEnvMap()
 	if *serverAddr == "" {
 	if *serverAddr == "" {
@@ -88,15 +170,22 @@ func main() {
 	}
 	}
 	logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion())
 	logs.Info("the version of client is %s, the core version of client is %s", version.VERSION, version.GetVersion())
 	if *verifyKey != "" && *serverAddr != "" && *configPath == "" {
 	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 {
 	} else {
 		if *configPath == "" {
 		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
 }
 }

+ 108 - 21
cmd/nps/nps.go

@@ -2,9 +2,12 @@ package main
 
 
 import (
 import (
 	"flag"
 	"flag"
+	"github.com/cnlh/nps/lib/install"
 	"log"
 	"log"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"runtime"
+	"strings"
 
 
 	"github.com/astaxie/beego"
 	"github.com/astaxie/beego"
 	"github.com/astaxie/beego/logs"
 	"github.com/astaxie/beego/logs"
@@ -12,14 +15,13 @@ import (
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/crypt"
 	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/daemon"
 	"github.com/cnlh/nps/lib/file"
 	"github.com/cnlh/nps/lib/file"
-	"github.com/cnlh/nps/lib/install"
 	"github.com/cnlh/nps/lib/version"
 	"github.com/cnlh/nps/lib/version"
 	"github.com/cnlh/nps/server"
 	"github.com/cnlh/nps/server"
 	"github.com/cnlh/nps/server/connection"
 	"github.com/cnlh/nps/server/connection"
-	"github.com/cnlh/nps/server/test"
 	"github.com/cnlh/nps/server/tool"
 	"github.com/cnlh/nps/server/tool"
 
 
 	"github.com/cnlh/nps/web/routers"
 	"github.com/cnlh/nps/web/routers"
+	"github.com/kardianos/service"
 )
 )
 
 
 var (
 var (
@@ -29,20 +31,9 @@ var (
 
 
 func main() {
 func main() {
 	flag.Parse()
 	flag.Parse()
-	beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf"))
-	routers.Init()
-	if len(os.Args) > 1 {
-		switch os.Args[1] {
-		case "test":
-			test.TestServerConfig()
-			log.Println("test ok, no error")
-			return
-		case "start", "restart", "stop", "status", "reload":
-			daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
-		case "install":
-			install.InstallNps()
-			return
-		}
+	// init log
+	if err := beego.LoadAppConfig("ini", filepath.Join(common.GetRunPath(), "conf", "nps.conf")); err != nil {
+		log.Fatalln("load config file error", err.Error())
 	}
 	}
 	if level = beego.AppConfig.String("log_level"); level == "" {
 	if level = beego.AppConfig.String("log_level"); level == "" {
 		level = "7"
 		level = "7"
@@ -50,11 +41,102 @@ func main() {
 	logs.Reset()
 	logs.Reset()
 	logs.EnableFuncCallDepth(true)
 	logs.EnableFuncCallDepth(true)
 	logs.SetLogFuncCallDepth(3)
 	logs.SetLogFuncCallDepth(3)
-	if *logType == "stdout" {
-		logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
-	} else {
-		logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"filename":"`+beego.AppConfig.String("log_path")+`","daily":false,"maxlines":100000,"color":true}`)
+	logPath := beego.AppConfig.String("log_path")
+	if logPath == "" {
+		logPath = common.GetLogPath()
 	}
 	}
+	if common.IsWindows() {
+		logPath = strings.Replace(logPath, "\\", "\\\\", -1)
+	}
+	logs.SetLogger(logs.AdapterFile, `{"level":`+level+`,"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:        "Nps",
+		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"}
+	}
+	prg := &nps{}
+	prg.exit = make(chan struct{})
+	s, err := service.New(prg, svcConfig)
+	if err != nil {
+		logs.Error(err)
+		return
+	}
+	if len(os.Args) > 1 {
+		switch os.Args[1] {
+		case "debug":
+			logs.SetLogger(logs.AdapterConsole, `{"level":`+level+`,"color":true}`)
+		case "reload":
+			daemon.InitDaemon("nps", common.GetRunPath(), common.GetTmpPath())
+			return
+		case "install":
+			// uninstall before
+			service.Control(s, "uninstall")
+
+			binPath := install.InstallNps()
+			svcConfig.Executable = binPath
+			s, err := service.New(prg, svcConfig)
+			if err != nil {
+				logs.Error(err)
+				return
+			}
+			err = service.Control(s, os.Args[1])
+			if err != nil {
+				logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
+			}
+			return
+		case "start", "restart", "stop", "uninstall":
+			err := service.Control(s, os.Args[1])
+			if err != nil {
+				logs.Error("Valid actions: %q\n", service.ControlAction, err.Error())
+			}
+			return
+		case "update":
+			install.UpdateNps()
+			return
+		default:
+			logs.Error("command is not support")
+			return
+		}
+	}
+	s.Run()
+}
+
+type nps struct {
+	exit chan struct{}
+}
+
+func (p *nps) Start(s service.Service) error {
+	p.run()
+	return nil
+}
+func (p *nps) Stop(s service.Service) error {
+	close(p.exit)
+	if service.Interactive() {
+		os.Exit(0)
+	}
+	return nil
+}
+
+func (p *nps) 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("nps: panic serving %v: %v\n%s", err, string(buf))
+		}
+	}()
+	routers.Init()
 	task := &file.Tunnel{
 	task := &file.Tunnel{
 		Mode: "webServer",
 		Mode: "webServer",
 	}
 	}
@@ -68,5 +150,10 @@ func main() {
 	crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
 	crypt.InitTls(filepath.Join(common.GetRunPath(), "conf", "server.pem"), filepath.Join(common.GetRunPath(), "conf", "server.key"))
 	tool.InitAllowPort()
 	tool.InitAllowPort()
 	tool.StartSystemInfo()
 	tool.StartSystemInfo()
-	server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
+	go server.StartNewServer(bridgePort, task, beego.AppConfig.String("bridge_type"))
+	select {
+	case <-p.exit:
+		logs.Warning("stop...")
+	}
+	return nil
 }
 }

+ 4 - 1
conf/nps.conf

@@ -26,7 +26,7 @@ public_vkey=123
 
 
 # log level LevelEmergency->0  LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
 # log level LevelEmergency->0  LevelAlert->1 LevelCritical->2 LevelError->3 LevelWarning->4 LevelNotice->5 LevelInformational->6 LevelDebug->7
 log_level=7
 log_level=7
-log_path=nps.log
+#log_path=nps.log
 
 
 #Whether to restrict IP access, true or false or ignore
 #Whether to restrict IP access, true or false or ignore
 #ip_limit=true
 #ip_limit=true
@@ -42,6 +42,9 @@ web_password=123
 web_port = 8080
 web_port = 8080
 web_ip=0.0.0.0
 web_ip=0.0.0.0
 web_base_url=
 web_base_url=
+web_open_ssl=false
+web_cert_file=conf/server.pem
+web_key_file=conf/server.key
 # if web under proxy use sub path. like http://host/nps need this.
 # if web under proxy use sub path. like http://host/nps need this.
 #web_base_url=/nps
 #web_base_url=/nps
 
 

+ 2 - 1
docs/_sidebar.md

@@ -18,7 +18,8 @@
   * [功能](feature.md)
   * [功能](feature.md)
   * [说明](description.md)
   * [说明](description.md)
   * [web api](api.md)
   * [web api](api.md)
-
+  * [sdk](npc_sdk.md)
+git
 * 其他
 * 其他
 
 
   * [贡献](contribute.md)
   * [贡献](contribute.md)

+ 3 - 0
docs/description.md

@@ -24,3 +24,6 @@
 默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。
 默认情况下linux对连接数量有限制,对于性能好的机器完全可以调整内核参数以处理更多的连接。
 `tcp_max_syn_backlog` `somaxconn`
 `tcp_max_syn_backlog` `somaxconn`
 酌情调整参数,增强网络性能
 酌情调整参数,增强网络性能
+
+## web管理保护
+当一个ip连续登陆失败次数超过10次,将在一分钟内禁止该ip再次尝试。

+ 2 - 2
docs/example.md

@@ -25,7 +25,7 @@
 
 
 现在访问(http|https://)`a.proxy.com`,`b.proxy.com`即可成功
 现在访问(http|https://)`a.proxy.com`,`b.proxy.com`即可成功
 
 
-**https:** 如需使用https请进行相关配置,详见 [使用https](##使用https)
+**https:** 如需使用https请进行相关配置,详见 [使用https](/nps_extend?id=使用https)
 
 
 ## tcp隧道
 ## tcp隧道
 
 
@@ -100,7 +100,7 @@
 
 
 ## p2p服务
 ## p2p服务
 
 
-**适用范围:**  大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](##nat类型检测)
+**适用范围:**  大流量传输场景,流量不经过公网服务器,但是由于p2p穿透和nat类型关系较大,不保证100%成功,支持大部分nat类型。[nat类型检测](/npc_extend?id=nat类型检测)
 
 
 **假设场景:**
 **假设场景:**
 
 

+ 8 - 2
docs/index.html

@@ -11,7 +11,10 @@
 </head>
 </head>
 <body>
 <body>
 <div id="app"></div>
 <div id="app"></div>
+<script src="//unpkg.com/docsify-edit-on-github/index.js"></script>
+
 <script>
 <script>
+
     window.$docsify = {
     window.$docsify = {
         name: '',
         name: '',
         repo: '',
         repo: '',
@@ -24,13 +27,16 @@
             paths: 'auto',
             paths: 'auto',
             placeholder: "搜索",
             placeholder: "搜索",
             hideOtherSidebarContent: true, // whether or not to hide other sidebar content
             hideOtherSidebarContent: true, // whether or not to hide other sidebar content
-        }
+        },
+        plugins: [
+            EditOnGithubPlugin.create("https://github.com/cnlh/nps/tree/master/docs/", "", "在github上编辑"),
+        ]
+
     }
     }
 </script>
 </script>
 <script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
 <script src="//unpkg.com/docsify/lib/docsify.min.js"></script>
 <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
 <script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
 <script src="//unpkg.com/docsify-copy-code"></script>
 <script src="//unpkg.com/docsify-copy-code"></script>
 
 
-
 </body>
 </body>
 </html>
 </html>

BIN
docs/logo.png


+ 23 - 0
docs/npc_sdk.md

@@ -0,0 +1,23 @@
+# npc sdk文档
+
+```
+命令行模式启动客户端
+p0->连接地址
+p1->vkey
+p2->连接类型(tcp or udp)
+p3->连接代理
+
+extern GoInt StartClientByVerifyKey(char* p0, char* p1, char* p2, char* p3);
+
+查看当前启动的客户端状态,在线为1,离线为0
+extern GoInt GetClientStatus();
+
+关闭客户端
+extern void CloseClient();
+
+获取当前客户端版本
+extern char* Version();
+
+获取日志,实时更新
+extern char* Logs();
+```

+ 2 - 1
docs/nps_extend.md

@@ -44,7 +44,8 @@ server {
     }
     }
 }
 }
 ```
 ```
-
+## web管理使用https
+如果web管理需要使用https,可以在配置文件`nps.conf`中设置`web_open_ssl=true`,并配置`web_cert_file`和`web_key_file`
 ## web使用Caddy代理
 ## web使用Caddy代理
 
 
 如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置.
 如果将web配置到Caddy代理,实现子路径访问nps,可以这样配置.

+ 24 - 38
docs/nps_use.md

@@ -1,57 +1,43 @@
+# 使用
 **提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
 **提示:使用web模式时,服务端执行文件必须在项目根目录,否则无法正确加载配置文件**
 
 
-
-# 服务端测试
-```shell
- ./nps test
-```
-如有错误请及时修改配置文件,无错误可继续进行下去
-# 服务端启动
-```shell
- ./nps start
-```
-**如果无需daemon运行或者打开后无法正常访问web管理,去掉start查看日志运行即可**
-
-# web管理
+## web管理
 
 
 进入web界面,公网ip:web界面端口(默认8080),密码默认为123
 进入web界面,公网ip:web界面端口(默认8080),密码默认为123
 
 
 进入web管理界面,有详细的说明
 进入web管理界面,有详细的说明
 
 
-# 服务端配置文件重载
-如果是daemon启动
+## 服务端配置文件重载
+对于linux、darwin
 ```shell
 ```shell
- ./nps reload
+ sudo nps reload
 ```
 ```
-**说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多
-
-
-# 服务端停止或重启
-如果是daemon启动
+对于windows
 ```shell
 ```shell
- ./nps stop|restart
-```
-
-# 将nps安装到系统
-如果需要长期并且方便的运行nps服务端,可将nps安装到操作系统中,可执行命令
-
-```
-(./nps|nps.exe) install
+ nps.exe reload
 ```
 ```
-安装成功后,对于linux,darwin,将会把配置文件和静态文件放置于/etc/nps/,并将可执行文件nps复制到/usr/bin/nps或者/usr/local/bin/nps,安装成功后可在任何位置执行,同时也会添加systemd配置。
+**说明:** 仅支持部分配置重载,例如`allow_user_login` `auth_crypt_key` `auth_key` `web_username` `web_password` 等,未来将支持更多
 
 
-```
-sudo systemctl enable|disable|start|stop|restart|status nps
-```
-systemd,带有开机自启,自动重启配置,当进程结束后15秒会启动,日志输出至/var/log/nps/nps.log。
-建议采用此方式启动,能够捕获panic信息,便于排查问题。
 
 
+## 服务端停止或重启
+对于linux、darwin
+```shell
+ sudo nps stop|restart
 ```
 ```
-nps test|start|stop|restart|status
+对于windows
+```shell
+ nps.exe stop|restart
 ```
 ```
-对于windows系统,将会把配置文件和静态文件放置于C:\Program Files\nps,安装成功后可将可执行文件nps.exe复制到任何位置执行
+## 服务端更新
+请首先执行`sudo nps stop`或者`nps.exe stop`停止运行,然后
 
 
+对于linux
+```shell
+ sudo nps-update update
 ```
 ```
-nps.exe test|start|stop|restart|status
+对于windows
+```shell
+ nps-update.exe update
 ```
 ```
 
 
+更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级

+ 24 - 11
docs/run.md

@@ -1,19 +1,32 @@
 # 启动
 # 启动
 ## 服务端
 ## 服务端
 下载完服务器压缩包后,解压,然后进入解压后的文件夹
 下载完服务器压缩包后,解压,然后进入解压后的文件夹
-1. 执行命令启动
-```shell
- ./nps
-```
-**如有错误(E)修改配置文件相应端口**,无错误可继续进行下去
-2. 访问服务端ip:web服务端口(默认为8024)
-3. 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
-4. 创建客户端
+
+- 执行安装命令
+
+对于linux|darwin ```sudo ./nps install```
+
+对于windows,管理员身份运行cmd,进入安装目录 ```nps.exe install```
+
+- 启动
+
+对于linux|darwin ```sudo nps start```
+
+对于windows,管理员身份运行cmd,进入程序目录 ```nps.exe start```
+
+停止和重启可用,stop和restart
+
+**如果发现没有启动成功,可以使用`nps(.exe) debug`运行调试,或查看日志**(Windows日志文件位于当前运行目录下,linux和darwin位于/var/log/nps.log)
+- 访问服务端ip:web服务端口(默认为8080)
+- 使用用户名和密码登陆(默认admin/123,正式使用一定要更改)
+- 创建客户端
 
 
 ## 客户端
 ## 客户端
-1. 下载客户端安装包并解压,进入到解压目录
-1. 点击web管理中客户端前的+号,复制启动命令
-2. 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
+- 下载客户端安装包并解压,进入到解压目录
+- 点击web管理中客户端前的+号,复制启动命令
+- 执行启动命令,linux直接执行即可,windows将./npc换成npc.exe用cmd执行
+
+如果需要注册到系统服务可查看[注册到系统服务](/use?id=注册到系统服务)
 
 
 ## 配置
 ## 配置
 - 客户端连接后,在web中配置对应穿透服务即可
 - 客户端连接后,在web中配置对应穿透服务即可

+ 33 - 22
docs/use.md

@@ -2,34 +2,45 @@
 ## 无配置文件模式
 ## 无配置文件模式
 此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
 此模式的各种配置在服务端web管理中完成,客户端除运行一条命令外无需任何其他设置
 ```
 ```
- ./npc -server=ip:port -vkey=web界面中显示的密钥
+ ./npc -debug=true -server=ip:port -vkey=web界面中显示的密钥
 ```
 ```
+## 注册到系统服务
+对于linux、darwin
+- 注册:`sudo ./npc install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
+- 启动:`sudo ./npc start`
+- 停止:`sudo ./npc stop`
+- 如果需要更换命令内容需要先卸载`./npc -service=uninstall`,再重新注册
+
+对于windows,使用管理员身份运行cmd
+
+- 注册:`npc.exe install 其他参数(例如-server=xx -vkey=xx或者-config=xxx)`
+- 启动:`npc.exe start`
+- 停止:`npc.exe stop`
+- 如果需要更换命令内容需要先卸载`npc.exe -service=uninstall`,再重新注册
+
+注册到服务后,日志文件windows位于当前目录下,linux和darwin位于/var/log/npc.log
+
+## 客户端更新
+首先进入到对于的客户端二进制文件目录
+
+请首先执行`sudo ./npc stop`或者`nps.exe stop`停止运行,然后
+
+对于linux
+```shell
+ sudo ./npc-update update
+```
+对于windows
+```shell
+npc-update.exe update
+```
+
+更新完成后,执行执行`sudo nps start`或者`nps.exe start`重新运行即可完成升级
+
 ## 配置文件模式
 ## 配置文件模式
 此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理
 此模式使用nps的公钥或者客户端私钥验证,各种配置在客户端完成,同时服务端web也可以进行管理
 ```
 ```
  ./npc -config=npc配置文件路径
  ./npc -config=npc配置文件路径
 ```
 ```
-可自行添加systemd service,例如:`npc.service`
-```
-[Unit]
-Description=npc - convenient proxy server client
-Documentation=https://github.com/cnlh/nps/
-After=network-online.target remote-fs.target nss-lookup.target
-Wants=network-online.target
-
-[Service]
-Type=simple
-KillMode=process
-Restart=always
-RestartSec=15s
-StandardOutput=append:/var/log/nps/npc.log
-ExecStartPre=/bin/echo 'Starting npc'
-ExecStopPost=/bin/echo 'Stopping npc'
-ExecStart=/absolutely path to/npc -server=ip:port -vkey=web界面中显示的密钥
-
-[Install]
-WantedBy=multi-user.target
-```
 ## 配置文件说明
 ## 配置文件说明
 [示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf)
 [示例配置文件](https://github.com/cnlh/nps/tree/master/conf/npc.conf)
 #### 全局配置
 #### 全局配置

+ 10 - 6
go.mod

@@ -1,28 +1,32 @@
 module github.com/cnlh/nps
 module github.com/cnlh/nps
 
 
-go 1.12
+go 1.13
 
 
 require (
 require (
+	fyne.io/fyne v1.2.0
 	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
 	github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect
 	github.com/astaxie/beego v1.12.0
 	github.com/astaxie/beego v1.12.0
-	github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff // indirect
+	github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c // indirect
+	github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c
 	github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
 	github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d
+	github.com/dsnet/compress v0.0.1 // indirect
 	github.com/go-ole/go-ole v1.2.4 // indirect
 	github.com/go-ole/go-ole v1.2.4 // indirect
 	github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
 	github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db
+	github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 // indirect
+	github.com/kardianos/service v1.0.0
 	github.com/klauspost/cpuid v1.2.1 // indirect
 	github.com/klauspost/cpuid v1.2.1 // indirect
+	github.com/klauspost/pgzip v1.2.1 // indirect
 	github.com/klauspost/reedsolomon v1.9.2 // indirect
 	github.com/klauspost/reedsolomon v1.9.2 // indirect
-	github.com/onsi/gomega v1.5.0 // indirect
 	github.com/panjf2000/ants/v2 v2.2.2
 	github.com/panjf2000/ants/v2 v2.2.2
-	github.com/pkg/errors v0.8.0
+	github.com/pkg/errors v0.8.1
 	github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
 	github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 // indirect
 	github.com/shirou/gopsutil v2.19.11+incompatible
 	github.com/shirou/gopsutil v2.19.11+incompatible
-	github.com/stretchr/testify v1.3.0 // indirect
 	github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
 	github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect
 	github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
 	github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b // indirect
 	github.com/tjfoc/gmsm v1.0.1 // indirect
 	github.com/tjfoc/gmsm v1.0.1 // indirect
 	github.com/xtaci/kcp-go v5.4.4+incompatible
 	github.com/xtaci/kcp-go v5.4.4+incompatible
 	github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
 	github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae // indirect
-	golang.org/x/net v0.0.0-20181114220301-adae6a3d119a
+	golang.org/x/net v0.0.0-20181220203305-927f97764cc3
 	golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
 	golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa // indirect
 )
 )
 
 

+ 56 - 18
go.sum

@@ -1,13 +1,18 @@
+fyne.io/fyne v1.2.0 h1:mdp7Cs7QmSJTeazYxEDa9wWeJNig7paBcjm0dooFtLE=
+fyne.io/fyne v1.2.0/go.mod h1:Ab+3DIB/FVteW0y4DXfmZv4N3JdnCBh2lHkINI02BOU=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I=
 github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
 github.com/OwnLocal/goes v1.0.0/go.mod h1:8rIFjBGTue3lCU0wplczcUgt9Gxgrkkrw7etMIcn8TM=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
-github.com/astaxie/beego v1.12.0 h1:MRhVoeeye5N+Flul5PoVfD9CslfdoH+xqC/xvSQ5u2Y=
-github.com/astaxie/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
+github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
 github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
 github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
 github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
 github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
-github.com/belogik/goes v0.0.0-20151229125003-e54d722c3aff/go.mod h1:PhH1ZhyCzHKt4uAasyx+ljRCgoezetRNf59CUtwUkqY=
 github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
 github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
+github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c h1:FUUopH4brHNO2kJoNN3pV+OBEYmgraLT/KHZrMM69r0=
+github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo=
+github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c h1:aprLqMn7gSPT+vdDSl+/E6NLEuArwD/J7IWd8bJt5lQ=
+github.com/c4milo/unpackit v0.0.0-20170704181138-4ed373e9ef1c/go.mod h1:Ie6SubJv/NTO9Q0UBH0QCl3Ve50lu9hjbi5YJUw03TE=
 github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
 github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
 github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
 github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d h1:As4937T5NVbJ/DmZT9z33pyLEprMd6CUSfhbmMY57Io=
 github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
 github.com/ccding/go-stun v0.0.0-20180726100737-be486d185f3d/go.mod h1:3FK1bMar37f7jqVY7q/63k3OMX1c47pGCufzt3X0sYE=
@@ -18,52 +23,75 @@ github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFl
 github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
 github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
+github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
+github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
 github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
 github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
 github.com/exfly/beego v1.12.0-export-init h1:VQNYKdXhAwZGUaFmQv8Aj921O3rQJZRIF8xeGrhsjrI=
 github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
 github.com/exfly/beego v1.12.0-export-init/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
-github.com/exfly/beego v1.12.0 h1:OXwIwngaAx35Mga+jLiZmArusBxj8/H0jYXzGDAdwOg=
-github.com/exfly/beego v1.12.0/go.mod h1:fysx+LZNZKnvh4GED/xND7jWtjCR6HzydR2Hh2Im57o=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 h1:SCYMcCJ89LjRGwEa0tRluNRiMjZHalQZrVrvTbPh+qw=
+github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk=
+github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f h1:7MsFMbSn8Lcw0blK4+NEOf8DuHoOBDhJsHz04yh13pM=
+github.com/go-gl/glfw v0.0.0-20181213070059-819e8ce5125f/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
 github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI=
 github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
 github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
 github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8=
+github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
 github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214 h1:WgfvpuKg42WVLkxNwzfFraXkTXPK36bMqXvMFN67clI=
+github.com/hooklift/assert v0.0.0-20170704181755-9d1defd6d214/go.mod h1:kj6hFWqfwSjFjLnYW5PK1DoxZ4O0uapwHRmd9jhln4E=
+github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc=
+github.com/josephspurrier/goversioninfo v0.0.0-20190124120936-8611f5a5ff3f/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE=
+github.com/kardianos/service v1.0.0 h1:HgQS3mFfOlyntWX8Oke98JcJLqt1DBcHR4kxShpYef0=
+github.com/kardianos/service v1.0.0/go.mod h1:8CzDhVuCuugtsHyZoTvsOBuvonN/UDBvl0kH+BUxvbo=
+github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
+github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
 github.com/klauspost/cpuid v1.2.1 h1:vJi+O/nMdFt0vqm8NZBI6wzALWdA2X+egi0ogNyrC/w=
 github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
+github.com/klauspost/pgzip v1.2.1 h1:oIPZROsWuPHpOdMVWLuJZXwgjhrW8r1yEX8UqMyeNHM=
+github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
 github.com/klauspost/reedsolomon v1.9.2 h1:E9CMS2Pqbv+C7tsrYad4YC9MfhnMVWhMRsTi7U0UB18=
 github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
 github.com/klauspost/reedsolomon v1.9.2/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ/pcNv7fu+8Un4=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
+github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
 github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
 github.com/panjf2000/ants/v2 v2.2.2 h1:TWzusBjq/IflXhy+/S6u5wmMLCBdJnB9tPIx9Zmhvok=
 github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
 github.com/panjf2000/ants/v2 v2.2.2/go.mod h1:1GFm8bV8nyCQvU5K4WvBCTG1/YBFOD2VzjffD8fV55A=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
 github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
-github.com/shirou/gopsutil v2.18.12+incompatible h1:1eaJvGomDnH74/5cF4CTmTbLHAriGFsTZppLXDX93OM=
-github.com/shirou/gopsutil v2.18.12+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
 github.com/shirou/gopsutil v2.19.11+incompatible h1:lJHR0foqAjI4exXqWsU3DbH7bX1xvdhGdnXTIARA9W4=
 github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
 github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
 github.com/siddontang/ledisdb v0.0.0-20181029004158-becf5f38d373/go.mod h1:mF1DpOSOUiJRMR+FDqaqu3EBqrybQtrDDszLUZ6oxPg=
 github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
 github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e h1:LJUrNHytcMXWKxnULIHPe5SCb1jDpO9o672VB1x2EuQ=
+github.com/srwiley/oksvg v0.0.0-20190829233741-58e08c8fe40e/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
+github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e h1:FFotfUvew9Eg02LYRl8YybAnm0HCwjjfY5JlOI1oB00=
+github.com/srwiley/rasterx v0.0.0-20181219215540-696f7edb7a7e/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709 h1:Ko2LQMrRU+Oy/+EDBwX7eZ2jp3C47eDBB8EIhKTun+I=
+github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
 github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU=
 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
 github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU=
@@ -71,6 +99,8 @@ github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b h1:mnG1fcsIB1d/3vbkB
 github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
 github.com/templexxx/xor v0.0.0-20181023030647-4e92f724b73b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4=
 github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
 github.com/tjfoc/gmsm v1.0.1 h1:R11HlqhXkDospckjZEihx9SW/2VW0RgdwrykyWMFOQU=
 github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
 github.com/tjfoc/gmsm v1.0.1/go.mod h1:XxO4hdhhrzAd+G4CjDqaOkd0hUzmtPR/d3EiBBMn/wc=
+github.com/ulikunitz/xz v0.5.6 h1:jGHAfXawEGZQ3blwU5wnWKQJvAraT7Ftq9EXjnXYgt8=
+github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
 github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c=
 github.com/xtaci/kcp-go v5.4.4+incompatible h1:QIJ0a0Q0N1G20yLHL2+fpdzyy2v/Cb3PI+xiwx/KK9c=
 github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
 github.com/xtaci/kcp-go v5.4.4+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE=
@@ -78,17 +108,25 @@ github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+A
 github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
 github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
 golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
 golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85 h1:et7+NAX3lLIk5qUCTA9QelBjGE/NkhzYw/mhnr0s7nI=
 golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3 h1:eH6Eip3UpmR+yM/qI9Ijluzb1bNv/cAU/n+6l8tRSis=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa h1:KIDDMLT1O0Nr7TSxp8xM5tJcdn8tgyAONntO829og1M=
 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
 gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

+ 173 - 0
gui/npc/npc.go

@@ -0,0 +1,173 @@
+package main
+
+import (
+	"fmt"
+	"fyne.io/fyne"
+	"fyne.io/fyne/app"
+	"fyne.io/fyne/layout"
+	"fyne.io/fyne/widget"
+	"github.com/astaxie/beego/logs"
+	"github.com/cnlh/nps/client"
+	"github.com/cnlh/nps/lib/common"
+	"github.com/cnlh/nps/lib/daemon"
+	"github.com/cnlh/nps/lib/version"
+	"io/ioutil"
+	"os"
+	"path"
+	"runtime"
+	"strings"
+	"time"
+)
+
+func main() {
+	daemon.InitDaemon("npc", common.GetRunPath(), common.GetTmpPath())
+	logs.SetLogger("store")
+	application := app.New()
+	window := application.NewWindow("Npc " + version.VERSION)
+	window.SetContent(WidgetScreen())
+	window.Resize(fyne.NewSize(910, 350))
+
+	window.ShowAndRun()
+
+}
+
+var (
+	start    bool
+	status   = "Start!"
+	connType = "tcp"
+	cl       = new(client.TRPClient)
+)
+
+func WidgetScreen() fyne.CanvasObject {
+	return fyne.NewContainerWithLayout(layout.NewBorderLayout(nil, nil, nil, nil),
+		makeMainTab(),
+	)
+}
+
+func makeMainTab() fyne.Widget {
+	serverPort := widget.NewEntry()
+	serverPort.SetPlaceHolder("Server:Port")
+
+	vKey := widget.NewEntry()
+	vKey.SetPlaceHolder("Vkey")
+
+	radio := widget.NewRadio([]string{"tcp", "kcp"}, func(s string) { connType = s })
+	radio.Horizontal = true
+
+	refreshCh := make(chan struct{})
+	button := widget.NewButton(status, func() {
+		start = !start
+		if start {
+			status = "Stop!"
+			// init the npc
+			fmt.Println("submit", serverPort.Text, vKey.Text, connType)
+			sp, vk, ct := loadConfig()
+			if sp != serverPort.Text || vk != vKey.Text || ct != connType {
+				saveConfig(serverPort.Text, vKey.Text, connType)
+			}
+			cl = client.NewRPClient(serverPort.Text, vKey.Text, connType, "", nil)
+			go cl.Start()
+		} else {
+			// close the npc
+			status = "Start!"
+			if cl != nil {
+				go cl.Close()
+				cl = nil
+			}
+		}
+		refreshCh <- struct{}{}
+	})
+	go func() {
+		for {
+			<-refreshCh
+			button.SetText(status)
+		}
+	}()
+
+	lo := widget.NewMultiLineEntry()
+	lo.SetReadOnly(true)
+	lo.Resize(fyne.NewSize(910, 250))
+	slo := widget.NewScrollContainer(lo)
+	slo.Resize(fyne.NewSize(910, 250))
+	go func() {
+		for {
+			time.Sleep(time.Second)
+			lo.SetText(common.GetLogMsg())
+			slo.Resize(fyne.NewSize(910, 250))
+		}
+	}()
+
+	sp, vk, ct := loadConfig()
+	if sp != "" && vk != "" && ct != "" {
+		serverPort.SetText(sp)
+		vKey.SetText(vk)
+		connType = ct
+		radio.SetSelected(ct)
+	}
+
+	return widget.NewVBox(
+		widget.NewLabel("Npc "+version.VERSION),
+		serverPort,
+		vKey,
+		radio,
+		button,
+		slo,
+	)
+}
+
+func getDir() (dir string, err error) {
+	if runtime.GOOS != "android" {
+		dir, err = os.UserConfigDir()
+		if err != nil {
+			return
+		}
+	} else {
+		dir = "/data/data/org.nps.client/files"
+	}
+	return
+}
+
+func saveConfig(host, vkey, connType string) {
+	data := strings.Join([]string{host, vkey, connType}, "\n")
+	ph, err := getDir()
+	if err != nil {
+		logs.Warn("not found config dir")
+		return
+	}
+	_ = os.Remove(path.Join(ph, "npc.conf"))
+	f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_CREATE|os.O_WRONLY, 0644)
+	defer f.Close()
+	if err != nil {
+		logs.Error(err)
+		return
+	}
+	if _, err := f.Write([]byte(data)); err != nil {
+		f.Close() // ignore error; Write error takes precedence
+		logs.Error(err)
+		return
+	}
+}
+
+func loadConfig() (host, vkey, connType string) {
+	ph, err := getDir()
+	if err != nil {
+		logs.Warn("not found config dir")
+		return
+	}
+	f, err := os.OpenFile(path.Join(ph, "npc.conf"), os.O_RDONLY, 0644)
+	defer f.Close()
+	if err != nil {
+		logs.Error(err)
+		return
+	}
+	data, err := ioutil.ReadAll(f)
+	if err != nil {
+		logs.Error(err)
+		return
+	}
+	li := strings.Split(string(data), "\n")
+	host = li[0]
+	vkey = li[1]
+	connType = li[2]
+	return
+}

+ 10 - 2
lib/common/netpackager.go

@@ -41,6 +41,9 @@ func (Self *BasePackager) NewPac(contents ...interface{}) (err error) {
 		}
 		}
 	}
 	}
 	Self.setLength()
 	Self.setLength()
+	if Self.Length > MAXIMUM_SEGMENT_SIZE {
+		err = errors.New("mux:packer: newpack content segment too large")
+	}
 	return
 	return
 }
 }
 
 
@@ -77,6 +80,11 @@ func (Self *BasePackager) UnPack(reader io.Reader) (n uint16, err error) {
 	}
 	}
 	if int(Self.Length) > cap(Self.Content) {
 	if int(Self.Length) > cap(Self.Content) {
 		err = errors.New("unpack err, content length too large")
 		err = errors.New("unpack err, content length too large")
+		return
+	}
+	if Self.Length > MAXIMUM_SEGMENT_SIZE {
+		err = errors.New("mux:packer: unpack content segment too large")
+		return
 	}
 	}
 	Self.Content = Self.Content[:int(Self.Length)]
 	Self.Content = Self.Content[:int(Self.Length)]
 	//n, err := io.ReadFull(reader, Self.Content)
 	//n, err := io.ReadFull(reader, Self.Content)
@@ -273,10 +281,10 @@ func (addr *Addr) Decode(b []byte) error {
 	pos := 1
 	pos := 1
 	switch addr.Type {
 	switch addr.Type {
 	case ipV4:
 	case ipV4:
-		addr.Host = net.IP(b[pos:pos+net.IPv4len]).String()
+		addr.Host = net.IP(b[pos : pos+net.IPv4len]).String()
 		pos += net.IPv4len
 		pos += net.IPv4len
 	case ipV6:
 	case ipV6:
-		addr.Host = net.IP(b[pos:pos+net.IPv6len]).String()
+		addr.Host = net.IP(b[pos : pos+net.IPv6len]).String()
 		pos += net.IPv6len
 		pos += net.IPv6len
 	case domainName:
 	case domainName:
 		addrlen := int(b[pos])
 		addrlen := int(b[pos])

+ 13 - 2
lib/common/run.go

@@ -48,9 +48,20 @@ func IsWindows() bool {
 func GetLogPath() string {
 func GetLogPath() string {
 	var path string
 	var path string
 	if IsWindows() {
 	if IsWindows() {
-		path = GetAppPath()
+		path = filepath.Join(GetAppPath(), "nps.log")
 	} else {
 	} else {
-		path = "/tmp"
+		path = "/var/log/nps.log"
+	}
+	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
 	return path
 }
 }

+ 4 - 1
lib/common/util.go

@@ -51,7 +51,10 @@ func DomainCheck(domain string) bool {
 func CheckAuth(r *http.Request, user, passwd string) bool {
 func CheckAuth(r *http.Request, user, passwd string) bool {
 	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
 	s := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
 	if len(s) != 2 {
 	if len(s) != 2 {
-		return false
+		s = strings.SplitN(r.Header.Get("Proxy-Authorization"), " ", 2)
+		if len(s) != 2 {
+			return false
+		}
 	}
 	}
 
 
 	b, err := base64.StdEncoding.DecodeString(s[1])
 	b, err := base64.StdEncoding.DecodeString(s[1])

+ 117 - 58
lib/install/install.go

@@ -1,99 +1,149 @@
 package install
 package install
 
 
 import (
 import (
+	"encoding/json"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"github.com/c4milo/unpackit"
+	"github.com/cnlh/nps/lib/common"
 	"io"
 	"io"
 	"io/ioutil"
 	"io/ioutil"
 	"log"
 	"log"
+	"net/http"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"strings"
-
-	"github.com/cnlh/nps/lib/common"
 )
 )
 
 
-func InstallNps() {
-	unit := `[Unit]
-Description=nps - convenient proxy server
-Documentation=https://github.com/cnlh/nps/
-After=network-online.target remote-fs.target nss-lookup.target
-Wants=network-online.target`
-	service := `[Service]
-Type=simple
-KillMode=process
-Restart=always
-RestartSec=15s
-StandardOutput=append:/var/log/nps/nps.log
-ExecStartPre=/bin/echo 'Starting nps'
-ExecStopPost=/bin/echo 'Stopping nps'
-ExecStart=`
-	install := `[Install]
-WantedBy=multi-user.target`
+func UpdateNps() {
+	destPath := downloadLatest("server")
+	//复制文件到对应目录
+	copyStaticFile(destPath, "nps")
+	fmt.Println("Update completed, please restart")
+}
 
 
-	path := common.GetInstallPath()
-	if common.FileExists(path) {
-		log.Fatalf("the path %s has exist, does not support install", path)
-	}
-	MkidrDirAll(path, "conf", "web/static", "web/views")
+func UpdateNpc() {
+	destPath := downloadLatest("client")
 	//复制文件到对应目录
 	//复制文件到对应目录
-	if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {
-		log.Fatalln(err)
+	copyStaticFile(destPath, "npc")
+	fmt.Println("Update completed, please restart")
+}
+
+type release struct {
+	TagName string `json:"tag_name"`
+}
+
+func downloadLatest(bin string) string {
+	// get version
+	data, err := http.Get("https://api.github.com/repos/cnlh/nps/releases/latest")
+	if err != nil {
+		log.Fatal(err.Error())
+	}
+	b, err := ioutil.ReadAll(data.Body)
+	if err != nil {
+		log.Fatal(err)
 	}
 	}
-	if err := CopyDir(filepath.Join(common.GetAppPath(), "web", "static"), filepath.Join(path, "web", "static")); err != nil {
-		log.Fatalln(err)
+	rl := new(release)
+	json.Unmarshal(b, &rl)
+	version := rl.TagName
+	fmt.Println("the latest version is", version)
+	filename := runtime.GOOS + "_" + runtime.GOARCH + "_" + bin + ".tar.gz"
+	// download latest package
+	downloadUrl := fmt.Sprintf("https://github.com/cnlh/nps/releases/download/%s/%s", version, filename)
+	fmt.Println("download package from ", downloadUrl)
+	resp, err := http.Get(downloadUrl)
+	if err != nil {
+		log.Fatal(err.Error())
 	}
 	}
-	if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
-		log.Fatalln(err)
+	destPath, err := unpackit.Unpack(resp.Body, "")
+	if err != nil {
+		log.Fatal(err)
 	}
 	}
+	if bin == "server" {
+		destPath = strings.Replace(destPath, "/web", "", -1)
+		destPath = strings.Replace(destPath, `\web`, "", -1)
+		destPath = strings.Replace(destPath, "/views", "", -1)
+		destPath = strings.Replace(destPath, `\views`, "", -1)
+	} else {
+		destPath = strings.Replace(destPath, `\conf`, "", -1)
+		destPath = strings.Replace(destPath, "/conf", "", -1)
+	}
+	return destPath
+}
 
 
+func copyStaticFile(srcPath, bin string) string {
+	path := common.GetInstallPath()
+	if bin == "nps" {
+		//复制文件到对应目录
+		if err := CopyDir(filepath.Join(srcPath, "web", "views"), filepath.Join(path, "web", "views")); err != nil {
+			log.Fatalln(err)
+		}
+		chMod(filepath.Join(path, "web", "views"), 0766)
+		if err := CopyDir(filepath.Join(srcPath, "web", "static"), filepath.Join(path, "web", "static")); err != nil {
+			log.Fatalln(err)
+		}
+		chMod(filepath.Join(path, "web", "static"), 0766)
+	}
+	binPath, _ := filepath.Abs(os.Args[0])
 	if !common.IsWindows() {
 	if !common.IsWindows() {
-		if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/bin/nps"); err != nil {
-			if _, err := copyFile(filepath.Join(common.GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil {
+		if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/bin/"+bin); err != nil {
+			if _, err := copyFile(filepath.Join(srcPath, bin), "/usr/local/bin/"+bin); err != nil {
 				log.Fatalln(err)
 				log.Fatalln(err)
 			} else {
 			} else {
-				os.Chmod("/usr/local/bin/nps", 0755)
-				service += "/usr/local/bin/nps"
-				log.Println("Executable files have been copied to", "/usr/local/bin/nps")
+				copyFile(filepath.Join(srcPath, "nps"), "/usr/local/bin/"+bin+"-update")
+				binPath = "/usr/local/bin/" + bin
 			}
 			}
 		} else {
 		} else {
-			os.Chmod("/usr/bin/nps", 0755)
-			service += "/usr/bin/nps"
-			log.Println("Executable files have been copied to", "/usr/bin/nps")
+			copyFile(filepath.Join(srcPath, "nps"), "/usr/bin/"+bin+"-update")
+			binPath = "/usr/bin/" + bin
 		}
 		}
-		systemd := unit + "\n\n" + service + "\n\n" + install
-		if _, err := os.Stat("/usr/lib/systemd/system"); os.IsExist(err) {
-			_ = os.Remove("/usr/lib/systemd/system/nps.service")
-			err := ioutil.WriteFile("/usr/lib/systemd/system/nps.service", []byte(systemd), 0644)
-			if err != nil {
-				log.Println("Write systemd service err ", err)
-			}
-		} else if _, err := os.Stat("/lib/systemd/system"); os.IsExist(err) {
-			_ = os.Remove("/lib/systemd/system/nps.service")
-			err := ioutil.WriteFile("/lib/systemd/system/nps.service", []byte(systemd), 0644)
-			if err != nil {
-				log.Println("Write systemd service err ", err)
-			}
-		} else {
-			log.Println("Write systemd service fail, not found the systemd system path ")
+	} else {
+		copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+"-update.exe"))
+		copyFile(filepath.Join(srcPath, bin+".exe"), filepath.Join(common.GetAppPath(), bin+".exe"))
+	}
+	chMod(binPath, 0755)
+	return binPath
+}
+
+func InstallNpc() {
+	path := common.GetInstallPath()
+	if !common.FileExists(path) {
+		err := os.Mkdir(path, 0755)
+		if err != nil {
+			log.Fatal(err)
 		}
 		}
+	}
+	copyStaticFile(common.GetAppPath(), "npc")
+}
 
 
-		_ = os.Mkdir("/var/log/nps", 644)
+func InstallNps() string {
+	path := common.GetInstallPath()
+	if common.FileExists(path) {
+		MkidrDirAll(path, "web/static", "web/views")
+	} else {
+		MkidrDirAll(path, "conf", "web/static", "web/views")
+		// not copy config if the config file is exist
+		if err := CopyDir(filepath.Join(common.GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
+			log.Fatalln(err)
+		}
+		chMod(filepath.Join(path, "conf"), 0766)
 	}
 	}
+	binPath := copyStaticFile(common.GetAppPath(), "nps")
 	log.Println("install ok!")
 	log.Println("install ok!")
 	log.Println("Static files and configuration files in the current directory will be useless")
 	log.Println("Static files and configuration files in the current directory will be useless")
 	log.Println("The new configuration file is located in", path, "you can edit them")
 	log.Println("The new configuration file is located in", path, "you can edit them")
 	if !common.IsWindows() {
 	if !common.IsWindows() {
 		log.Println(`You can start with:
 		log.Println(`You can start with:
-sudo systemctl enable|disable|start|stop|restart|status nps
-or:
-nps test|start|stop|restart|status 
+nps start|stop|restart|uninstall|update or nps-update update
 anywhere!`)
 anywhere!`)
 	} else {
 	} else {
 		log.Println(`You can copy executable files to any directory and start working with:
 		log.Println(`You can copy executable files to any directory and start working with:
-nps.exe test|start|stop|restart|status
+nps.exe start|stop|restart|uninstall|update or nps-update.exe update
 now!`)
 now!`)
 	}
 	}
+	chMod(common.GetLogPath(), 0777)
+	return binPath
 }
 }
 func MkidrDirAll(path string, v ...string) {
 func MkidrDirAll(path string, v ...string) {
 	for _, item := range v {
 	for _, item := range v {
@@ -130,6 +180,9 @@ func CopyDir(srcPath string, destPath string) error {
 			destNewPath := strings.Replace(path, srcPath, destPath, -1)
 			destNewPath := strings.Replace(path, srcPath, destPath, -1)
 			log.Println("copy file ::" + path + " to " + destNewPath)
 			log.Println("copy file ::" + path + " to " + destNewPath)
 			copyFile(path, destNewPath)
 			copyFile(path, destNewPath)
+			if !common.IsWindows() {
+				chMod(destNewPath, 0766)
+			}
 		}
 		}
 		return nil
 		return nil
 	})
 	})
@@ -182,3 +235,9 @@ func pathExists(path string) (bool, error) {
 	}
 	}
 	return false, err
 	return false, err
 }
 }
+
+func chMod(name string, mode os.FileMode) {
+	if !common.IsWindows() {
+		os.Chmod(name, mode)
+	}
+}

+ 7 - 6
lib/mux/conn.go

@@ -293,7 +293,8 @@ copyData:
 		// reset to 60s if timeout and data still available
 		// reset to 60s if timeout and data still available
 		Self.off = 0
 		Self.off = 0
 		if err != nil {
 		if err != nil {
-			return // queue receive stop or time out, break the loop and return
+			Self.CloseWindow() // also close the window, to avoid read twice
+			return             // queue receive stop or time out, break the loop and return
 		}
 		}
 		//logs.Warn("pop element", Self.element.l, Self.element.part)
 		//logs.Warn("pop element", Self.element.l, Self.element.part)
 	}
 	}
@@ -361,14 +362,14 @@ func (Self *ReceiveWindow) release() {
 	//	common.ListElementPool.Put(Self.element)
 	//	common.ListElementPool.Put(Self.element)
 	//}
 	//}
 	for {
 	for {
-		Self.element = Self.bufQueue.TryPop()
-		if Self.element == nil {
+		ele := Self.bufQueue.TryPop()
+		if ele == nil {
 			return
 			return
 		}
 		}
-		if Self.element.Buf != nil {
-			common.WindowBuff.Put(Self.element.Buf)
+		if ele.Buf != nil {
+			common.WindowBuff.Put(ele.Buf)
 		}
 		}
-		common.ListElementPool.Put(Self.element)
+		common.ListElementPool.Put(ele)
 	} // release resource
 	} // release resource
 }
 }
 
 

+ 1 - 1
lib/version/version.go

@@ -1,6 +1,6 @@
 package version
 package version
 
 
-const VERSION = "0.25.1"
+const VERSION = "0.25.2"
 
 
 // Compulsory minimum version, Minimum downward compatibility to this version
 // Compulsory minimum version, Minimum downward compatibility to this version
 func GetVersion() string {
 func GetVersion() string {

+ 11 - 3
server/proxy/tcp.go

@@ -65,13 +65,21 @@ func (s *WebServer) Start() error {
 	beego.BConfig.WebConfig.Session.SessionOn = true
 	beego.BConfig.WebConfig.Session.SessionOn = true
 	beego.SetStaticPath(beego.AppConfig.String("web_base_url")+"/static", filepath.Join(common.GetRunPath(), "web", "static"))
 	beego.SetStaticPath(beego.AppConfig.String("web_base_url")+"/static", filepath.Join(common.GetRunPath(), "web", "static"))
 	beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
 	beego.SetViewsPath(filepath.Join(common.GetRunPath(), "web", "views"))
-	if l, err := connection.GetWebManagerListener(); err == nil {
+	err := errors.New("Web management startup failure ")
+	var l net.Listener
+	if l, err = connection.GetWebManagerListener(); err == nil {
 		beego.InitBeforeHTTPRun()
 		beego.InitBeforeHTTPRun()
-		http.Serve(l, beego.BeeApp.Handlers)
+		if beego.AppConfig.String("web_open_ssl") == "true" {
+			keyPath := beego.AppConfig.String("web_key_file")
+			certPath := beego.AppConfig.String("web_cert_file")
+			err = http.ServeTLS(l, beego.BeeApp.Handlers, certPath, keyPath)
+		} else {
+			err = http.Serve(l, beego.BeeApp.Handlers)
+		}
 	} else {
 	} else {
 		logs.Error(err)
 		logs.Error(err)
 	}
 	}
-	return errors.New("Web management startup failure")
+	return err
 }
 }
 
 
 func (s *WebServer) Close() error {
 func (s *WebServer) Close() error {

+ 0 - 50
update.sh

@@ -1,50 +0,0 @@
-#/bash/sh
-echo "start upgrading to the latest version"
-if [ $1 == "latest" ]
-then
-  version=`wget -qO- -t1 -T2 "https://api.github.com/repos/cnlh/nps/releases/latest" | grep "tag_name" | head -n 1 | awk -F ":" '{print $2}' | sed 's/\"//g;s/,//g;s/ //g'`
-else
-  version=$1
-fi
-echo "the current latest version is "$version""
-download_base_url=https://github.com/cnlh/nps/releases/download/$version/
-
-if [ $4 ]
-then
-  filename=""$2"_"$3"_v"$4"_"server".tar.gz"
-else
-  filename=""$2"_"$3"_"server".tar.gz"
-fi
-complete_download_url=""$download_base_url""$filename""
-echo "start download file from "$complete_download_url""
-
-dir_name=`echo $RANDOM`
-mkdir $dir_name && cd $dir_name
-wget $complete_download_url >/dev/null 2>&1
-if [ ! -f "$filename" ]; then
-  echo "download file failed!"
-  rm -rf $dir_name
-  exit
-fi
-
-echo "start extracting files"
-mkdir nps
-tar -xvf $filename -C ./nps  >/dev/null 2>&1
-cd nps
-
-if [ -f "../../nps" ]; then
-  echo "replace "../../nps"!"
-  cp -rf nps ../../
-fi
-
-usr_dir=`which nps`
-
-if [ -f "$usr_dir" ]; then
-  echo "replace "$usr_dir"!"
-  cp -rf nps $usr_dir
-fi
-
-cd ../../ && rm -rf $dir_name
-
-echo "update complete!"
-echo -e "\033[32m please restart nps \033[0m"

+ 44 - 0
web/controllers/login.go

@@ -1,6 +1,9 @@
 package controllers
 package controllers
 
 
 import (
 import (
+	"math/rand"
+	"net"
+	"sync"
 	"time"
 	"time"
 
 
 	"github.com/astaxie/beego"
 	"github.com/astaxie/beego"
@@ -13,12 +16,32 @@ type LoginController struct {
 	beego.Controller
 	beego.Controller
 }
 }
 
 
+var ipRecord sync.Map
+
+type record struct {
+	hasLoginFailTimes int
+	lastLoginTime     time.Time
+}
+
 func (self *LoginController) Index() {
 func (self *LoginController) Index() {
 	self.Data["web_base_url"] = beego.AppConfig.String("web_base_url")
 	self.Data["web_base_url"] = beego.AppConfig.String("web_base_url")
 	self.Data["register_allow"], _ = beego.AppConfig.Bool("allow_user_register")
 	self.Data["register_allow"], _ = beego.AppConfig.Bool("allow_user_register")
 	self.TplName = "login/index.html"
 	self.TplName = "login/index.html"
 }
 }
 func (self *LoginController) Verify() {
 func (self *LoginController) Verify() {
+	clearIprecord()
+	ip, _, _ := net.SplitHostPort(self.Ctx.Request.RemoteAddr)
+	if v, ok := ipRecord.Load(ip); ok {
+		vv := v.(*record)
+		if (time.Now().Unix() - vv.lastLoginTime.Unix()) >= 60 {
+			vv.hasLoginFailTimes = 0
+		}
+		if vv.hasLoginFailTimes >= 10 {
+			self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
+			self.ServeJSON()
+			return
+		}
+	}
 	var auth bool
 	var auth bool
 	if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") {
 	if self.GetString("password") == beego.AppConfig.String("web_password") && self.GetString("username") == beego.AppConfig.String("web_username") {
 		self.SetSession("isAdmin", true)
 		self.SetSession("isAdmin", true)
@@ -56,7 +79,14 @@ func (self *LoginController) Verify() {
 	if auth {
 	if auth {
 		self.SetSession("auth", true)
 		self.SetSession("auth", true)
 		self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"}
 		self.Data["json"] = map[string]interface{}{"status": 1, "msg": "login success"}
+		ipRecord.Delete(ip)
 	} else {
 	} else {
+		if v, load := ipRecord.LoadOrStore(ip, &record{hasLoginFailTimes: 1, lastLoginTime: time.Now()}); load {
+			vv := v.(*record)
+			vv.lastLoginTime = time.Now()
+			vv.hasLoginFailTimes += 1
+			ipRecord.Store(ip, vv)
+		}
 		self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
 		self.Data["json"] = map[string]interface{}{"status": 0, "msg": "username or password incorrect"}
 	}
 	}
 	self.ServeJSON()
 	self.ServeJSON()
@@ -97,3 +127,17 @@ func (self *LoginController) Out() {
 	self.SetSession("auth", false)
 	self.SetSession("auth", false)
 	self.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302)
 	self.Redirect(beego.AppConfig.String("web_base_url")+"/login/index", 302)
 }
 }
+
+func clearIprecord() {
+	rand.Seed(time.Now().UnixNano())
+	x := rand.Intn(100)
+	if x == 1 {
+		ipRecord.Range(func(key, value interface{}) bool {
+			v := value.(*record)
+			if time.Now().Unix()-v.lastLoginTime.Unix() >= 60 {
+				ipRecord.Delete(key)
+			}
+			return true
+		})
+	}
+}