package main
import (
"errors"
"net/http"
"strings"
)
type ControllerHandler func(r *http.Request, w http.ResponseWriter)
type Tree struct {
root *node
}
type node struct {
isLast bool
segment string
handler ControllerHandler
children []*node
http.Handler
}
func isWildSegment(segment string) bool {
return strings.HasPrefix(segment, ":")
}
func (n *node) filterChildNodes(segment string) []*node {
if n.children == nil || len(n.children) == 0 {
return nil
}
if isWildSegment(segment) {
return n.children
}
nodes := make([]*node, 0, len(n.children))
for _, cnode := range n.children {
if isWildSegment(cnode.segment) {
nodes = append(nodes, cnode)
} else if cnode.segment == segment {
nodes = append(nodes, cnode)
}
}
return nodes
}
func (n *node) matchNode(uri string) *node {
segments := strings.SplitN(uri, "/", 2)
segment := segments[0]
if !isWildSegment(segment) {
segment = strings.ToUpper(segment)
}
nodes := n.filterChildNodes(segment)
if nodes == nil || len(nodes) == 0 {
return nil
}
if len(segments) == 1 {
for _, tn := range nodes {
if tn.isLast {
return tn
}
}
// 都不是最后一个节点
return nil
}
// 如果有2个segment, 递归每个子节点继续进行查找
for _, tn := range nodes {
tnMatch := tn.matchNode(segments[1])
if tnMatch != nil {
return tnMatch
}
}
return nil
}
func newNode() *node {
return &node{
isLast: false,
segment: "",
handler: nil,
children: make([]*node, 0, 10),
Handler: nil,
}
}
func (tree *Tree) AddRouter(uri string, handler ControllerHandler) error {
n := tree.root
if n.matchNode(uri) != nil {
return errors.New("route exist: " + uri)
}
segments := strings.Split(uri, "/")
for index, segment := range segments {
if !isWildSegment(segment) {
segment = strings.ToUpper(segment)
}
isLast := index == len(segments)-1
var objNode *node
childNodes := n.filterChildNodes(segment)
if len(childNodes) > 0 {
for _, cnode := range childNodes {
if cnode.segment == segment {
objNode = cnode
break
}
}
}
if objNode == nil {
cnode := newNode()
cnode.segment = segment
if isLast {
cnode.isLast = true
cnode.handler = handler
}
n.children = append(n.children, cnode)
objNode = cnode
}
n = objNode
}
return nil
}
func main() {
t := Tree{
root: newNode(),
}
t.AddRouter("/book/list", nil)
t.AddRouter("/book/name", nil)
}
tire-go实现
最新推荐文章于 2024-08-03 21:24:43 发布