1
0

config.go 7.7 KB

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