type.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. package tinymq
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "regexp"
  7. "strconv"
  8. // "regexp"
  9. "strings"
  10. "time"
  11. )
  12. // 中间件函数
  13. // 如果返回为空,表示处理完成,通过
  14. // 如果返回 NEXT_MIDDLE,表示需要下一个中间件函数处理;如果没有下一函数则默认通过
  15. type MiddleFunc func(request *RequestData) (response *ResponseData)
  16. // 订阅频道响应函数
  17. type SubscribeBackFunc func(request *RequestData) (state uint8, result any)
  18. // GET 获取数据的回调函数,如果返回 false 则提前结束
  19. type GetBackFunc func(response *ResponseData) (ok bool)
  20. // 线路状态改变时调用
  21. type ConnectStatusFunc func(conn *Line)
  22. // 频道过滤器函数,如果返回true表示成功匹配
  23. type FilterFunc func(conn *Line) (ok bool)
  24. // 通过过滤函数获取一个频道信息
  25. type FilterToChannelFunc func(filter FilterFunc) (channel string)
  26. // 订阅频道数据结构
  27. type SubscribeData struct {
  28. Filter FilterFunc // 频道匹配过滤
  29. Cmd string // 请求的命令
  30. BackFunc SubscribeBackFunc //回调函数,如果状态为 NEXT_SUBSCRIBE 将继续下一个频道调用
  31. }
  32. // 获取数据使用的数据结构
  33. type GetData struct {
  34. Filter FilterFunc // 命令匹配过滤
  35. Cmd string
  36. Data any
  37. Max int // 获取数据的频道最多有几个,如果为0表示没有限制
  38. Timeout int // 超时时间(毫秒)
  39. Rand bool // 是否使用随机的数列
  40. backchan chan *ResponseData // 获取响应返回的数据
  41. }
  42. // 连接状态
  43. type ConnectState byte
  44. const (
  45. Disconnected ConnectState = iota
  46. Connected
  47. Closed
  48. )
  49. func (t ConnectState) String() string {
  50. switch t {
  51. case Disconnected:
  52. return "Disconnected"
  53. case Connected:
  54. return "Connected"
  55. case Closed:
  56. return "Closed"
  57. default:
  58. return fmt.Sprintf("Unknown ConnectState (%d)", t)
  59. }
  60. }
  61. // 主机类型
  62. type HostType byte
  63. const (
  64. Direct HostType = iota
  65. Proxy
  66. Both
  67. )
  68. // 请求数据包
  69. type RequestData struct {
  70. Id uint16
  71. Cmd string
  72. Data []byte
  73. timeout int // 超时时间,单位为毫秒
  74. backchan chan *ResponseData // 返回数据的管道
  75. conn *Line // 将连接传递出去是为了能够让上层找回来
  76. }
  77. func (r *RequestData) Conn() *Line {
  78. return r.conn
  79. }
  80. type ResponseData struct {
  81. Id uint16
  82. State uint8
  83. Data []byte
  84. conn *Line
  85. }
  86. // 获取当前的连接
  87. func (r *ResponseData) Conn() *Line {
  88. return r.conn
  89. }
  90. // 输出状态和数据,方便直接返回
  91. func (r *ResponseData) Out() (state uint8, data []byte) {
  92. return r.State, r.Data
  93. }
  94. // 输出可视化
  95. func (r *ResponseData) String() string {
  96. return fmt.Sprintf("id: %d, state: [%d]%s, data: %s", r.Id, r.State, IdMsg(r.State), string(r.Data))
  97. }
  98. type PingData struct {
  99. Id uint16
  100. }
  101. // 请求信息,得到回应通过管道传递信息
  102. type GetMsg struct {
  103. out chan *ResponseData
  104. timer *time.Timer
  105. }
  106. // 连接服务结构
  107. type HostInfo struct {
  108. Proto string `json:"proto" yaml:"proto"` // 协议
  109. Version uint8 `json:"version" yaml:"version"` // 版本
  110. Host string `json:"host" yaml:"host"` // 连接的IP地址或者域名
  111. Bind string `json:"bind,omitempty" yaml:"bind"` // 绑定的地址
  112. Port uint16 `json:"port,omitempty" yaml:"port"` // 连接的端口
  113. Path string `json:"path,omitempty" yaml:"path"` // 连接的路径
  114. Hash string `json:"hash,omitempty" yaml:"hash"` // 连接验证使用,格式 method:key
  115. Proxy bool `json:"proxy,omitempty" yaml:"proxy"` // 是否代理
  116. Nat bool `json:"nat,omitempty" yaml:"nat"` // 是否是前端nat的方式处理
  117. Priority int16 `json:"priority,omitempty" yaml:"priority"` // 优先级,-1 表示不可用,0 表示最高优先级(为了兼容没有优先级的节点),1-100 表示优先级别,数值越高优先级越高
  118. Errors uint16 `json:"errors,omitempty" yaml:"errors"` // 连接失败计数,如果成功了则重置为0
  119. Updated time.Time `json:"updated,omitempty" yaml:"updated"` // 节点信息刷新时间
  120. }
  121. // 从 url 中解析信息
  122. // url 格式:ws2://xor:s^7mv7L!Mrn8Y!vn@127.0.0.1:14541/wsv2?proxy=1
  123. // 仅支持客户端连接使用
  124. func ParseUrl(url string) (hostInfo *HostInfo, err error) {
  125. mx := regexp.MustCompile(`^([a-z]+)([0-9]*)://([^#/\?]+)(/[\w\-/]+)?`).FindStringSubmatch(url)
  126. if mx == nil {
  127. return nil, errors.New("invalid url")
  128. }
  129. protocol := mx[1]
  130. version, _ := strconv.Atoi(mx[2])
  131. host := mx[3]
  132. index := strings.LastIndex(host, "@")
  133. hash := ""
  134. if index >= 0 {
  135. hash = host[0:index]
  136. host = host[index+1:]
  137. }
  138. // 检查是否ipv6,解析出ip和端口
  139. index = strings.Index(host, "]:")
  140. port := 0
  141. if index > 0 {
  142. // ipv6 地址和端口
  143. port, err = strconv.Atoi(host[index+2:])
  144. if err != nil {
  145. return nil, err
  146. }
  147. host = host[1:index]
  148. } else {
  149. hs := strings.Split(host, ":")
  150. if len(hs) == 2 {
  151. host = hs[0]
  152. port, err = strconv.Atoi(hs[1])
  153. if err != nil {
  154. return nil, err
  155. }
  156. }
  157. }
  158. path := ""
  159. if len(mx) > 4 {
  160. path = mx[4]
  161. }
  162. hostInfo = &HostInfo{
  163. Proto: protocol,
  164. Version: uint8(version),
  165. Host: host,
  166. Port: uint16(port),
  167. Hash: hash,
  168. Path: path,
  169. }
  170. // 查找是否代理
  171. url = url[len(mx[0]):]
  172. if regexp.MustCompile(`[\?&]proxy=1`).MatchString(url) {
  173. hostInfo.Proxy = true
  174. }
  175. if regexp.MustCompile(`[\?&]nat=1`).MatchString(url) {
  176. hostInfo.Nat = true
  177. }
  178. priorityM := regexp.MustCompile(`[\?&]priority=(-?\d+)`).FindStringSubmatch(url)
  179. if priorityM != nil {
  180. priority, err := strconv.Atoi(priorityM[1])
  181. if err != nil {
  182. return nil, err
  183. }
  184. hostInfo.Priority = int16(priority)
  185. }
  186. return hostInfo, nil
  187. }
  188. // 只输出客户端要连接的信息
  189. func (h *HostInfo) Url() string {
  190. if h == nil {
  191. // 避免空出错
  192. return ""
  193. }
  194. var b bytes.Buffer
  195. fmt.Fprintf(&b, "%s%d://", h.Proto, h.Version)
  196. if h.Hash != "" {
  197. b.WriteString(h.Hash + "@")
  198. }
  199. if strings.Contains(h.Host, ":") {
  200. // ipv6
  201. b.WriteString("[" + h.Host + "]")
  202. } else {
  203. b.WriteString(h.Host)
  204. }
  205. if h.Port > 0 {
  206. fmt.Fprintf(&b, ":%d", h.Port)
  207. }
  208. if h.Path != "" {
  209. b.WriteString(h.Path)
  210. }
  211. param := make([]string, 0)
  212. if h.Proxy {
  213. param = append(param, "proxy=1")
  214. }
  215. if h.Nat {
  216. param = append(param, "nat=1")
  217. }
  218. if h.Priority != 0 {
  219. param = append(param, fmt.Sprintf("priority=%d", h.Priority))
  220. }
  221. if len(param) > 0 {
  222. b.WriteString("?" + strings.Join(param, "&"))
  223. }
  224. return b.String()
  225. }
  226. // 输出代表一个节点的关键信息
  227. func (h *HostInfo) Key() string {
  228. if h == nil {
  229. // 避免空出错
  230. return ""
  231. }
  232. return fmt.Sprintf("%s%d://%s:%d%s", h.Proto, h.Version, h.Host, h.Port, h.Path)
  233. }
  234. // 获取对应频道的一个连接地址
  235. type ConnectHostFunc func(channel string, hostType HostType) (hostInfo *HostInfo, err error)
  236. // 获取认证信息
  237. type AuthFunc func(client bool, proto string, version uint8, channel string, remoteAuth []byte) (auth []byte)
  238. // 认证合法性函数
  239. type CheckAuthFunc func(client bool, proto string, version uint8, channel string, auth []byte) bool
  240. // 验证发送的数据条件是否满足
  241. type CheckConnectOkFunc = func(line *Line, data *GetData) bool