123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- package config
- import (
- "errors"
- "fmt"
- "regexp"
- "strings"
- "ehang.io/nps/lib/common"
- "ehang.io/nps/lib/file"
- )
- type CommonConfig struct {
- Server string
- VKey string
- Tp string //bridgeType kcp or tcp
- AutoReconnection bool
- ProxyUrl string
- Client *file.Client
- DisconnectTime int
- }
- type LocalServer struct {
- Type string
- Port int
- Ip string
- Password string
- Target string
- }
- type Config struct {
- content string
- title []string
- CommonConfig *CommonConfig
- Hosts []*file.Host
- Tasks []*file.Tunnel
- Healths []*file.Health
- LocalServer []*LocalServer
- }
- func NewConfig(path string) (c *Config, err error) {
- c = new(Config)
- var b []byte
- if b, err = common.ReadAllFromFile(path); err != nil {
- return
- } else {
- if c.content, err = common.ParseStr(string(b)); err != nil {
- return nil, err
- }
- if c.title, err = getAllTitle(c.content); err != nil {
- return
- }
- var nowIndex int
- var nextIndex int
- var nowContent string
- for i := 0; i < len(c.title); i++ {
- nowIndex = strings.Index(c.content, c.title[i]) + len(c.title[i])
- if i < len(c.title)-1 {
- nextIndex = strings.Index(c.content, c.title[i+1])
- } else {
- nextIndex = len(c.content)
- }
- nowContent = c.content[nowIndex:nextIndex]
- if strings.Index(getTitleContent(c.title[i]), "secret") == 0 && !strings.Contains(nowContent, "mode") {
- local := delLocalService(nowContent)
- local.Type = "secret"
- c.LocalServer = append(c.LocalServer, local)
- continue
- }
- //except mode
- if strings.Index(getTitleContent(c.title[i]), "p2p") == 0 && !strings.Contains(nowContent, "mode") {
- local := delLocalService(nowContent)
- local.Type = "p2p"
- c.LocalServer = append(c.LocalServer, local)
- continue
- }
- //health set
- if strings.Index(getTitleContent(c.title[i]), "health") == 0 {
- c.Healths = append(c.Healths, dealHealth(nowContent))
- continue
- }
- switch c.title[i] {
- case "[common]":
- c.CommonConfig = dealCommon(nowContent)
- default:
- if strings.Index(nowContent, "host") > -1 {
- h := dealHost(nowContent)
- h.Remark = getTitleContent(c.title[i])
- c.Hosts = append(c.Hosts, h)
- } else {
- t := dealTunnel(nowContent)
- t.Remark = getTitleContent(c.title[i])
- c.Tasks = append(c.Tasks, t)
- }
- }
- }
- }
- return
- }
- func getTitleContent(s string) string {
- re, _ := regexp.Compile(`[\[\]]`)
- return re.ReplaceAllString(s, "")
- }
- func dealCommon(s string) *CommonConfig {
- c := &CommonConfig{}
- c.Client = file.NewClient("", true, true)
- c.Client.Cnf = new(file.Config)
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- switch item[0] {
- case "server_addr":
- c.Server = item[1]
- case "vkey":
- c.VKey = item[1]
- case "conn_type":
- c.Tp = item[1]
- case "auto_reconnection":
- c.AutoReconnection = common.GetBoolByStr(item[1])
- case "basic_username":
- c.Client.Cnf.U = item[1]
- case "basic_password":
- c.Client.Cnf.P = item[1]
- case "web_password":
- c.Client.WebPassword = item[1]
- case "web_username":
- c.Client.WebUserName = item[1]
- case "compress":
- c.Client.Cnf.Compress = common.GetBoolByStr(item[1])
- case "crypt":
- c.Client.Cnf.Crypt = common.GetBoolByStr(item[1])
- case "proxy_url":
- c.ProxyUrl = item[1]
- case "rate_limit":
- c.Client.RateLimit = common.GetIntNoErrByStr(item[1])
- case "flow_limit":
- c.Client.Flow.FlowLimit = int64(common.GetIntNoErrByStr(item[1]))
- case "max_conn":
- c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
- case "remark":
- c.Client.Remark = item[1]
- case "pprof_addr":
- common.InitPProfFromArg(item[1])
- case "disconnect_timeout":
- c.DisconnectTime = common.GetIntNoErrByStr(item[1])
- }
- }
- return c
- }
- func dealHost(s string) *file.Host {
- h := &file.Host{}
- h.Target = new(file.Target)
- h.Scheme = "all"
- var headerChange string
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- switch strings.TrimSpace(item[0]) {
- case "host":
- h.Host = item[1]
- case "target_addr":
- h.Target.TargetStr = strings.Replace(item[1], ",", "\n", -1)
- case "host_change":
- h.HostChange = item[1]
- case "scheme":
- h.Scheme = item[1]
- case "location":
- h.Location = item[1]
- default:
- if strings.Contains(item[0], "header") {
- headerChange += strings.Replace(item[0], "header_", "", -1) + ":" + item[1] + "\n"
- }
- h.HeaderChange = headerChange
- }
- }
- return h
- }
- func dealHealth(s string) *file.Health {
- h := &file.Health{}
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- switch strings.TrimSpace(item[0]) {
- case "health_check_timeout":
- h.HealthCheckTimeout = common.GetIntNoErrByStr(item[1])
- case "health_check_max_failed":
- h.HealthMaxFail = common.GetIntNoErrByStr(item[1])
- case "health_check_interval":
- h.HealthCheckInterval = common.GetIntNoErrByStr(item[1])
- case "health_http_url":
- h.HttpHealthUrl = item[1]
- case "health_check_type":
- h.HealthCheckType = item[1]
- case "health_check_target":
- h.HealthCheckTarget = item[1]
- }
- }
- return h
- }
- func dealTunnel(s string) *file.Tunnel {
- t := &file.Tunnel{}
- t.Target = new(file.Target)
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- switch strings.TrimSpace(item[0]) {
- case "server_port":
- t.Ports = item[1]
- case "server_ip":
- t.ServerIp = item[1]
- case "mode":
- t.Mode = item[1]
- case "target_addr":
- t.Target.TargetStr = strings.Replace(item[1], ",", "\n", -1)
- case "target_port":
- t.Target.TargetStr = item[1]
- case "target_ip":
- t.TargetAddr = item[1]
- case "password":
- t.Password = item[1]
- case "local_path":
- t.LocalPath = item[1]
- case "strip_pre":
- t.StripPre = item[1]
- case "multi_account":
- t.MultiAccount = &file.MultiAccount{}
- if common.FileExists(item[1]) {
- if b, err := common.ReadAllFromFile(item[1]); err != nil {
- panic(err)
- } else {
- if content, err := common.ParseStr(string(b)); err != nil {
- panic(err)
- } else {
- t.MultiAccount.AccountMap = dealMultiUser(content)
- }
- }
- }
- }
- }
- return t
- }
- func dealMultiUser(s string) map[string]string {
- multiUserMap := make(map[string]string)
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- multiUserMap[strings.TrimSpace(item[0])] = item[1]
- }
- return multiUserMap
- }
- func delLocalService(s string) *LocalServer {
- l := new(LocalServer)
- for _, v := range splitStr(s) {
- item := strings.Split(v, "=")
- if len(item) == 0 {
- continue
- } else if len(item) == 1 {
- item = append(item, "")
- }
- switch item[0] {
- case "local_port":
- l.Port = common.GetIntNoErrByStr(item[1])
- case "local_ip":
- l.Ip = item[1]
- case "password":
- l.Password = item[1]
- case "target_addr":
- l.Target = item[1]
- }
- }
- return l
- }
- func getAllTitle(content string) (arr []string, err error) {
- var re *regexp.Regexp
- re, err = regexp.Compile(`(?m)^\[[^\[\]\r\n]+\]`)
- if err != nil {
- return
- }
- arr = re.FindAllString(content, -1)
- m := make(map[string]bool)
- for _, v := range arr {
- if _, ok := m[v]; ok {
- err = errors.New(fmt.Sprintf("Item names %s are not allowed to be duplicated", v))
- return
- }
- m[v] = true
- }
- return
- }
- func splitStr(s string) (configDataArr []string) {
- if common.IsWindows() {
- configDataArr = strings.Split(s, "\r\n")
- }
- if len(configDataArr) < 3 {
- configDataArr = strings.Split(s, "\n")
- }
- return
- }
|