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, &params)
   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  }