github.com/volts-dev/volts@v0.0.0-20240120094013-5e9c65924106/router/tree.go (about) 1 package router 2 3 import ( 4 "bytes" 5 "fmt" 6 "regexp" 7 "sort" 8 "strings" 9 "sync" 10 11 "github.com/volts-dev/utils" 12 "github.com/volts-dev/volts/registry" 13 "go.uber.org/atomic" 14 ) 15 16 /* 17 tree 负责路由树的解析,排序,匹配 18 实现前面加类型 19 '/web/content/<string:xmlid>', 20 '/web/content/<string:xmlid>/<string:filename>', 21 '/web/content/<int:id>', 22 '/web/content/<int:id>/<string:filename>', 23 '/web/content/<int:id>-<string:unique>', 24 '/web/content/<int:id>-<string:unique>/<string:filename>', 25 '/web/content/<string:model>/<int:id>/<string:field>', 26 '/web/content/<string:model>/<int:id>/<string:field>/<string:filename>' 27 */ 28 const ( 29 StaticNode NodeType = iota // static, should equal 30 VariantNode // named node, match a non-/ is ok 31 AnyNode // catch-all node, match any 32 RegexpNode // regex node, should match 33 34 AllType ContentType = iota 35 NumberType 36 CharType 37 38 LBracket = '<' 39 RBracket = '>' 40 ) 41 42 var ( 43 nodeType = map[NodeType]string{ 44 StaticNode: "Static", // static, should equal 45 VariantNode: "Var", // named node, match a non-/ is ok 46 AnyNode: "Any", // catch-all node, match any 47 RegexpNode: "Reg", // regex node, should match 48 } 49 50 contentType = map[ContentType]string{ 51 AllType: "all", 52 NumberType: "int", 53 CharType: "string", 54 } 55 ) 56 57 type NodeType byte // 节点类型 58 func (self NodeType) String() string { 59 return [...]string{"StaticNode", "VariantNode", "AnyNode", "RegexpNode"}[self] 60 } 61 62 type ContentType byte // 变量类型 63 func (self ContentType) String() string { 64 return [...]string{"AllType", "NumberType", "CharType"}[self] 65 } 66 67 type ( 68 param struct { 69 Name string 70 Value string 71 } 72 73 Params []param 74 75 // 配置函数接口 76 ConfigOption func(*TTree) 77 78 // 使用Sort 接口自动排序 79 subNodes []*treeNode 80 81 treeNode struct { 82 Route *route 83 Type NodeType 84 ContentType ContentType 85 Children subNodes 86 Text string // Path string /web/ 87 Path string 88 Level int // #动态Node排序等级 /.../ 之间的Nodes越多等级越高 89 regexp *regexp.Regexp 90 } 91 92 // safely tree 93 TTree struct { 94 sync.RWMutex // lock for conbine action 95 root map[string]*treeNode 96 Text string 97 IgnoreCase bool 98 __DelimitChar byte // Delimit Char xxx<.>xxx 99 PrefixChar byte // the Prefix Char </>xxx.xxx 100 Count atomic.Int32 101 } 102 ) 103 104 func (p *Params) Get(key string) string { 105 for _, v := range *p { 106 if v.Name == key { 107 return v.Value 108 } 109 } 110 return "" 111 } 112 113 func (p *Params) Set(key, value string) { 114 for i, v := range *p { 115 if v.Name == key { 116 (*p)[i].Value = value 117 return 118 } 119 } 120 } 121 122 func (p *Params) SetParams(params []param) { 123 *p = params 124 } 125 126 func (self subNodes) Len() int { 127 return len(self) 128 } 129 130 func (self subNodes) Swap(i, j int) { 131 self[i], self[j] = self[j], self[i] 132 } 133 134 // static route will be put the first, so it will be match first. 135 // two static route, content longer is first. 136 func (self subNodes) Less(i, j int) bool { 137 if self[i].Type == StaticNode { 138 if self[j].Type == StaticNode { 139 return len(self[i].Text) > len(self[j].Text) 140 } 141 return true 142 } 143 144 if self[j].Type == StaticNode { 145 return false 146 } else { 147 return self[i].Level > self[j].Level 148 } 149 150 //return i < j 151 } 152 153 func NewRouteTree(opts ...ConfigOption) *TTree { 154 tree := &TTree{ 155 root: make(map[string]*treeNode), 156 __DelimitChar: 0, // !NOTE! 默认为未定义 以便区分RPC 157 PrefixChar: '/', 158 } 159 tree.Init(opts...) 160 return tree 161 } 162 163 func (self *TTree) Init(opts ...ConfigOption) { 164 for _, cfg := range opts { 165 cfg(self) 166 } 167 } 168 169 // 解析Path为Node 170 /* /:name1/:name2 /:name1-:name2 /(:name1)sss(:name2) 171 /(*name) /(:name[0-9]+) /(type:name[a-z]+) 172 Result: @ Nodes List 173 @ is it dyn route 174 */ 175 func (r *TTree) parsePath(path string, delimitChar byte) (nodes []*treeNode, isDyn bool) { 176 if path == "" { 177 panic("path cannot be empty") 178 } 179 180 if delimitChar == '/' && path[0] != '/' { 181 path = "/" + path 182 } 183 184 var ( 185 i, startOffset int // i 游标 J 上次标记 186 187 bracket int 188 level int // #Node的 排序等级 189 target *treeNode // 记录等级的Node 一般为/ 开始的第一个动态 190 node *treeNode 191 ) 192 // 默认 193 nodes = make([]*treeNode, 0) 194 isDyn = false 195 l := len(path) 196 //j = i - 1 // 当i==0时J必须小于它 197 for ; i < l; i++ { 198 switch path[i] { 199 case delimitChar: 200 { // 创建Text:'/' Node 201 if bracket == 0 && i > startOffset { 202 //if path[j] == '/' { 203 // nodes = append(nodes, &treeNode{Type: StaticNode, Text: string(path[j])}) 204 //} 205 //j++ 206 nodes = append(nodes, &treeNode{Type: StaticNode, Level: 0, Text: path[startOffset:i]}) 207 startOffset = i 208 } 209 210 // # 重置计数 211 target = nil 212 level = 0 // #开始计数 213 } 214 case LBracket: 215 { 216 bracket = 1 217 } 218 case ':': 219 { 220 var typ ContentType = AllType 221 if path[i-1] == LBracket { //#like (:var) 222 // 添加变量前的静态字符节点 223 nodes = append(nodes, &treeNode{Type: StaticNode, Text: path[startOffset : i-bracket]}) 224 bracket = 1 225 } else { 226 // #为变量区分数据类型 227 str := path[startOffset : i-bracket] // #like /abc1(string|upper:var) 228 idx := strings.Index(str, string(LBracket)) 229 if idx == -1 { 230 log.Fatalf("expect a %s near path %s position %d~%d", path, string(LBracket), startOffset, i) 231 } 232 nodes = append(nodes, &treeNode{Type: StaticNode, Text: str[:idx]}) 233 str = str[idx+1:] 234 switch str { 235 case "int": 236 typ = NumberType 237 case "string": 238 typ = CharType 239 default: 240 typ = AllType 241 } 242 bracket = 1 243 } 244 245 startOffset = i 246 var ( 247 regex string 248 start = -1 249 ) 250 251 if bracket == 1 { 252 // 开始记录Pos 253 for ; i < l && RBracket != path[i]; i++ { // 移动Pos到")" 遇到正则字符标记起 254 if start == -1 && utils.IsSpecialByte(path[i]) { // 如果是正则 255 start = i 256 } 257 } 258 if path[i] != RBracket { 259 panic(fmt.Sprintf("lack of %v", RBracket)) 260 } 261 262 if start > -1 { 263 regex = path[start:i] //正则内容 264 } 265 } else { 266 i = i + 1 267 for ; i < l && utils.IsAlnumByte(path[i]); i++ { 268 } 269 } 270 271 if len(regex) > 0 { // 正则 272 node = &treeNode{Type: RegexpNode, regexp: regexp.MustCompile("(" + regex + ")"), Text: path[startOffset : i-len(regex)]} 273 nodes = append(nodes, node) 274 } else { // 变量 275 node = &treeNode{Type: VariantNode, Level: level + 1, ContentType: typ, Text: path[startOffset:i]} 276 nodes = append(nodes, node) 277 } 278 279 isDyn = true // #标记 Route 为动态 280 i = i + bracket // #剔除")"字符 bracket=len(“)”) 281 startOffset = i 282 283 // 当计数器遇到/或者Url末尾时将记录保存于Node中 284 if target != nil && ((i == l) || (i != l && path[startOffset+1] == delimitChar)) { 285 level++ 286 target.Level = level 287 288 // # 重置计数 289 target = nil 290 level = 0 291 } 292 293 if i == l { 294 return //nodes, isDyn 295 } 296 297 // #计数滴答 298 // 放置在 i == l 后 确保表达式2比1多一个层级 299 // @/(int:id1)-(:unique2) 300 // @/(:id3)-(:unique3)/(:filename) 301 if (i != l && path[startOffset] != delimitChar) || level != 0 { 302 if level == 0 { 303 target = node 304 } 305 306 level++ 307 } 308 } 309 case '*': 310 { 311 nodes = append(nodes, &treeNode{Type: StaticNode, Text: path[startOffset : i-bracket]}) 312 startOffset = i 313 //if bracket == 1 { 314 // for ; i < l && RBracket == path[i]; i++ { 315 // } 316 //} else { 317 i = i + 1 318 for ; i < l && utils.IsAlnumByte(path[i]); i++ { 319 } 320 //} 321 nodes = append(nodes, &treeNode{Type: AnyNode, Level: -1, Text: path[startOffset:i]}) 322 isDyn = true // 标记 Route 为动态 323 i = i + bracket // bracket=len(“)”) 324 startOffset = i 325 if i == l { 326 return //nodes, isDyn 327 } 328 } 329 330 default: 331 { 332 bracket = 0 333 } 334 } 335 } 336 337 nodes = append(nodes, &treeNode{ 338 Type: StaticNode, 339 Text: path[startOffset:i], 340 }) 341 342 return //nodes, isDyn 343 } 344 345 func (r *TTree) matchNode(node *treeNode, path string, delimitChar byte, aParams *Params) *treeNode { 346 var retnil bool 347 if node.Type == StaticNode { // 静态节点 348 // match static node 349 if strings.HasPrefix(path, node.Text) { 350 if len(path) == len(node.Text) { 351 return node 352 } 353 354 for _, c := range node.Children { 355 e := r.matchNode(c, path[len(node.Text):], delimitChar, aParams) 356 if e != nil { 357 return e 358 } 359 } 360 } 361 362 } else if node.Type == AnyNode { // 全匹配节点 363 //if len(node.Children) == 0 { 364 // *aParams = append(*aParams, param{node.Text[1:], path}) 365 // return node 366 //} 367 for _, c := range node.Children { 368 idx := strings.LastIndex(path, c.Text) 369 if idx > -1 { 370 h := r.matchNode(c, path[idx:], delimitChar, aParams) 371 if h != nil { 372 *aParams = append(*aParams, param{node.Text[1:], path[:idx]}) 373 return h 374 } 375 376 } 377 } 378 379 *aParams = append(*aParams, param{node.Text[1:], path}) 380 return node 381 } else if node.Type == VariantNode { // 变量节点 382 // # 消除path like /abc 的'/' 383 // 根据首字符判断接下来的处理条件 384 first_Char := path[0] 385 if first_Char == delimitChar { 386 for _, c := range node.Children { 387 h := r.matchNode(c, path[0:], delimitChar, aParams) 388 if h != nil { 389 /* 390 if !validType(path[:idx], node.ContentType) { 391 fmt.Println("错误类型", path[:idx], node.ContentType) 392 return nil 393 } 394 */ 395 *aParams = append(*aParams, param{node.Text[1:], path[:0]}) 396 return h 397 } 398 } 399 return nil 400 } 401 402 isLast := strings.IndexByte(path, delimitChar) == -1 403 if (isLast || len(node.Children) == 0) && node.Route != nil { // !NOTE! 匹配到最后一个条件 404 *aParams = append(*aParams, param{node.Text[1:], path}) 405 return node 406 } else { // !NOTE! 匹配回溯 当匹配进入错误子节点返回nil到父节点重新匹配父节点 407 for _, c := range node.Children { 408 idx := strings.Index(path, c.Text) // #匹配前面检索到的/之前的字符串 409 if idx > -1 { 410 if len(path[:idx]) > 1 && strings.IndexByte(path[:idx], delimitChar) > -1 { 411 retnil = true 412 continue 413 } 414 415 if !validType(path[:idx], node.ContentType) { 416 continue 417 } 418 419 h := r.matchNode(c, path[idx:], delimitChar, aParams) 420 if h != nil { 421 *aParams = append(*aParams, param{node.Text[1:], path[:idx]}) 422 return h 423 } 424 retnil = true 425 } 426 } 427 428 if retnil || len(node.Children) > 0 { 429 return nil 430 } 431 } 432 } else if node.Type == RegexpNode { // 正则节点 433 //if len(node.Children) == 0 && node.regexp.MatchString(path) { 434 // *aParams = append(*aParams, param{node.Text[1:], path}) 435 // return node 436 //} 437 idx := strings.IndexByte(path, delimitChar) 438 if idx > -1 { 439 if node.regexp.MatchString(path[:idx]) { 440 for _, c := range node.Children { 441 h := r.matchNode(c, path[idx:], delimitChar, aParams) 442 if h != nil { 443 *aParams = append(*aParams, param{node.Text[1:], path[:idx]}) 444 return h 445 } 446 } 447 } 448 return nil 449 } 450 for _, c := range node.Children { 451 idx := strings.Index(path, c.Text) 452 if idx > -1 && node.regexp.MatchString(path[:idx]) { 453 h := r.matchNode(c, path[idx:], delimitChar, aParams) 454 if h != nil { 455 *aParams = append(*aParams, param{node.Text[1:], path[:idx]}) 456 return h 457 } 458 459 } 460 } 461 462 if node.regexp.MatchString(path) { 463 *aParams = append(*aParams, param{node.Text[1:], path}) 464 return node 465 } 466 467 } 468 469 return nil 470 } 471 472 func (self *TTree) Endpoints() (services map[*TGroup][]*registry.Endpoint) { 473 services = make(map[*TGroup][]*registry.Endpoint, 0) 474 validator := make(map[string]*route) 475 var match func(method string, i int, node *treeNode) 476 match = func(method string, i int, node *treeNode) { 477 for _, c := range node.Children { 478 if c.Route != nil && c.Route.group != nil { 479 grp := c.Route.group 480 // TODO 检测 481 if _, ok := validator[c.Route.Path]; !ok { 482 // 483 } 484 485 if eps, has := services[grp]; has { 486 services[grp] = append(eps, RouteToEndpiont(c.Route)) 487 } else { 488 services[grp] = []*registry.Endpoint{RouteToEndpiont(c.Route)} 489 } 490 } 491 match(method, i+1, c) 492 } 493 } 494 495 for method, node := range self.root { 496 if len(node.Children) > 0 { 497 match(method, 1, node) 498 } 499 } 500 501 return services 502 } 503 504 func (r *TTree) Match(method string, path string) (*route, Params) { 505 var delimitChar byte = '/' 506 if method == "CONNECT" { 507 delimitChar = '.' 508 } 509 510 root := r.root[method] 511 if root != nil { 512 prefix_char := string(r.PrefixChar) 513 // trim the Url to including "/" on begin of path 514 if !strings.HasPrefix(path, prefix_char) && path != prefix_char { 515 path = prefix_char + path 516 } 517 518 var params = make(Params, 0, strings.Count(path, string(delimitChar))) 519 for _, n := range root.Children { 520 e := r.matchNode(n, path, delimitChar, ¶ms) 521 if e != nil { 522 return e.Route, params 523 } 524 } 525 } 526 527 return nil, nil 528 } 529 530 // add nodes to trees 531 func (self *TTree) addNodes(method string, nodes []*treeNode, isHook bool) { 532 // 获得对应方法[POST,GET...] 533 cn := self.root[method] 534 if cn == nil { 535 // 初始化Root node 536 cn = &treeNode{ 537 Children: subNodes{}, 538 } 539 self.root[method] = cn 540 } 541 542 var p *treeNode = cn // 复制方法对应的Root 543 544 // 层级插入Nodes的Node到Root 545 for idx := range nodes { 546 p = cn.addNode(self, p, nodes, idx, isHook) 547 } 548 } 549 550 // 添加路由到Tree 551 func (self *TTree) AddRoute(route *route) error { 552 if route == nil { 553 return nil 554 } 555 556 for _, method := range route.Methods { 557 method = strings.ToUpper(method) 558 559 delimitChar := route.PathDelimitChar 560 561 // to parse path as a List node 562 nodes, _ := self.parsePath(route.Path, delimitChar) 563 564 // 绑定Route到最后一个Node 565 node := nodes[len(nodes)-1] 566 route.Action = node.Text // 赋值Action 567 node.Route = route 568 node.Path = route.Path // 存储路由绑定的URL 569 570 // 验证合法性 571 if !validNodes(nodes) { 572 log.Panicf("express %s is not supported", route.Path) 573 } 574 575 // insert the node to tree 576 self.addNodes(method, nodes, false) 577 } 578 579 return nil 580 } 581 582 // delete the route 583 func (self *TTree) DelRoute(path string, route *route) error { 584 if route == nil { 585 return nil 586 } 587 for _, method := range route.Methods { 588 n := self.root[method] 589 if n == nil { 590 return nil 591 } 592 593 var delimitChar byte = '/' 594 if method == "CONNECT" { 595 delimitChar = '.' 596 } 597 598 // to parse path as a List node 599 nodes, _ := self.parsePath(path, delimitChar) 600 601 var p *treeNode = n // 复制方法对应的Root 602 603 // 层级插入Nodes的Node到Root 604 for idx := range nodes { 605 p = n.delNode(self, p, nodes, idx) 606 } 607 } 608 return nil 609 } 610 611 // conbine 2 node together 612 func (self *TTree) conbine(target, from *treeNode) { 613 var exist_node *treeNode 614 615 // 是否目标Node有该Node 616 for _, n := range target.Children { 617 if n.Equal(from) { 618 exist_node = n 619 } 620 } 621 // 如果:无该Node直接添加完成所有工作 622 // 或者:遍历添加所有没有的新Node 623 if exist_node == nil { 624 target.Children = append(target.Children, from) 625 return 626 } else { 627 if exist_node.Type == RegexpNode { 628 629 } 630 631 if from.Route != nil { 632 if exist_node.Route == nil { 633 exist_node.Route = from.Route 634 } else { 635 // 叠加合并Controller 636 exist_node.Route.CombineHandler(from.Route) 637 } 638 } 639 640 // conbine sub-node 641 for _, n := range from.Children { 642 self.conbine(exist_node, n) 643 } 644 } 645 } 646 647 // conbine 2 tree together 648 func (self *TTree) Conbine(from *TTree) *TTree { 649 // NOTE 避免合并不同分隔符的路由树 不应该发生 650 if len(self.root) > 0 && len(from.root) > 0 { // 非空的Tree 651 if self.__DelimitChar != from.__DelimitChar { // 分隔符对比 652 log.Panicf("could not conbine 2 different kinds (RPC/HTTP) of routes tree!") 653 return self 654 } 655 } 656 657 self.Lock() 658 defer self.Unlock() 659 for method, new_node := range from.root { 660 if main_nodes, has := self.root[method]; !has { 661 self.root[method] = new_node 662 } else { 663 for _, node := range new_node.Children { 664 self.conbine(main_nodes, node) 665 } 666 } 667 } 668 669 return self 670 } 671 672 func (self *TTree) PrintTrees() { 673 buf := bytes.NewBufferString("") 674 buf.WriteString("Print routes tree:\n") 675 for method, node := range self.root { 676 if len(node.Children) > 0 { 677 buf.WriteString(method + "\n") 678 printNode(buf, 1, node, "") 679 buf.WriteString("\n") 680 } 681 } 682 log.Info(buf.String()) 683 } 684 685 // add node nodes[i] to parent node p 686 func (self *treeNode) addNode(tree *TTree, parent *treeNode, nodes []*treeNode, i int, isHook bool) *treeNode { 687 if len(parent.Children) == 0 { 688 parent.Children = make([]*treeNode, 0) 689 } 690 691 // 如果:找到[已经注册]的分支节点则从该节继续[查找/添加]下一个节点 692 for _, n := range parent.Children { 693 if n.Equal(nodes[i]) { 694 // 如果:插入的节点层级已经到末尾,则为该节点注册路由 695 if i == len(nodes)-1 { 696 // 原始路由会被替换 697 if isHook { 698 n.Route.CombineHandler(nodes[i].Route) 699 } else { 700 n.Route = nodes[i].Route 701 tree.Count.Inc() 702 } 703 } 704 return n 705 } 706 } 707 708 // 如果:该节点没有对应分支则插入同级的nodes为新的分支 709 parent.Children = append(parent.Children, nodes[i]) 710 sort.Sort(parent.Children) 711 return nodes[i] 712 } 713 714 func (self *treeNode) delNode(tree *TTree, parent *treeNode, nodes []*treeNode, i int) *treeNode { 715 // 如果:找到[已经注册]的分支节点则从该节继续[查找/添加]下一个节点 716 for _, n := range parent.Children { 717 if n.Equal(nodes[i]) { 718 // 如果:插入的节点层级已经到末尾,则为该节点注册路由 719 if i == len(nodes)-1 { 720 // 剥离目标控制器 721 n.Route.StripHandler(nodes[i].Route) 722 tree.Count.Dec() // 递减计数器 723 } 724 return n 725 } 726 } 727 728 sort.Sort(parent.Children) 729 return nodes[i] 730 } 731 732 func (self *treeNode) Equal(node *treeNode) bool { 733 if self.Type != node.Type || self.Text != node.Text || self.ContentType != node.ContentType { 734 return false 735 } 736 return true 737 } 738 739 func validType(content string, typ ContentType) bool { 740 switch typ { 741 case NumberType: 742 for i := 0; i < len(content); i++ { 743 if !utils.IsDigitByte(content[i]) { 744 return false 745 } 746 } 747 case CharType: 748 for i := 0; i < len(content); i++ { 749 if !utils.IsAlphaByte(content[i]) { 750 return false 751 } 752 } 753 default: 754 // 所有字符串 755 return true 756 } 757 758 return true 759 } 760 761 // validate parsed nodes, all non-static route should have static route children. 762 func validNodes(nodes []*treeNode) bool { 763 if len(nodes) == 0 { 764 return false 765 } 766 var lastTp = nodes[0] 767 for _, node := range nodes[1:] { 768 if lastTp.Type != StaticNode && node.Type != StaticNode { 769 return false 770 } 771 lastTp = node 772 } 773 return true 774 } 775 776 func printNode(buf *bytes.Buffer, lv int, node *treeNode, path string) { 777 cnt := len(node.Children) 778 isLast := false 779 subPath := "" 780 for idx, c := range node.Children { 781 isLast = idx == cnt-1 782 783 // 计算子路径打印方式 784 if isLast { // 如果是最后一个 785 subPath = path + " " // 空格距离 786 } else { 787 subPath = path + " | " 788 } 789 790 buf.WriteString(path + " |-- ") 791 buf.WriteString(fmt.Sprintf(`%s ==> Lv:%d Type:%v VarType:%v `, c.Text, c.Level, nodeType[c.Type], contentType[c.ContentType])) 792 if c.Route != nil { 793 if c.Route.group != nil { 794 buf.WriteString(fmt.Sprintf(" (*%d Mod:%s)", len(c.Route.handlers), c.Route.group.String())) 795 } else { 796 buf.WriteString(fmt.Sprintf(" (*%d)", len(c.Route.handlers))) 797 } 798 } 799 800 //if !reflect.DeepEqual(c.Route, route{}) { 801 if c.Route != nil { 802 //fmt.Print(" ", c.Route.HandleType.String()) 803 //fmt.Printf(" %p", c.handle.method.Interface()) 804 } 805 buf.WriteString("\n") 806 printNode(buf, lv+1, c, subPath) 807 } 808 } 809 810 // 忽略大小写 811 func WithIgnoreCase() ConfigOption { 812 return func(tree *TTree) { 813 tree.IgnoreCase = true 814 } 815 }