安装 守护进程优化 web修改

pull/1219/head
刘河 2019-02-06 00:35:23 +08:00
parent 74b262503e
commit 7af09a2f4c
28 changed files with 406 additions and 3706 deletions

View File

@ -3,10 +3,12 @@ package main
import (
"flag"
"github.com/astaxie/beego"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/lib"
"github.com/cnlh/nps/server"
_ "github.com/cnlh/nps/web/routers"
"log"
"os"
"path/filepath"
)
const VERSION = "v0.0.13"
@ -26,12 +28,13 @@ var (
func main() {
flag.Parse()
var test bool
if len(os.Args) > 1 && os.Args[1] == "test" {
test = true
server.TestServerConfig()
log.Println("test ok, no error")
return
}
lib.InitDaemon("nps")
if *logType == "stdout" || test {
if *logType == "stdout" {
lib.InitLogFile("nps", true)
} else {
lib.InitLogFile("nps", false)
@ -61,7 +64,7 @@ func main() {
Flow: &lib.Flow{},
}
c.Cnf.CompressDecode, c.Cnf.CompressEncode = lib.GetCompressType(c.Cnf.Compress)
server.CsvDb.Clients[0] = c
lib.GetCsvDb().Clients[0] = c
task.Client = c
}
if *TcpPort == 0 {
@ -75,7 +78,8 @@ func main() {
lib.Println("服务端启动监听tcp服务端端口", *TcpPort)
task.Config.CompressDecode, task.Config.CompressEncode = lib.GetCompressType(task.Config.Compress)
if *rpMode != "webServer" {
server.CsvDb.Tasks[0] = task
lib.GetCsvDb().Tasks[0] = task
}
server.StartNewServer(*TcpPort, task, test)
beego.LoadAppConfig("ini", filepath.Join(lib.GetRunPath(), "conf", "app.conf"))
server.StartNewServer(*TcpPort, task)
}

View File

@ -1,7 +1,7 @@
appname = nps
#web管理端口
httpport = 8080
httpport = 8081
#启动模式dev|pro
runmode = dev
@ -15,10 +15,10 @@ tcpport=8284
#web api免验证IP地址
authip=127.0.0.1
##http代理端口
##http代理端口,为空则不启动
httpProxyPort=80
##https代理端口
##https代理端口,为空则不启动
httpsProxyPort=
##certFile绝对路径

View File

@ -0,0 +1 @@
1,ydiigrm4ghu7mym1,,true,,,0,,0,0
1 1 ydiigrm4ghu7mym1 true 0 0 0
1 1 ydiigrm4ghu7mym1 true 0 0 0

View File

@ -0,0 +1 @@
a.o.com,127.0.0.1:8081,1,,,测试
1 a.o.com 127.0.0.1:8081 1 测试
1 a.o.com 127.0.0.1:8081 1 测试

View File

@ -0,0 +1,4 @@
9001,tunnelServer,123.206.77.88:22,,,,1,0,0,0,1,1,true,测试tcp
53,udpServer,114.114.114.114:53,,,,1,0,0,0,2,1,true,udp
0,socks5Server,,,,,1,0,0,0,3,1,true,socks5
9005,httpProxyServer,,,,,1,0,0,0,4,1,true,
1 9001 tunnelServer 123.206.77.88:22 1 0 0 0 1 1 true 测试tcp
1 9001 tunnelServer 123.206.77.88:22 1 0 0 0 1 1 true 测试tcp
2 53 udpServer 114.114.114.114:53 1 0 0 0 2 1 true udp
3 0 socks5Server 1 0 0 0 3 1 true socks5
4 9005 httpProxyServer 1 0 0 0 4 1 true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 233 KiB

After

Width:  |  Height:  |  Size: 334 KiB

View File

@ -1,12 +1,11 @@
package lib
import (
"github.com/astaxie/beego"
"io/ioutil"
"log"
"os"
"os/exec"
"runtime"
"path/filepath"
"strconv"
"strings"
)
@ -33,39 +32,75 @@ func InitDaemon(f string) {
start(args, f)
os.Exit(0)
case "install":
InstallNps()
if f == "nps" {
InstallNps()
}
os.Exit(0)
case "status":
if status(f) {
log.Printf("%s is running", f)
} else {
log.Printf("%s is not running", f)
}
os.Exit(0)
}
}
func status(f string) bool {
var cmd *exec.Cmd
b, err := ioutil.ReadFile(filepath.Join(GetPidPath(), f+".pid"))
if err == nil {
if !IsWindows() {
cmd = exec.Command("/bin/sh", "-c", "ps -ax | awk '{ print $1 }' | grep "+string(b))
} else {
cmd = exec.Command("tasklist", )
}
out, _ := cmd.Output()
if strings.Index(string(out), string(b)) > -1 {
return true
}
}
return false
}
func start(osArgs []string, f string) {
if status(f) {
log.Printf(" %s is running", f)
return
}
cmd := exec.Command(osArgs[0], osArgs[1:]...)
cmd.Start()
log.Println("执行启动成功")
if cmd.Process.Pid > 0 {
log.Println("start ok , pid:", cmd.Process.Pid, "config path:", GetRunPath())
d1 := []byte(strconv.Itoa(cmd.Process.Pid))
ioutil.WriteFile(beego.AppPath+"/"+f+".pid", d1, 0600)
ioutil.WriteFile(filepath.Join(GetPidPath(), f+".pid"), d1, 0600)
} else {
log.Println("start error")
}
}
func stop(f string, p string) {
if !status(f) {
log.Printf(" %s is not running", f)
return
}
var c *exec.Cmd
var err error
switch runtime.GOOS {
case "windows":
if IsWindows() {
p := strings.Split(p, `\`)
c = exec.Command("taskkill", "/F", "/IM", p[len(p)-1])
case "linux", "darwin":
b, err := ioutil.ReadFile(beego.AppPath + "/" + f + ".pid")
} else {
b, err := ioutil.ReadFile(filepath.Join(GetPidPath(), f+".pid"))
if err == nil {
c = exec.Command("/bin/bash", "-c", `kill -9 `+string(b))
} else {
log.Println("停止服务失败,pid文件不存在")
log.Fatalln("stop error,PID file does not exist")
}
}
err = c.Run()
if err != nil {
log.Println("停止服务失败,", err)
log.Println("stop error,", err)
} else {
log.Println("停止服务成功")
log.Println("stop ok")
}
}

View File

@ -3,8 +3,8 @@ package lib
import (
"encoding/csv"
"errors"
"github.com/astaxie/beego"
"os"
"path/filepath"
"strconv"
"strings"
"sync"
@ -37,7 +37,7 @@ func (s *Csv) Init() {
func (s *Csv) StoreTasksToCsv() {
// 创建文件
csvFile, err := os.Create(beego.AppPath + "/conf/tasks.csv")
csvFile, err := os.Create(filepath.Join(GetRunPath(), "conf", "tasks.csv"))
if err != nil {
Fatalf(err.Error())
}
@ -87,7 +87,7 @@ func (s *Csv) openFile(path string) ([][]string, error) {
}
func (s *Csv) LoadTaskFromCsv() {
path := beego.AppPath + "/conf/tasks.csv"
path := filepath.Join(GetRunPath(), "conf", "tasks.csv")
records, err := s.openFile(path)
if err != nil {
Fatalln("配置文件打开错误:", path)
@ -186,7 +186,7 @@ func (s *Csv) GetTask(id int) (v *Tunnel, err error) {
func (s *Csv) StoreHostToCsv() {
// 创建文件
csvFile, err := os.Create(beego.AppPath + "/conf/hosts.csv")
csvFile, err := os.Create(filepath.Join(GetRunPath(), "conf", "hosts.csv"))
if err != nil {
panic(err)
}
@ -214,7 +214,7 @@ func (s *Csv) StoreHostToCsv() {
}
func (s *Csv) LoadClientFromCsv() {
path := beego.AppPath + "/conf/clients.csv"
path := filepath.Join(GetRunPath(), "conf", "clients.csv")
records, err := s.openFile(path)
if err != nil {
Fatalln("配置文件打开错误:", path)
@ -250,7 +250,7 @@ func (s *Csv) LoadClientFromCsv() {
}
func (s *Csv) LoadHostFromCsv() {
path := beego.AppPath + "/conf/hosts.csv"
path := filepath.Join(GetRunPath(), "conf", "hosts.csv")
records, err := s.openFile(path)
if err != nil {
Fatalln("配置文件打开错误:", path)
@ -389,7 +389,7 @@ func (s *Csv) GetClient(id int) (v *Client, err error) {
}
func (s *Csv) StoreClientsToCsv() {
// 创建文件
csvFile, err := os.Create(beego.AppPath + "/conf/clients.csv")
csvFile, err := os.Create(filepath.Join(GetRunPath(), "conf", "clients.csv"))
if err != nil {
Fatalln(err.Error())
}

View File

@ -7,34 +7,52 @@ import (
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
)
func InstallNps() {
var path string
switch runtime.GOOS {
case "windows":
path = "C:/"
case "linux", "darwin":
path = "/etc/nps/"
}
if err := os.Mkdir(path, 0755); err != nil {
log.Fatalf("创建目录%s失败:%s", path, err.Error())
}
path := GetInstallPath()
MkidrDirAll(path, "conf", "web/static", "web/views")
//复制文件到对应目录
if err := CopyDir("./web", path); err != nil {
if err := CopyDir(filepath.Join(GetAppPath(), "web", "views"), filepath.Join(path, "web", "views")); err != nil {
log.Fatalln(err)
}
if err := CopyDir("./conf", path); err != nil {
if err := CopyDir(filepath.Join(GetAppPath(), "web", "static"), filepath.Join(path, "web", "static")); err != nil {
log.Fatalln(err)
}
if err := CopyDir(filepath.Join(GetAppPath(), "conf"), filepath.Join(path, "conf")); err != nil {
log.Fatalln(err)
}
//linux加入到/etc/init.d
//windows处理
if !IsWindows() {
if _, err := copyFile(filepath.Join(GetAppPath(), "nps"), "/usr/bin/nps"); err != nil {
if _, err := copyFile(filepath.Join(GetAppPath(), "nps"), "/usr/local/bin/nps"); err != nil {
log.Fatalln(err)
} else {
os.Chmod("/usr/local/bin/nps", 0777)
log.Println("Executable files have been copied to", "/usr/local/bin/nps")
}
} else {
os.Chmod("/usr/bin/nps", 0777)
log.Println("Executable files have been copied to", "/usr/bin/nps")
}
//darwin处理
}
log.Println("install ok!")
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")
if !IsWindows() {
log.Println("You can start with nps test|start|stop|restart|status anywhere")
} else {
log.Println("You can copy executable files to any directory and start working with nps.exe test|start|stop|restart|status")
}
}
func MkidrDirAll(path string, v ... string) {
for _, item := range v {
if err := os.MkdirAll(filepath.Join(path, item), 0755); err != nil {
log.Fatalf("Failed to create directory %s error:%s", path, err.Error())
}
}
}
func CopyDir(srcPath string, destPath string) error {
@ -44,39 +62,29 @@ func CopyDir(srcPath string, destPath string) error {
return err
} else {
if !srcInfo.IsDir() {
e := errors.New("srcPath不是一个正确的目录")
fmt.Println(e.Error())
e := errors.New("SrcPath is not the right directory!")
return e
}
}
if destInfo, err := os.Stat(destPath); err != nil {
fmt.Println(err.Error())
return err
} else {
if !destInfo.IsDir() {
e := errors.New("destInfo不是一个正确的目录")
fmt.Println(e.Error())
e := errors.New("DestInfo is not the right directory!")
return e
}
}
//加上拷贝时间:不用可以去掉
destPath = destPath + "_" + time.Now().Format("20060102150405")
err := filepath.Walk(srcPath, func(path string, f os.FileInfo, err error) error {
if f == nil {
return err
}
if !f.IsDir() {
path := strings.Replace(path, "\\", "/", -1)
destNewPath := strings.Replace(path, srcPath, destPath, -1)
fmt.Println("复制文件:" + path + " 到 " + destNewPath)
log.Println("copy file ::" + path + " to " + destNewPath)
copyFile(path, destNewPath)
}
return nil
})
if err != nil {
fmt.Printf(err.Error())
}
return err
}
@ -84,32 +92,30 @@ func CopyDir(srcPath string, destPath string) error {
func copyFile(src, dest string) (w int64, err error) {
srcFile, err := os.Open(src)
if err != nil {
fmt.Println(err.Error())
return
}
defer srcFile.Close()
//分割path目录
destSplitPathDirs := strings.Split(dest, "/")
destSplitPathDirs := strings.Split(dest, string(filepath.Separator))
//检测时候存在目录
destSplitPath := ""
for index, dir := range destSplitPathDirs {
if index < len(destSplitPathDirs)-1 {
destSplitPath = destSplitPath + dir + "/"
destSplitPath = destSplitPath + dir + string(filepath.Separator)
b, _ := pathExists(destSplitPath)
if b == false {
fmt.Println("创建目录:" + destSplitPath)
log.Println("mkdir:" + destSplitPath)
//创建目录
err := os.Mkdir(destSplitPath, os.ModePerm)
if err != nil {
fmt.Println(err)
log.Fatalln(err)
}
}
}
}
dstFile, err := os.Create(dest)
if err != nil {
fmt.Println(err.Error())
return
}
defer dstFile.Close()

View File

@ -1,9 +1,9 @@
package lib
import (
"github.com/astaxie/beego"
"log"
"os"
"path/filepath"
"runtime"
)
@ -12,9 +12,9 @@ var Log *log.Logger
func InitLogFile(f string, isStdout bool) {
var prefix string
if !isStdout {
logFile, err := os.OpenFile(beego.AppPath+"/"+f+"_log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
logFile, err := os.OpenFile(filepath.Join(GetLogPath(), f+"_log.txt"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
if err != nil {
log.Fatalln("open file error !")
log.Fatalln("open file error !", err)
}
if runtime.GOOS == "windows" {
prefix = "\r\n"

View File

@ -6,7 +6,9 @@ import (
"net"
"net/http"
"os"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
)
@ -151,7 +153,6 @@ func ReadAllFromFile(filePath string) ([]byte, error) {
return ioutil.ReadAll(f)
}
// FileExists reports whether the named file or directory exists.
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
@ -160,4 +161,60 @@ func FileExists(name string) bool {
}
}
return true
}
}
func GetRunPath() string {
var path string
if path = GetInstallPath(); !FileExists(path) {
return "./"
}
return path
}
func GetInstallPath() string {
var path string
if IsWindows() {
path = `C:\Program Files\nps`
} else {
path = "/etc/nps"
}
return path
}
func GetAppPath() string {
if path, err := filepath.Abs(filepath.Dir(os.Args[0])); err == nil {
return path
}
return os.Args[0]
}
func IsWindows() bool {
if runtime.GOOS == "windows" {
return true
}
return false
}
func GetLogPath() string {
var path string
if IsWindows() {
path = "./"
} else {
path = "/tmp"
}
return path
}
func GetPidPath() string {
var path string
if IsWindows() {
path = "./"
} else {
path = "/tmp"
}
return path
}
func TestTcpPort(port int) bool {
l, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
if err != nil {
return false
}
return true
}

View File

@ -36,7 +36,7 @@ func (s *server) FlowAddHost(host *lib.Host, in, out int64) {
//热更新配置
func (s *server) ResetConfig() bool {
//获取最新数据
task, err := CsvDb.GetTask(s.task.Id)
task, err := lib.GetCsvDb().GetTask(s.task.Id)
if err != nil {
return false
}
@ -45,7 +45,7 @@ func (s *server) ResetConfig() bool {
}
s.task.UseClientCnf = task.UseClientCnf
//使用客户端配置
client, err := CsvDb.GetClient(s.task.Client.Id)
client, err := lib.GetCsvDb().GetClient(s.task.Client.Id)
if s.task.UseClientCnf {
if err == nil {
s.config.U = client.Cnf.U

View File

@ -6,9 +6,9 @@ import (
"github.com/astaxie/beego"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib"
"net"
"net/http"
"net/http/httputil"
"path/filepath"
"strconv"
"sync"
)
@ -44,14 +44,11 @@ func NewHttp(bridge *bridge.Bridge, c *lib.Tunnel) *httpServer {
func (s *httpServer) Start() error {
var err error
var http, https *http.Server
if s.errorContent, err = lib.ReadAllFromFile(beego.AppPath + "/web/static/page/error.html"); err != nil {
if s.errorContent, err = lib.ReadAllFromFile(filepath.Join(lib.GetRunPath(), "web", "static", "page", "error.html")); err != nil {
s.errorContent = []byte("easyProxy 404")
}
if s.httpPort > 0 {
if !s.TestTcpPort(s.httpPort) {
lib.Fatalln("http端口", s.httpPort, "被占用!")
}
http = s.NewServer(s.httpPort)
go func() {
lib.Println("启动http监听,端口为", s.httpPort)
@ -62,9 +59,6 @@ func (s *httpServer) Start() error {
}()
}
if s.httpsPort > 0 {
if !s.TestTcpPort(s.httpsPort) {
lib.Fatalln("https端口", s.httpsPort, "被占用!")
}
if !lib.FileExists(s.pemPath) {
lib.Fatalf("ssl certFile文件%s不存在", s.pemPath)
}
@ -80,7 +74,6 @@ func (s *httpServer) Start() error {
}
}()
}
startFinish <- true
select {
case <-s.stop:
if http != nil {
@ -90,7 +83,6 @@ func (s *httpServer) Start() error {
https.Close()
}
}
return nil
}
@ -180,12 +172,3 @@ func (s *httpServer) NewServer(port int) *http.Server {
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
}
}
func (s *httpServer) TestTcpPort(port int) bool {
l, err := net.ListenTCP("tcp", &net.TCPAddr{net.ParseIP("0.0.0.0"), port, ""})
defer l.Close()
if err != nil {
return false
}
return true
}

View File

@ -4,8 +4,6 @@ import (
"errors"
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib"
"log"
"os"
"reflect"
"strings"
)
@ -13,7 +11,6 @@ import (
var (
Bridge *bridge.Bridge
RunList map[int]interface{} //运行中的任务
CsvDb = lib.GetCsvDb()
startFinish chan bool
)
@ -24,7 +21,7 @@ func init() {
//从csv文件中恢复任务
func InitFromCsv() {
for _, v := range CsvDb.Tasks {
for _, v := range lib.GetCsvDb().Tasks {
if v.Status {
lib.Println("启动模式:", v.Mode, "监听端口:", v.TcpPort)
AddTask(v)
@ -33,31 +30,21 @@ func InitFromCsv() {
}
//start a new server
func StartNewServer(bridgePort int, cnf *lib.Tunnel, test bool) {
go func() {
Bridge = bridge.NewTunnel(bridgePort, RunList)
if err := Bridge.StartTunnel(); err != nil {
lib.Fatalln("服务端开启失败", err)
}
if svr := NewMode(Bridge, cnf); svr != nil {
RunList[cnf.Id] = svr
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
if err.Interface() != nil {
lib.Fatalln(err)
}
} else {
lib.Fatalln("启动模式不正确")
}
}()
for {
select {
case <-startFinish:
if test {
log.Println("测试完成,未发现错误")
os.Exit(0)
}
}
func StartNewServer(bridgePort int, cnf *lib.Tunnel) {
Bridge = bridge.NewTunnel(bridgePort, RunList)
if err := Bridge.StartTunnel(); err != nil {
lib.Fatalln("服务端开启失败", err)
}
if svr := NewMode(Bridge, cnf); svr != nil {
RunList[cnf.Id] = svr
err := reflect.ValueOf(svr).MethodByName("Start").Call(nil)[0]
if err.Interface() != nil {
lib.Fatalln(err)
}
} else {
lib.Fatalln("启动模式不正确")
}
}
//new a server by mode name
@ -94,11 +81,11 @@ func NewMode(Bridge *bridge.Bridge, c *lib.Tunnel) interface{} {
func StopServer(id int) error {
if v, ok := RunList[id]; ok {
reflect.ValueOf(v).MethodByName("Close").Call(nil)
if t, err := CsvDb.GetTask(id); err != nil {
if t, err := lib.GetCsvDb().GetTask(id); err != nil {
return err
} else {
t.Status = false
CsvDb.UpdateTask(t)
lib.GetCsvDb().UpdateTask(t)
}
return nil
}
@ -124,12 +111,12 @@ func AddTask(t *lib.Tunnel) error {
//start task
func StartTask(id int) error {
if t, err := CsvDb.GetTask(id); err != nil {
if t, err := lib.GetCsvDb().GetTask(id); err != nil {
return err
} else {
AddTask(t)
t.Status = true
CsvDb.UpdateTask(t)
lib.GetCsvDb().UpdateTask(t)
}
return nil
}
@ -139,12 +126,12 @@ func DelTask(id int) error {
if err := StopServer(id); err != nil {
return err
}
return CsvDb.DelTask(id)
return lib.GetCsvDb().DelTask(id)
}
//get key by host from x
func GetInfoByHost(host string) (h *lib.Host, err error) {
for _, v := range CsvDb.Hosts {
for _, v := range lib.GetCsvDb().Hosts {
s := strings.Split(host, ":")
if s[0] == v.Host {
h = v
@ -159,7 +146,7 @@ func GetInfoByHost(host string) (h *lib.Host, err error) {
func GetTunnel(start, length int, typeVal string, clientId int) ([]*lib.Tunnel, int) {
list := make([]*lib.Tunnel, 0)
var cnt int
for _, v := range CsvDb.Tasks {
for _, v := range lib.GetCsvDb().Tasks {
if (typeVal != "" && v.Mode != typeVal) || (typeVal == "" && clientId != v.Client.Id) {
continue
}
@ -185,7 +172,7 @@ func GetTunnel(start, length int, typeVal string, clientId int) ([]*lib.Tunnel,
//获取客户端列表
func GetClientList(start, length int) (list []*lib.Client, cnt int) {
list, cnt = CsvDb.GetClientList(start, length)
list, cnt = lib.GetCsvDb().GetClientList(start, length)
dealClientData(list)
return
}
@ -199,13 +186,13 @@ func dealClientData(list []*lib.Client) {
}
v.Flow.InletFlow = 0
v.Flow.ExportFlow = 0
for _, h := range CsvDb.Hosts {
for _, h := range lib.GetCsvDb().Hosts {
if h.Client.Id == v.Id {
v.Flow.InletFlow += h.Flow.InletFlow
v.Flow.ExportFlow += h.Flow.ExportFlow
}
}
for _, t := range CsvDb.Tasks {
for _, t := range lib.GetCsvDb().Tasks {
if t.Client.Id == v.Id {
v.Flow.InletFlow += t.Flow.InletFlow
v.Flow.ExportFlow += t.Flow.ExportFlow
@ -217,14 +204,14 @@ func dealClientData(list []*lib.Client) {
//根据客户端id删除其所属的所有隧道和域名
func DelTunnelAndHostByClientId(clientId int) {
for _, v := range CsvDb.Tasks {
for _, v := range lib.GetCsvDb().Tasks {
if v.Client.Id == clientId {
DelTask(v.Id)
}
}
for _, v := range CsvDb.Hosts {
for _, v := range lib.GetCsvDb().Hosts {
if v.Client.Id == clientId {
CsvDb.DelHost(v.Host)
lib.GetCsvDb().DelHost(v.Host)
}
}
}
@ -236,9 +223,9 @@ func DelClientConnect(clientId int) {
func GetDashboardData() map[string]int {
data := make(map[string]int)
data["hostCount"] = len(CsvDb.Hosts)
data["clientCount"] = len(CsvDb.Clients)
list := CsvDb.Clients
data["hostCount"] = len(lib.GetCsvDb().Hosts)
data["clientCount"] = len(lib.GetCsvDb().Clients)
list := lib.GetCsvDb().Clients
dealClientData(list)
c := 0
var in, out int64
@ -252,7 +239,7 @@ func GetDashboardData() map[string]int {
data["clientOnlineCount"] = c
data["inletFlowCount"] = int(in)
data["exportFlowCount"] = int(out)
for _, v := range CsvDb.Tasks {
for _, v := range lib.GetCsvDb().Tasks {
switch v.Mode {
case "tunnelServer":
data["tunnelServerCount"] += 1

View File

@ -6,6 +6,7 @@ import (
"github.com/cnlh/nps/bridge"
"github.com/cnlh/nps/lib"
"net"
"path/filepath"
"strings"
)
@ -71,10 +72,14 @@ type WebServer struct {
//开始
func (s *WebServer) Start() error {
p, _ := beego.AppConfig.Int("httpport")
if !lib.TestTcpPort(p) {
lib.Fatalln("web管理端口", p, "被占用!")
}
beego.BConfig.WebConfig.Session.SessionOn = true
lib.Println("web管理启动访问端口为", beego.AppConfig.String("httpport"))
beego.SetViewsPath(beego.AppPath + "/web/views")
beego.SetStaticPath("/static", beego.AppPath+"/web/static")
beego.SetStaticPath("/static", filepath.Join(lib.GetRunPath(), "web", "static"))
beego.SetViewsPath(filepath.Join(lib.GetRunPath(), "web", "views"))
beego.Run()
return errors.New("web管理启动失败")
}

54
server/test.go Normal file
View File

@ -0,0 +1,54 @@
package server
import (
"github.com/astaxie/beego"
"github.com/cnlh/nps/lib"
"log"
"strconv"
)
func TestServerConfig() {
var postArr []int
for _, v := range lib.GetCsvDb().Tasks {
isInArr(&postArr, v.TcpPort, v.Remark)
}
p, err := beego.AppConfig.Int("httpport")
if err != nil {
log.Fatalln("Getting web management port error :", err)
} else {
isInArr(&postArr, p, "WebmManagement port")
}
if p := beego.AppConfig.String("httpProxyPort"); p != "" {
if port, err := strconv.Atoi(p); err != nil {
log.Fatalln("get http port error:", err)
} else {
isInArr(&postArr, port, "https port")
}
}
if p := beego.AppConfig.String("httpsProxyPort"); p != "" {
if port, err := strconv.Atoi(p); err != nil {
log.Fatalln("get https port error", err)
} else {
if !lib.FileExists(beego.AppConfig.String("pemPath")) {
log.Fatalf("ssl certFile %s is not exist", beego.AppConfig.String("pemPath"))
}
if !lib.FileExists(beego.AppConfig.String("ketPath")) {
log.Fatalf("ssl keyFile %s is not exist", beego.AppConfig.String("pemPath"))
}
isInArr(&postArr, port, "http port")
}
}
}
func isInArr(arr *[]int, val int, remark string) {
for _, v := range *arr {
if v == val {
log.Fatalf("the port %d is reused,remark: %s", val, remark)
}
}
if !lib.TestTcpPort(val) {
log.Fatalf("open the %d port error ,remark: %s", val, remark)
}
*arr = append(*arr, val)
return
}

View File

@ -2,8 +2,8 @@ package controllers
import (
"github.com/astaxie/beego"
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/lib"
"github.com/cnlh/nps/server"
"strconv"
"strings"
)

View File

@ -1,8 +1,8 @@
package controllers
import (
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/lib"
"github.com/cnlh/nps/server"
)
type ClientController struct {
@ -30,7 +30,7 @@ func (s *ClientController) Add() {
} else {
t := &lib.Client{
VerifyKey: lib.GetRandomString(16),
Id: server.CsvDb.GetClientId(),
Id: lib.GetCsvDb().GetClientId(),
Status: true,
Remark: s.GetString("remark"),
Cnf: &lib.Config{
@ -50,7 +50,7 @@ func (s *ClientController) Add() {
t.Rate = lib.NewRate(int64(t.RateLimit * 1024))
t.Rate.Start()
}
server.CsvDb.NewClient(t)
lib.GetCsvDb().NewClient(t)
s.AjaxOk("添加成功")
}
}
@ -58,7 +58,7 @@ func (s *ClientController) GetClient() {
if s.Ctx.Request.Method == "POST" {
id := s.GetIntNoErr("id")
data := make(map[string]interface{})
if c, err := server.CsvDb.GetClient(id); err != nil {
if c, err := lib.GetCsvDb().GetClient(id); err != nil {
data["code"] = 0
} else {
data["code"] = 1
@ -74,7 +74,7 @@ func (s *ClientController) Edit() {
id := s.GetIntNoErr("id")
if s.Ctx.Request.Method == "GET" {
s.Data["menu"] = "client"
if c, err := server.CsvDb.GetClient(id); err != nil {
if c, err := lib.GetCsvDb().GetClient(id); err != nil {
s.error()
} else {
s.Data["c"] = c
@ -82,7 +82,7 @@ func (s *ClientController) Edit() {
s.SetInfo("修改")
s.display()
} else {
if c, err := server.CsvDb.GetClient(id); err != nil {
if c, err := lib.GetCsvDb().GetClient(id); err != nil {
s.error()
} else {
c.Remark = s.GetString("remark")
@ -101,7 +101,7 @@ func (s *ClientController) Edit() {
} else {
c.Rate = nil
}
server.CsvDb.UpdateClient(c)
lib.GetCsvDb().UpdateClient(c)
}
s.AjaxOk("修改成功")
}
@ -110,7 +110,7 @@ func (s *ClientController) Edit() {
//更改状态
func (s *ClientController) ChangeStatus() {
id := s.GetIntNoErr("id")
if client, err := server.CsvDb.GetClient(id); err == nil {
if client, err := lib.GetCsvDb().GetClient(id); err == nil {
client.Status = s.GetBoolNoErr("status")
if client.Status == false {
server.DelClientConnect(client.Id)
@ -123,7 +123,7 @@ func (s *ClientController) ChangeStatus() {
//删除客户端
func (s *ClientController) Del() {
id := s.GetIntNoErr("id")
if err := server.CsvDb.DelClient(id); err != nil {
if err := lib.GetCsvDb().DelClient(id); err != nil {
s.AjaxErr("删除失败")
}
server.DelTunnelAndHostByClientId(id)

View File

@ -1,8 +1,8 @@
package controllers
import (
"github.com/cnlh/nps/server"
"github.com/cnlh/nps/lib"
"github.com/cnlh/nps/server"
)
type IndexController struct {
@ -82,17 +82,17 @@ func (s *IndexController) Add() {
Compress: s.GetString("compress"),
Crypt: s.GetBoolNoErr("crypt"),
},
Id: server.CsvDb.GetTaskId(),
Id: lib.GetCsvDb().GetTaskId(),
UseClientCnf: s.GetBoolNoErr("use_client"),
Status: true,
Remark: s.GetString("remark"),
Flow: &lib.Flow{},
}
var err error
if t.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
if t.Client, err = lib.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr(err.Error())
}
server.CsvDb.NewTask(t)
lib.GetCsvDb().NewTask(t)
if err := server.AddTask(t); err != nil {
s.AjaxErr(err.Error())
} else {
@ -103,7 +103,7 @@ func (s *IndexController) Add() {
func (s *IndexController) GetOneTunnel() {
id := s.GetIntNoErr("id")
data := make(map[string]interface{})
if t, err := server.CsvDb.GetTask(id); err != nil {
if t, err := lib.GetCsvDb().GetTask(id); err != nil {
data["code"] = 0
} else {
data["code"] = 1
@ -115,7 +115,7 @@ func (s *IndexController) GetOneTunnel() {
func (s *IndexController) Edit() {
id := s.GetIntNoErr("id")
if s.Ctx.Request.Method == "GET" {
if t, err := server.CsvDb.GetTask(id); err != nil {
if t, err := lib.GetCsvDb().GetTask(id); err != nil {
s.error()
} else {
s.Data["t"] = t
@ -123,7 +123,7 @@ func (s *IndexController) Edit() {
s.SetInfo("修改")
s.display()
} else {
if t, err := server.CsvDb.GetTask(id); err != nil {
if t, err := lib.GetCsvDb().GetTask(id); err != nil {
s.error()
} else {
t.TcpPort = s.GetIntNoErr("port")
@ -137,10 +137,10 @@ func (s *IndexController) Edit() {
t.Config.Crypt = s.GetBoolNoErr("crypt")
t.UseClientCnf = s.GetBoolNoErr("use_client")
t.Remark = s.GetString("remark")
if t.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
if t.Client, err = lib.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr("修改失败")
}
server.CsvDb.UpdateTask(t)
lib.GetCsvDb().UpdateTask(t)
}
s.AjaxOk("修改成功")
}
@ -179,7 +179,7 @@ func (s *IndexController) HostList() {
} else {
start, length := s.GetAjaxParams()
clientId := s.GetIntNoErr("client_id")
list, cnt := server.CsvDb.GetHost(start, length, clientId)
list, cnt := lib.GetCsvDb().GetHost(start, length, clientId)
s.AjaxTable(list, cnt, cnt)
}
}
@ -200,7 +200,7 @@ func (s *IndexController) GetHost() {
func (s *IndexController) DelHost() {
host := s.GetString("host")
if err := server.CsvDb.DelHost(host); err != nil {
if err := lib.GetCsvDb().DelHost(host); err != nil {
s.AjaxErr("删除失败")
}
s.AjaxOk("删除成功")
@ -222,10 +222,10 @@ func (s *IndexController) AddHost() {
Flow: &lib.Flow{},
}
var err error
if h.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
if h.Client, err = lib.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr("添加失败")
}
server.CsvDb.NewHost(h)
lib.GetCsvDb().NewHost(h)
s.AjaxOk("添加成功")
}
}
@ -251,9 +251,9 @@ func (s *IndexController) EditHost() {
h.HostChange = s.GetString("hostchange")
h.Remark = s.GetString("remark")
h.TargetArr = nil
server.CsvDb.UpdateHost(h)
lib.GetCsvDb().UpdateHost(h)
var err error
if h.Client, err = server.CsvDb.GetClient(s.GetIntNoErr("client_id")); err != nil {
if h.Client, err = lib.GetCsvDb().GetClient(s.GetIntNoErr("client_id")); err != nil {
s.AjaxErr("修改失败")
}
}

File diff suppressed because it is too large Load Diff

22
web/static/js/echarts.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
<div class="row tile">
<div class="col-md-6 col-md-auto">
<div>
<h3 class="tile-title"></h3>
<h3 class="tile-title"></h3>
<div class="tile-body">
<form>
<input type="hidden" name="id" value="{{.c.Id}}">

View File

@ -1,12 +1,4 @@
<div class="row tile">
<div class="col-lg-12">
<div class="bs-component">
<div class="alert alert-dismissible alert-success">
<button class="close" type="button" data-dismiss="alert">×</button>
<span id="info"></span>
</div>
</div>
</div>
<div class="col-md-6 col-md-auto">
<div>
<h3 class="tile-title"></h3>

View File

@ -1,7 +1,7 @@
<div class="row tile">
<div class="col-md-6 col-md-auto">
<div>
<h3 class="tile-title"></h3>
<h3 class="tile-title"></h3>
<div class="tile-body">
<form>
<input type="hidden" name="id" value="{{.t.Id}}">

View File

@ -20,7 +20,7 @@
<div class="form-group">
<label class="control-label"></label>
<textarea class="form-control" rows="4" type="text" name="target"
placeholder="内网隧道目标例如10.1.50.203:22换行分隔"></textarea>
placeholder="内网隧道目标例如10.1.50.203:22如需负载均衡多个地址换行分隔"></textarea>
</div>
<div class="form-group" id="header">
<label class="control-label">header()</label>

View File

@ -2,7 +2,7 @@
<div class="col-md-3">
<div class="widget-small warning coloured-icon"><i class="icon fa fa-html5 fa-3x"></i>
<div class="info">
<h4>HTTP</h4>
<h4></h4>
<p><b>{{.p}}</b></p>
</div>
</div>
@ -36,69 +36,95 @@
<div class="col-md-6">
<div class="tile">
<h3 class="tile-title"></h3>
<div class="embed-responsive embed-responsive-16by9">
<canvas class="embed-responsive-item" id="flow"></canvas>
</div>
<div id="flow" style="width: 600px;height:400px;"></div>
</div>
</div>
<div class="col-md-6">
<div class="tile">
<h3 class="tile-title"></h3>
<div class="embed-responsive embed-responsive-16by9">
<canvas class="embed-responsive-item" id="types"></canvas>
</div>
<div id="tj" style="width: 600px;height:400px;"></div>
</div>
</div>
</div>
<script>
var pdataFlow = [
{
value: {{.data.inletFlowCount}},
color: "#46BFBD",
highlight: "#5AD3D1",
label: "入口流量"
option = {
title : {
x:'center'
},
{
value: {{.data.exportFlowCount}},
color: "#FDB45C",
highlight: "#FFC870",
label: "出口流量"
}
]
var pdataTypes = [
{
value: {{.data.tunnelServerCount}},
color: "#46BFBD",
highlight: "#5AD3D1",
label: "tcp隧道"
tooltip: {
trigger: 'item',
formatter: function (p) {
return p.seriesName + "<br>" + p.name + ":" + change(p.data.value);
},
},
{
value: {{.data.socks5ServerCount}},
color: "#85FEAA",
highlight: "#85FEAA",
label: "socks5隧道"
legend: {
orient: 'vertical',
left: 'left',
data: ['', '']
},
{
value: {{.data.httpProxyServerCount}},
color: "#4B653C",
highlight: "#4B653C",
label: "http代理"
series : [
{
name: ' ',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data:[
{value:{{.data.inletFlowCount}}, name: ''},
{value:{{.data.exportFlowCount}}, name: ''},
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
var myChart = echarts.init(document.getElementById('flow'));
myChart.setOption(option);
option = {
title : {
x:'center'
},
{
value: {{.data.udpServerCount}},
color: "#90653C",
highlight: "#90653C",
label: "udp代理"
tooltip : {
trigger: 'item',
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
{
value: {{.data.hostCount}},
color: "#FDB45C",
highlight: "#FDB45C",
label: "域名解析"
}
]
var ctxp = $("#flow").get(0).getContext("2d");
var pieChart = new Chart(ctxp).Pie(pdataFlow);
var ctxd = $("#types").get(0).getContext("2d");
var doughnutChart = new Chart(ctxd).Doughnut(pdataTypes);
legend: {
orient: 'vertical',
left: 'left',
data: ['tcp','socks5','http','udp','']
},
series : [
{
name: ' ',
type: 'pie',
radius : '55%',
center: ['50%', '60%'],
data:[
{value:{{.data.tunnelServerCount}}, name:'tcp'},
{value:{{.data.socks5ServerCount}}, name:'socks5'},
{value:{{.data.httpProxyServerCount}}, name:'http'},
{value:{{.data.udpServerCount}}, name:'udp'},
{value:{{.data.hostCount}}, name:''}
],
itemStyle: {
emphasis: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
var myChart = echarts.init(document.getElementById('tj'));
myChart.setOption(option);
</script>

View File

@ -9,7 +9,7 @@
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
<!-- Font-icon css-->
<link rel="stylesheet" type="text/css" href="/static/css/font-awesome.min.css">
<title>easyProxy穿</title>
<title>nps穿</title>
</head>
<body>
<section class="material-half-bg">

View File

@ -4,7 +4,7 @@
<meta name="description"
content="Vali is a responsive and free admin theme built with Bootstrap 4, SASS and PUG.js. It's fully customizable and modular.">
<link rel="shortcut icon" href="/static/img/favicon.ico">
<title>easyProxy穿</title>
<title>nps穿</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
@ -61,7 +61,7 @@
<script type="text/javascript" src="/static/js/datatables.min.js"></script>
<script src="/static/js/main.js"></script>
<script src="/static/js/chart.js"></script>
<script src="/static/js/echarts.min.js"></script>
<main class="app-content">
<div class="app-title">
<div>