csv file change

This commit is contained in:
刘河 2019-03-29 13:31:11 +08:00
parent 58cb05e302
commit cd7f99063c
9 changed files with 120 additions and 257 deletions

View File

@ -1,2 +0,0 @@
12,ao0yd0jx6ty0ht69,,true,,,0,false,0,0,0,1
11,mxg22qa06dc137of,,true,,,0,false,0,0,0,1
1 12 ao0yd0jx6ty0ht69 true 0 false 0 0 0 1
2 11 mxg22qa06dc137of true 0 false 0 0 0 1

0
conf/clients.json Normal file
View File

View File

@ -1 +0,0 @@
a.o.com,123.206.77.88:8080,11,,,,/,1,0,0,all
1 a.o.com 123.206.77.88:8080 11 / 1 0 0 all

0
conf/hosts.json Normal file
View File

View File

@ -1 +0,0 @@
9999,tcp,,1,3,11,,0,0,,0.0.0.0
1 9999 tcp 1 3 11 0 0 0.0.0.0

0
conf/tasks.json Normal file
View File

View File

@ -1,18 +1,16 @@
package file package file
import ( import (
"encoding/csv" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"github.com/cnlh/nps/lib/common" "github.com/cnlh/nps/lib/common"
"github.com/cnlh/nps/lib/crypt" "github.com/cnlh/nps/lib/crypt"
"github.com/cnlh/nps/lib/rate" "github.com/cnlh/nps/lib/rate"
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -21,6 +19,9 @@ import (
func NewCsv(runPath string) *Csv { func NewCsv(runPath string) *Csv {
return &Csv{ return &Csv{
RunPath: runPath, RunPath: runPath,
TaskFilePath: filepath.Join(runPath, "conf", "tasks.json"),
HostFilePath: filepath.Join(runPath, "conf", "hosts.json"),
ClientFilePath: filepath.Join(runPath, "conf", "clients.json"),
} }
} }
@ -33,96 +34,62 @@ type Csv struct {
ClientIncreaseId int32 //客户端id ClientIncreaseId int32 //客户端id
TaskIncreaseId int32 //任务自增ID TaskIncreaseId int32 //任务自增ID
HostIncreaseId int32 //host increased id HostIncreaseId int32 //host increased id
} TaskFilePath string
HostFilePath string
func (s *Csv) StoreTasksToCsv() { ClientFilePath string
// 创建文件
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "tasks.csv"))
if err != nil {
logs.Error(err.Error())
}
defer csvFile.Close()
writer := csv.NewWriter(csvFile)
s.Tasks.Range(func(key, value interface{}) bool {
task := value.(*Tunnel)
if task.NoStore {
return true
}
record := []string{
strconv.Itoa(task.Port),
task.Mode,
task.Target.TargetStr,
common.GetStrByBool(task.Status),
strconv.Itoa(task.Id),
strconv.Itoa(task.Client.Id),
task.Remark,
strconv.Itoa(int(task.Flow.ExportFlow)),
strconv.Itoa(int(task.Flow.InletFlow)),
task.Password,
task.ServerIp,
}
err := writer.Write(record)
if err != nil {
logs.Error(err.Error())
}
return true
})
writer.Flush()
}
func (s *Csv) openFile(path string) ([][]string, error) {
// 打开文件
file, err := os.Open(path)
if err != nil {
panic(err)
}
defer file.Close()
// 获取csv的reader
reader := csv.NewReader(file)
// 设置FieldsPerRecord为-1
reader.FieldsPerRecord = -1
// 读取文件中所有行保存到slice中
return reader.ReadAll()
} }
func (s *Csv) LoadTaskFromCsv() { func (s *Csv) LoadTaskFromCsv() {
path := filepath.Join(s.RunPath, "conf", "tasks.csv") loadSyncMapFromFile(s.TaskFilePath, func(v string) {
records, err := s.openFile(path) var err error
if err != nil { post := new(Tunnel)
logs.Error("Profile Opening Error:", path) if json.Unmarshal([]byte(v), &post) != nil {
os.Exit(0) return
} }
// 将每一行数据保存到内存slice中 if post.Client, err = s.GetClient(post.Client.Id); err != nil {
for _, item := range records { return
post := &Tunnel{
Port: common.GetIntNoErrByStr(item[0]),
Mode: item[1],
Status: common.GetBoolByStr(item[3]),
Id: common.GetIntNoErrByStr(item[4]),
Remark: item[6],
Password: item[9],
}
post.Target = new(Target)
post.Target.TargetStr = item[2]
post.Flow = new(Flow)
post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[7]))
post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[8]))
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[5])); err != nil {
continue
}
if len(item) > 10 {
post.ServerIp = item[10]
} else {
post.ServerIp = "0.0.0.0"
} }
s.Tasks.Store(post.Id, post) s.Tasks.Store(post.Id, post)
if post.Id > int(s.TaskIncreaseId) { if post.Id > int(s.TaskIncreaseId) {
s.TaskIncreaseId = int32(s.TaskIncreaseId) s.TaskIncreaseId = int32(post.Id)
} }
})
}
func (s *Csv) LoadClientFromCsv() {
loadSyncMapFromFile(s.ClientFilePath, func(v string) {
post := new(Client)
if json.Unmarshal([]byte(v), &post) != nil {
return
} }
if post.RateLimit > 0 {
post.Rate = rate.NewRate(int64(post.RateLimit * 1024))
} else {
post.Rate = rate.NewRate(int64(2 << 23))
}
post.Rate.Start()
s.Clients.Store(post.Id, post)
if post.Id > int(s.ClientIncreaseId) {
s.ClientIncreaseId = int32(post.Id)
}
})
}
func (s *Csv) LoadHostFromCsv() {
loadSyncMapFromFile(s.HostFilePath, func(v string) {
var err error
post := new(Host)
if json.Unmarshal([]byte(v), &post) != nil {
return
}
if post.Client, err = s.GetClient(post.Client.Id); err != nil {
return
}
s.Hosts.Store(post.Id, post)
if post.Id > int(s.HostIncreaseId) {
s.HostIncreaseId = int32(post.Id)
}
})
} }
func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (id int, err error) { func (s *Csv) GetIdByVerifyKey(vKey string, addr string) (id int, err error) {
@ -195,135 +162,15 @@ func (s *Csv) GetTask(id int) (t *Tunnel, err error) {
} }
func (s *Csv) StoreHostToCsv() { func (s *Csv) StoreHostToCsv() {
// 创建文件 storeSyncMapToFile(s.Hosts, s.HostFilePath)
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "hosts.csv"))
if err != nil {
panic(err)
}
defer csvFile.Close()
// 获取csv的Writer
writer := csv.NewWriter(csvFile)
// 将map中的Post转换成slice因为csv的Write需要slice参数
// 并写入csv文件
s.Hosts.Range(func(key, value interface{}) bool {
host := value.(*Host)
if host.NoStore {
return true
}
record := []string{
host.Host,
host.Target.TargetStr,
strconv.Itoa(host.Client.Id),
host.HeaderChange,
host.HostChange,
host.Remark,
host.Location,
strconv.Itoa(host.Id),
strconv.Itoa(int(host.Flow.ExportFlow)),
strconv.Itoa(int(host.Flow.InletFlow)),
host.Scheme,
}
err1 := writer.Write(record)
if err1 != nil {
panic(err1)
}
return true
})
// 确保所有内存数据刷到csv文件
writer.Flush()
} }
func (s *Csv) LoadClientFromCsv() { func (s *Csv) StoreTasksToCsv() {
path := filepath.Join(s.RunPath, "conf", "clients.csv") storeSyncMapToFile(s.Tasks, s.TaskFilePath)
records, err := s.openFile(path)
if err != nil {
logs.Error("Profile Opening Error:", path)
os.Exit(0)
}
// 将每一行数据保存到内存slice中
for _, item := range records {
post := &Client{
Id: common.GetIntNoErrByStr(item[0]),
VerifyKey: item[1],
Remark: item[2],
Status: common.GetBoolByStr(item[3]),
RateLimit: common.GetIntNoErrByStr(item[8]),
Cnf: &Config{
U: item[4],
P: item[5],
Crypt: common.GetBoolByStr(item[6]),
Compress: common.GetBoolByStr(item[7]),
},
MaxConn: common.GetIntNoErrByStr(item[10]),
}
if post.Id > int(s.ClientIncreaseId) {
s.ClientIncreaseId = int32(post.Id)
}
if post.RateLimit > 0 {
post.Rate = rate.NewRate(int64(post.RateLimit * 1024))
post.Rate.Start()
} else {
post.Rate = rate.NewRate(int64(2 << 23))
post.Rate.Start()
}
post.Flow = new(Flow)
post.Flow.FlowLimit = int64(common.GetIntNoErrByStr(item[9]))
if len(item) >= 12 {
post.ConfigConnAllow = common.GetBoolByStr(item[11])
} else {
post.ConfigConnAllow = true
}
if len(item) >= 13 {
post.WebUserName = item[12]
} else {
post.WebUserName = ""
}
if len(item) >= 14 {
post.WebPassword = item[13]
} else {
post.WebPassword = ""
}
s.Clients.Store(post.Id, post)
}
} }
func (s *Csv) LoadHostFromCsv() { func (s *Csv) StoreClientsToCsv() {
path := filepath.Join(s.RunPath, "conf", "hosts.csv") storeSyncMapToFile(s.Clients, s.ClientFilePath)
records, err := s.openFile(path)
if err != nil {
logs.Error("Profile Opening Error:", path)
os.Exit(0)
}
// 将每一行数据保存到内存slice中
for _, item := range records {
post := &Host{
Host: item[0],
HeaderChange: item[3],
HostChange: item[4],
Remark: item[5],
Location: item[6],
Id: common.GetIntNoErrByStr(item[7]),
}
if post.Client, err = s.GetClient(common.GetIntNoErrByStr(item[2])); err != nil {
continue
}
post.Target = new(Target)
post.Target.TargetStr = item[1]
post.Flow = new(Flow)
post.Flow.ExportFlow = int64(common.GetIntNoErrByStr(item[8]))
post.Flow.InletFlow = int64(common.GetIntNoErrByStr(item[9]))
if len(item) > 10 {
post.Scheme = item[10]
} else {
post.Scheme = "all"
}
s.Hosts.Store(post.Id, post)
if post.Id > int(s.HostIncreaseId) {
s.HostIncreaseId = int32(post.Id)
}
//store host to hostMap if the host url is none
}
} }
func (s *Csv) DelHost(id int) error { func (s *Csv) DelHost(id int) error {
@ -439,6 +286,7 @@ func (s *Csv) VerifyVkey(vkey string, id int) (res bool) {
}) })
return res return res
} }
func (s *Csv) VerifyUserName(username string, id int) (res bool) { func (s *Csv) VerifyUserName(username string, id int) (res bool) {
res = true res = true
s.Clients.Range(func(key, value interface{}) bool { s.Clients.Range(func(key, value interface{}) bool {
@ -452,18 +300,6 @@ func (s *Csv) VerifyUserName(username string, id int) (res bool) {
return res return res
} }
func (s *Csv) GetClientId() int32 {
return atomic.AddInt32(&s.ClientIncreaseId, 1)
}
func (s *Csv) GetTaskId() int32 {
return atomic.AddInt32(&s.TaskIncreaseId, 1)
}
func (s *Csv) GetHostId() int32 {
return atomic.AddInt32(&s.HostIncreaseId, 1)
}
func (s *Csv) UpdateClient(t *Client) error { func (s *Csv) UpdateClient(t *Client) error {
s.Clients.Store(t.Id, t) s.Clients.Store(t.Id, t)
if t.RateLimit == 0 { if t.RateLimit == 0 {
@ -516,6 +352,7 @@ func (s *Csv) GetClient(id int) (c *Client, err error) {
err = errors.New("未找到客户端") err = errors.New("未找到客户端")
return return
} }
func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) { func (s *Csv) GetClientIdByVkey(vkey string) (id int, err error) {
var exist bool var exist bool
s.Clients.Range(func(key, value interface{}) bool { s.Clients.Range(func(key, value interface{}) bool {
@ -585,40 +422,70 @@ func (s *Csv) GetInfoByHost(host string, r *http.Request) (h *Host, err error) {
return return
} }
func (s *Csv) StoreClientsToCsv() { func (s *Csv) GetClientId() int32 {
// 创建文件 return atomic.AddInt32(&s.ClientIncreaseId, 1)
csvFile, err := os.Create(filepath.Join(s.RunPath, "conf", "clients.csv")) }
func (s *Csv) GetTaskId() int32 {
return atomic.AddInt32(&s.TaskIncreaseId, 1)
}
func (s *Csv) GetHostId() int32 {
return atomic.AddInt32(&s.HostIncreaseId, 1)
}
func loadSyncMapFromFile(filePath string, f func(value string)) {
b, err := common.ReadAllFromFile(filePath)
if err != nil { if err != nil {
logs.Error(err.Error()) panic(err)
} }
defer csvFile.Close() for _, v := range strings.Split(string(b), "\n"+common.CONN_DATA_SEQ) {
writer := csv.NewWriter(csvFile) f(v)
s.Clients.Range(func(key, value interface{}) bool { }
client := value.(*Client) }
if client.NoStore {
func storeSyncMapToFile(m sync.Map, filePath string) {
file, err := os.Create(filePath)
if err != nil {
panic(err)
}
defer file.Close()
m.Range(func(key, value interface{}) bool {
var b []byte
var err error
switch value.(type) {
case *Tunnel:
obj := value.(*Tunnel)
if obj.NoStore {
return true return true
} }
record := []string{ b, err = json.Marshal(obj)
strconv.Itoa(client.Id), case *Host:
client.VerifyKey, obj := value.(*Host)
client.Remark, if obj.NoStore {
strconv.FormatBool(client.Status), return true
client.Cnf.U, }
client.Cnf.P, b, err = json.Marshal(obj)
common.GetStrByBool(client.Cnf.Crypt), case *Client:
strconv.FormatBool(client.Cnf.Compress), obj := value.(*Client)
strconv.Itoa(client.RateLimit), if obj.NoStore {
strconv.Itoa(int(client.Flow.FlowLimit)), return true
strconv.Itoa(int(client.MaxConn)), }
common.GetStrByBool(client.ConfigConnAllow), b, err = json.Marshal(obj)
client.WebUserName, default:
client.WebPassword, return true
} }
err := writer.Write(record)
if err != nil { if err != nil {
logs.Error(err.Error()) return true
}
_, err = file.Write(b)
if err != nil {
panic(err)
}
_, err = file.Write([]byte("\n" + common.CONN_DATA_SEQ))
if err != nil {
panic(err)
} }
return true return true
}) })
writer.Flush()
} }

View File

@ -183,6 +183,6 @@ type Host struct {
Flow *Flow Flow *Flow
Client *Client Client *Client
Target *Target //目标 Target *Target //目标
Health Health `json:"-"`
sync.RWMutex sync.RWMutex
} }

View File

@ -65,7 +65,7 @@ func (s *Mux) NewConn() (*conn, error) {
return nil, err return nil, err
} }
//set a timer timeout 30 second //set a timer timeout 30 second
timer := time.NewTimer(time.Second * 30) timer := time.NewTimer(time.Minute * 2)
defer timer.Stop() defer timer.Stop()
select { select {
case <-conn.connStatusOkCh: case <-conn.connStatusOkCh: