1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
package main
import (
"fmt"
"strings"
)
// HandlerFunc defines the handler function type
type HandlerFunc func(params map[string]string)
// Node represents a node in the Radix Tree
type Node struct {
Children map[string]*Node
Handler HandlerFunc
Param string
IsParam bool
IsWild bool
}
// RadixTree represents the Radix Tree
type RadixTree struct {
Root *Node
}
// NewRadixTree creates a new Radix Tree
func NewRadixTree() *RadixTree {
return &RadixTree{Root: &Node{Children: make(map[string]*Node)}}
}
// Insert inserts a path and its handler into the Radix Tree
func (rt *RadixTree) Insert(path string, handler HandlerFunc) {
node := rt.Root
segments := strings.Split(path, "/")
for i := 0; i < len(segments); i++ {
segment := segments[i]
if segment == "" {
continue
}
var child *Node
var exists bool
if segment[0] == ':' {
segment = ":"
exists = false
for _, v := range node.Children {
if v.IsParam {
child = v
exists = true
break
}
}
} else if segment[0] == '*' {
segment = "*"
exists = false
for _, v := range node.Children {
if v.IsWild {
child = v
exists = true
break
}
}
} else {
child, exists = node.Children[segment]
}
if !exists {
child = &Node{Children: make(map[string]*Node)}
node.Children[segment] = child
if segment == ":" {
child.IsParam = true
child.Param = segments[i][1:]
} else if segment == "*" {
child.IsWild = true
child.Param = segments[i][1:]
}
}
node = child
}
node.Handler = handler
}
// Search searches for a path in the Radix Tree and returns its handler and parameters
func (rt *RadixTree) Search(path string) (HandlerFunc, map[string]string) {
node := rt.Root
params := make(map[string]string)
segments := strings.Split(path, "/")
for i := 0; i < len(segments); i++ {
segment := segments[i]
if segment == "" {
continue
}
var child *Node
var exists bool
if child, exists = node.Children[segment]; !exists {
if child, exists = node.Children[":"]; exists {
params[child.Param] = segment
} else if child, exists = node.Children["*"]; exists {
params[child.Param] = strings.Join(segments[i:], "/")
return child.Handler, params
} else {
return nil, nil
}
}
node = child
}
return node.Handler, params
}
// Router represents the HTTP router with method based routing tables
type Router struct {
trees map[string]*RadixTree
}
// NewRouter creates a new Router
func NewRouter() *Router {
return &Router{trees: make(map[string]*RadixTree)}
}
// AddRoute adds a route to the router
func (r *Router) AddRoute(method, path string, handler HandlerFunc) {
if r.trees[method] == nil {
r.trees[method] = NewRadixTree()
}
r.trees[method].Insert(path, handler)
}
// FindRoute finds a route in the router
func (r *Router) FindRoute(method, path string) (HandlerFunc, map[string]string) {
if r.trees[method] == nil {
return nil, nil
}
return r.trees[method].Search(path)
}
func main() {
router := NewRouter()
router.AddRoute("GET", "/user/:id", func(params map[string]string) {
fmt.Println("User handler, ID:", params["id"])
})
router.AddRoute("GET", "/static/*filepath", func(params map[string]string) {
fmt.Println("Static file handler, filepath:", params["filepath"])
})
handler, params := router.FindRoute("GET", "/user/123")
if handler != nil {
handler(params)
} else {
fmt.Println("Not found")
}
handler, params = router.FindRoute("GET", "/static/css/style.css")
if handler != nil {
handler(params)
} else {
fmt.Println("Not found")
}
}
|