config.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. package config
  2. import (
  3. "errors"
  4. "fmt"
  5. "regexp"
  6. "strings"
  7. "github.com/cnlh/nps/lib/common"
  8. "github.com/cnlh/nps/lib/file"
  9. )
  10. type CommonConfig struct {
  11. Server string
  12. VKey string
  13. Tp string //bridgeType kcp or tcp
  14. AutoReconnection bool
  15. ProxyUrl string
  16. Client *file.Client
  17. }
  18. type LocalServer struct {
  19. Type string
  20. Port int
  21. Ip string
  22. Password string
  23. Target string
  24. }
  25. type Config struct {
  26. content string
  27. title []string
  28. CommonConfig *CommonConfig
  29. Hosts []*file.Host
  30. Tasks []*file.Tunnel
  31. Healths []*file.Health
  32. LocalServer []*LocalServer
  33. }
  34. func NewConfig(path string) (c *Config, err error) {
  35. c = new(Config)
  36. var b []byte
  37. if b, err = common.ReadAllFromFile(path); err != nil {
  38. return
  39. } else {
  40. if c.content, err = common.ParseStr(string(b)); err != nil {
  41. return nil, err
  42. }
  43. if c.title, err = getAllTitle(c.content); err != nil {
  44. return
  45. }
  46. var nowIndex int
  47. var nextIndex int
  48. var nowContent string
  49. for i := 0; i < len(c.title); i++ {
  50. nowIndex = strings.Index(c.content, c.title[i]) + len(c.title[i])
  51. if i < len(c.title)-1 {
  52. nextIndex = strings.Index(c.content, c.title[i+1])
  53. } else {
  54. nextIndex = len(c.content)
  55. }
  56. nowContent = c.content[nowIndex:nextIndex]
  57. if strings.Index(getTitleContent(c.title[i]), "secret") == 0 && !strings.Contains(nowContent, "mode") {
  58. local := delLocalService(nowContent)
  59. local.Type = "secret"
  60. c.LocalServer = append(c.LocalServer, local)
  61. continue
  62. }
  63. //except mode
  64. if strings.Index(getTitleContent(c.title[i]), "p2p") == 0 && !strings.Contains(nowContent, "mode") {
  65. local := delLocalService(nowContent)
  66. local.Type = "p2p"
  67. c.LocalServer = append(c.LocalServer, local)
  68. continue
  69. }
  70. //health set
  71. if strings.Index(getTitleContent(c.title[i]), "health") == 0 {
  72. c.Healths = append(c.Healths, dealHealth(nowContent))
  73. continue
  74. }
  75. switch c.title[i] {
  76. case "[common]":
  77. c.CommonConfig = dealCommon(nowContent)
  78. default:
  79. if strings.Index(nowContent, "host") > -1 {
  80. h := dealHost(nowContent)
  81. h.Remark = getTitleContent(c.title[i])
  82. c.Hosts = append(c.Hosts, h)
  83. } else {
  84. t := dealTunnel(nowContent)
  85. t.Remark = getTitleContent(c.title[i])
  86. c.Tasks = append(c.Tasks, t)
  87. }
  88. }
  89. }
  90. }
  91. return
  92. }
  93. func getTitleContent(s string) string {
  94. re, _ := regexp.Compile(`[\[\]]`)
  95. return re.ReplaceAllString(s, "")
  96. }
  97. func dealCommon(s string) *CommonConfig {
  98. c := &CommonConfig{}
  99. c.Client = file.NewClient("", true, true)
  100. c.Client.Cnf = new(file.Config)
  101. for _, v := range splitStr(s) {
  102. item := strings.Split(v, "=")
  103. if len(item) == 0 {
  104. continue
  105. } else if len(item) == 1 {
  106. item = append(item, "")
  107. }
  108. switch item[0] {
  109. case "server_addr":
  110. c.Server = item[1]
  111. case "vkey":
  112. c.VKey = item[1]
  113. case "conn_type":
  114. c.Tp = item[1]
  115. case "auto_reconnection":
  116. c.AutoReconnection = common.GetBoolByStr(item[1])
  117. case "basic_username":
  118. c.Client.Cnf.U = item[1]
  119. case "basic_password":
  120. c.Client.Cnf.P = item[1]
  121. case "web_password":
  122. c.Client.WebPassword = item[1]
  123. case "web_username":
  124. c.Client.WebUserName = item[1]
  125. case "compress":
  126. c.Client.Cnf.Compress = common.GetBoolByStr(item[1])
  127. case "crypt":
  128. c.Client.Cnf.Crypt = common.GetBoolByStr(item[1])
  129. case "proxy_url":
  130. c.ProxyUrl = item[1]
  131. case "rate_limit":
  132. c.Client.RateLimit = common.GetIntNoErrByStr(item[1])
  133. case "flow_limit":
  134. c.Client.Flow.FlowLimit = int64(common.GetIntNoErrByStr(item[1]))
  135. case "max_conn":
  136. c.Client.MaxConn = common.GetIntNoErrByStr(item[1])
  137. case "remark":
  138. c.Client.Remark = item[1]
  139. }
  140. }
  141. return c
  142. }
  143. func dealHost(s string) *file.Host {
  144. h := &file.Host{}
  145. h.Target = new(file.Target)
  146. h.Scheme = "all"
  147. var headerChange string
  148. for _, v := range splitStr(s) {
  149. item := strings.Split(v, "=")
  150. if len(item) == 0 {
  151. continue
  152. } else if len(item) == 1 {
  153. item = append(item, "")
  154. }
  155. switch strings.TrimSpace(item[0]) {
  156. case "host":
  157. h.Host = item[1]
  158. case "target_addr":
  159. h.Target.TargetStr = strings.Replace(item[1], ",", "\n", -1)
  160. case "host_change":
  161. h.HostChange = item[1]
  162. case "scheme":
  163. h.Scheme = item[1]
  164. case "location":
  165. h.Location = item[1]
  166. default:
  167. if strings.Contains(item[0], "header") {
  168. headerChange += strings.Replace(item[0], "header_", "", -1) + ":" + item[1] + "\n"
  169. }
  170. h.HeaderChange = headerChange
  171. }
  172. }
  173. return h
  174. }
  175. func dealHealth(s string) *file.Health {
  176. h := &file.Health{}
  177. for _, v := range splitStr(s) {
  178. item := strings.Split(v, "=")
  179. if len(item) == 0 {
  180. continue
  181. } else if len(item) == 1 {
  182. item = append(item, "")
  183. }
  184. switch strings.TrimSpace(item[0]) {
  185. case "health_check_timeout":
  186. h.HealthCheckTimeout = common.GetIntNoErrByStr(item[1])
  187. case "health_check_max_failed":
  188. h.HealthMaxFail = common.GetIntNoErrByStr(item[1])
  189. case "health_check_interval":
  190. h.HealthCheckInterval = common.GetIntNoErrByStr(item[1])
  191. case "health_http_url":
  192. h.HttpHealthUrl = item[1]
  193. case "health_check_type":
  194. h.HealthCheckType = item[1]
  195. case "health_check_target":
  196. h.HealthCheckTarget = item[1]
  197. }
  198. }
  199. return h
  200. }
  201. func dealTunnel(s string) *file.Tunnel {
  202. t := &file.Tunnel{}
  203. t.Target = new(file.Target)
  204. for _, v := range splitStr(s) {
  205. item := strings.Split(v, "=")
  206. if len(item) == 0 {
  207. continue
  208. } else if len(item) == 1 {
  209. item = append(item, "")
  210. }
  211. switch strings.TrimSpace(item[0]) {
  212. case "server_port":
  213. t.Ports = item[1]
  214. case "server_ip":
  215. t.ServerIp = item[1]
  216. case "mode":
  217. t.Mode = item[1]
  218. case "target_addr":
  219. t.Target.TargetStr = strings.Replace(item[1], ",", "\n", -1)
  220. case "target_port":
  221. t.Target.TargetStr = item[1]
  222. case "target_ip":
  223. t.TargetAddr = item[1]
  224. case "password":
  225. t.Password = item[1]
  226. case "local_path":
  227. t.LocalPath = item[1]
  228. case "strip_pre":
  229. t.StripPre = item[1]
  230. case "multi_account":
  231. t.MultiAccount = &file.MultiAccount{}
  232. if common.FileExists(item[1]){
  233. if b, err := common.ReadAllFromFile(item[1]); err != nil {
  234. panic(err)
  235. } else {
  236. if content, err := common.ParseStr(string(b)); err != nil {
  237. panic(err)
  238. } else {
  239. t.MultiAccount.AccountMap = dealMultiUser(content)
  240. }
  241. }
  242. }
  243. }
  244. }
  245. return t
  246. }
  247. func dealMultiUser(s string) map[string]string {
  248. multiUserMap := make(map[string]string)
  249. for _, v := range splitStr(s) {
  250. item := strings.Split(v, "=")
  251. if len(item) == 0 {
  252. continue
  253. } else if len(item) == 1 {
  254. item = append(item, "")
  255. }
  256. multiUserMap[strings.TrimSpace(item[0])] = item[1]
  257. }
  258. return multiUserMap
  259. }
  260. func delLocalService(s string) *LocalServer {
  261. l := new(LocalServer)
  262. for _, v := range splitStr(s) {
  263. item := strings.Split(v, "=")
  264. if len(item) == 0 {
  265. continue
  266. } else if len(item) == 1 {
  267. item = append(item, "")
  268. }
  269. switch item[0] {
  270. case "local_port":
  271. l.Port = common.GetIntNoErrByStr(item[1])
  272. case "local_ip":
  273. l.Ip = item[1]
  274. case "password":
  275. l.Password = item[1]
  276. case "target_addr":
  277. l.Target = item[1]
  278. }
  279. }
  280. return l
  281. }
  282. func getAllTitle(content string) (arr []string, err error) {
  283. var re *regexp.Regexp
  284. re, err = regexp.Compile(`\[.+?\]`)
  285. if err != nil {
  286. return
  287. }
  288. arr = re.FindAllString(content, -1)
  289. m := make(map[string]bool)
  290. for _, v := range arr {
  291. if _, ok := m[v]; ok {
  292. err = errors.New(fmt.Sprintf("Item names %s are not allowed to be duplicated", v))
  293. return
  294. }
  295. m[v] = true
  296. }
  297. return
  298. }
  299. func splitStr(s string) (configDataArr []string) {
  300. if common.IsWindows() {
  301. configDataArr = strings.Split(s, "\r\n")
  302. }
  303. if len(configDataArr) < 3 {
  304. configDataArr = strings.Split(s, "\n")
  305. }
  306. return
  307. }