|
|
@@ -1,14 +1,7 @@
|
|
|
package tinymq
|
|
|
|
|
|
import (
|
|
|
- "bytes"
|
|
|
- "errors"
|
|
|
"fmt"
|
|
|
- "regexp"
|
|
|
- "strconv"
|
|
|
-
|
|
|
- // "regexp"
|
|
|
- "strings"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
@@ -129,138 +122,6 @@ type GetMsg struct {
|
|
|
timer *time.Timer
|
|
|
}
|
|
|
|
|
|
-// 连接服务结构
|
|
|
-type HostInfo struct {
|
|
|
- Proto string `json:"proto" yaml:"proto"` // 协议
|
|
|
- Version uint8 `json:"version" yaml:"version"` // 版本
|
|
|
- Host string `json:"host" yaml:"host"` // 连接的IP地址或者域名
|
|
|
- Bind string `json:"bind,omitempty" yaml:"bind"` // 绑定的地址
|
|
|
- Port uint16 `json:"port,omitempty" yaml:"port"` // 连接的端口
|
|
|
- Path string `json:"path,omitempty" yaml:"path"` // 连接的路径
|
|
|
- Hash string `json:"hash,omitempty" yaml:"hash"` // 连接验证使用,格式 method:key
|
|
|
- Proxy bool `json:"proxy,omitempty" yaml:"proxy"` // 是否代理
|
|
|
- Nat bool `json:"nat,omitempty" yaml:"nat"` // 是否是前端nat的方式处理
|
|
|
- Priority int16 `json:"priority,omitempty" yaml:"priority"` // 优先级,-1 表示不可用,0 表示最高优先级(为了兼容没有优先级的节点),1-100 表示优先级别,数值越高优先级越高
|
|
|
- Errors uint16 `json:"errors,omitempty" yaml:"errors"` // 连接失败计数,如果成功了则重置为0
|
|
|
- Updated time.Time `json:"updated,omitempty" yaml:"updated"` // 节点信息刷新时间
|
|
|
-}
|
|
|
-
|
|
|
-// 从 url 中解析信息
|
|
|
-// url 格式:ws2://xor:s^7mv7L!Mrn8Y!vn@127.0.0.1:14541/wsv2?proxy=1
|
|
|
-// 仅支持客户端连接使用
|
|
|
-func ParseUrl(url string) (hostInfo *HostInfo, err error) {
|
|
|
- mx := regexp.MustCompile(`^([a-z]+)([0-9]*)://([^#/\?]+)(/[\w\-/]+)?`).FindStringSubmatch(url)
|
|
|
- if mx == nil {
|
|
|
- return nil, errors.New("invalid url")
|
|
|
- }
|
|
|
- protocol := mx[1]
|
|
|
- version, _ := strconv.Atoi(mx[2])
|
|
|
- host := mx[3]
|
|
|
- index := strings.LastIndex(host, "@")
|
|
|
- hash := ""
|
|
|
- if index >= 0 {
|
|
|
- hash = host[0:index]
|
|
|
- host = host[index+1:]
|
|
|
- }
|
|
|
- // 检查是否ipv6,解析出ip和端口
|
|
|
- index = strings.Index(host, "]:")
|
|
|
- port := 0
|
|
|
- if index > 0 {
|
|
|
- // ipv6 地址和端口
|
|
|
- port, err = strconv.Atoi(host[index+2:])
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- host = host[1:index]
|
|
|
- } else {
|
|
|
- hs := strings.Split(host, ":")
|
|
|
- if len(hs) == 2 {
|
|
|
- host = hs[0]
|
|
|
- port, err = strconv.Atoi(hs[1])
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- path := ""
|
|
|
- if len(mx) > 4 {
|
|
|
- path = mx[4]
|
|
|
- }
|
|
|
- hostInfo = &HostInfo{
|
|
|
- Proto: protocol,
|
|
|
- Version: uint8(version),
|
|
|
- Host: host,
|
|
|
- Port: uint16(port),
|
|
|
- Hash: hash,
|
|
|
- Path: path,
|
|
|
- }
|
|
|
- // 查找是否代理
|
|
|
- url = url[len(mx[0]):]
|
|
|
- if regexp.MustCompile(`[\?&]proxy=1`).MatchString(url) {
|
|
|
- hostInfo.Proxy = true
|
|
|
- }
|
|
|
- if regexp.MustCompile(`[\?&]nat=1`).MatchString(url) {
|
|
|
- hostInfo.Nat = true
|
|
|
- }
|
|
|
- priorityM := regexp.MustCompile(`[\?&]priority=(-?\d+)`).FindStringSubmatch(url)
|
|
|
- if priorityM != nil {
|
|
|
- priority, err := strconv.Atoi(priorityM[1])
|
|
|
- if err != nil {
|
|
|
- return nil, err
|
|
|
- }
|
|
|
- hostInfo.Priority = int16(priority)
|
|
|
- }
|
|
|
- return hostInfo, nil
|
|
|
-}
|
|
|
-
|
|
|
-// 只输出客户端要连接的信息
|
|
|
-func (h *HostInfo) Url() string {
|
|
|
- if h == nil {
|
|
|
- // 避免空出错
|
|
|
- return ""
|
|
|
- }
|
|
|
- var b bytes.Buffer
|
|
|
- fmt.Fprintf(&b, "%s%d://", h.Proto, h.Version)
|
|
|
- if h.Hash != "" {
|
|
|
- b.WriteString(h.Hash + "@")
|
|
|
- }
|
|
|
- if strings.Contains(h.Host, ":") {
|
|
|
- // ipv6
|
|
|
- b.WriteString("[" + h.Host + "]")
|
|
|
- } else {
|
|
|
- b.WriteString(h.Host)
|
|
|
- }
|
|
|
- if h.Port > 0 {
|
|
|
- fmt.Fprintf(&b, ":%d", h.Port)
|
|
|
- }
|
|
|
- if h.Path != "" {
|
|
|
- b.WriteString(h.Path)
|
|
|
- }
|
|
|
- param := make([]string, 0)
|
|
|
- if h.Proxy {
|
|
|
- param = append(param, "proxy=1")
|
|
|
- }
|
|
|
- if h.Nat {
|
|
|
- param = append(param, "nat=1")
|
|
|
- }
|
|
|
- if h.Priority != 0 {
|
|
|
- param = append(param, fmt.Sprintf("priority=%d", h.Priority))
|
|
|
- }
|
|
|
- if len(param) > 0 {
|
|
|
- b.WriteString("?" + strings.Join(param, "&"))
|
|
|
- }
|
|
|
- return b.String()
|
|
|
-}
|
|
|
-
|
|
|
-// 输出代表一个节点的关键信息
|
|
|
-func (h *HostInfo) Key() string {
|
|
|
- if h == nil {
|
|
|
- // 避免空出错
|
|
|
- return ""
|
|
|
- }
|
|
|
- return fmt.Sprintf("%s%d://%s:%d%s", h.Proto, h.Version, h.Host, h.Port, h.Path)
|
|
|
-}
|
|
|
-
|
|
|
// 获取对应频道的一个连接地址
|
|
|
type ConnectHostFunc func(channel string, hostType HostType) (hostInfo *HostInfo, err error)
|
|
|
|