host.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package tinymq
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "regexp"
  7. "strconv"
  8. "strings"
  9. "time"
  10. )
  11. // 连接服务结构
  12. type HostInfo struct {
  13. Proto string `json:"proto" yaml:"proto"` // 协议
  14. Version uint8 `json:"version" yaml:"version"` // 版本
  15. Host string `json:"host" yaml:"host"` // 连接的IP地址或者域名
  16. Bind string `json:"bind,omitempty" yaml:"bind"` // 绑定的地址
  17. Port uint16 `json:"port,omitempty" yaml:"port"` // 连接的端口
  18. Path string `json:"path,omitempty" yaml:"path"` // 连接的路径
  19. Hash string `json:"hash,omitempty" yaml:"hash"` // 连接验证使用,格式 method:key
  20. Proxy bool `json:"proxy,omitempty" yaml:"proxy"` // 是否代理
  21. Nat bool `json:"nat,omitempty" yaml:"nat"` // 是否是前端nat的方式处理
  22. Priority int16 `json:"priority,omitempty" yaml:"priority"` // 优先级,-1 表示不可用,0 表示最高优先级(为了兼容没有优先级的节点),1-100 表示优先级别,数值越高优先级越高,不过这是由应用端决定的规则
  23. Errors uint16 `json:"errors,omitempty" yaml:"errors"` // 连接失败计数,如果成功了则重置为0
  24. Updated time.Time `json:"updated" yaml:"updated"` // 节点信息刷新时间
  25. }
  26. // 从 url 中解析信息
  27. // url 格式:ws2://xor:s^7mv7L!Mrn8Y!vn@127.0.0.1:14541/wsv2?proxy=1
  28. // 仅支持客户端连接使用
  29. func ParseUrl(url string) (hostInfo *HostInfo, err error) {
  30. mx := regexp.MustCompile(`^([a-z]+)([0-9]*)://([^#/\?]+)(/[\w\-/]+)?`).FindStringSubmatch(url)
  31. if mx == nil {
  32. return nil, errors.New("invalid url")
  33. }
  34. protocol := mx[1]
  35. version, _ := strconv.Atoi(mx[2])
  36. host := mx[3]
  37. index := strings.LastIndex(host, "@")
  38. hash := ""
  39. if index >= 0 {
  40. hash = host[0:index]
  41. host = host[index+1:]
  42. }
  43. // 检查是否ipv6,解析出ip和端口
  44. index = strings.Index(host, "]:")
  45. port := 0
  46. if index > 0 {
  47. // ipv6 地址和端口
  48. port, err = strconv.Atoi(host[index+2:])
  49. if err != nil {
  50. return nil, err
  51. }
  52. host = host[1:index]
  53. } else {
  54. hs := strings.Split(host, ":")
  55. if len(hs) == 2 {
  56. host = hs[0]
  57. port, err = strconv.Atoi(hs[1])
  58. if err != nil {
  59. return nil, err
  60. }
  61. }
  62. }
  63. path := ""
  64. if len(mx) > 4 {
  65. path = mx[4]
  66. }
  67. hostInfo = &HostInfo{
  68. Proto: protocol,
  69. Version: uint8(version),
  70. Host: host,
  71. Port: uint16(port),
  72. Hash: hash,
  73. Path: path,
  74. }
  75. // 查找是否代理
  76. url = url[len(mx[0]):]
  77. if regexp.MustCompile(`[\?&]proxy=1`).MatchString(url) {
  78. hostInfo.Proxy = true
  79. }
  80. if regexp.MustCompile(`[\?&]nat=1`).MatchString(url) {
  81. hostInfo.Nat = true
  82. }
  83. priorityM := regexp.MustCompile(`[\?&]priority=(-?\d+)`).FindStringSubmatch(url)
  84. if priorityM != nil {
  85. priority, err := strconv.Atoi(priorityM[1])
  86. if err != nil {
  87. return nil, err
  88. }
  89. hostInfo.Priority = int16(priority)
  90. }
  91. return hostInfo, nil
  92. }
  93. // 只输出客户端要连接的信息
  94. func (h *HostInfo) Url() string {
  95. if h == nil {
  96. // 避免空出错
  97. return ""
  98. }
  99. var b bytes.Buffer
  100. fmt.Fprintf(&b, "%s%d://", h.Proto, h.Version)
  101. if h.Hash != "" {
  102. b.WriteString(h.Hash)
  103. b.WriteString("@")
  104. }
  105. if strings.Contains(h.Host, ":") {
  106. // ipv6
  107. b.WriteString("[")
  108. b.WriteString(h.Host)
  109. b.WriteString("]")
  110. } else {
  111. b.WriteString(h.Host)
  112. }
  113. if h.Port > 0 {
  114. fmt.Fprintf(&b, ":%d", h.Port)
  115. }
  116. if h.Path != "" {
  117. b.WriteString(h.Path)
  118. }
  119. param := make([]string, 0)
  120. if h.Proxy {
  121. param = append(param, "proxy=1")
  122. }
  123. if h.Nat {
  124. param = append(param, "nat=1")
  125. }
  126. if h.Priority != 0 {
  127. param = append(param, fmt.Sprintf("priority=%d", h.Priority))
  128. }
  129. if len(param) > 0 {
  130. b.WriteString("?")
  131. b.WriteString(strings.Join(param, "&"))
  132. }
  133. return b.String()
  134. }
  135. // 输出代表一个节点的关键信息
  136. func (h *HostInfo) Key() string {
  137. if h == nil {
  138. // 避免空出错
  139. return ""
  140. }
  141. return fmt.Sprintf("%s%d://%s:%d%s", h.Proto, h.Version, h.Host, h.Port, h.Path)
  142. }