-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathnode.go
135 lines (125 loc) · 2.96 KB
/
node.go
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
package hermes
import (
"bytes"
"fmt"
)
type node struct {
wildcard *node
children map[string]*node
handler Handler
names []string
}
func newNode() *node {
return &node{
children: make(map[string]*node),
}
}
func (n *node) Add(path string, handler Handler, names []string, middlewares []Middleware) {
// Split path into chunks between `/`
pathBytes := bytes.Split([]byte(path), []byte{'/'})
lpath := len(pathBytes)
parent := n
// Go though all chars
for i := 0; i < lpath; i++ {
token := pathBytes[i]
if len(token) > 0 {
// If this token is a wildcard
if token[0] == ':' {
name := string(token[1:])
node := parent.wildcard
nodeCreated := false
if node == nil {
node = newNode()
parent.wildcard = node
nodeCreated = true
}
// If names is not defined yet
if names == nil {
names = make([]string, 0, 2) // Starts with a capacity of 2
}
names = append(names, name)
parent = node
if i+1 >= lpath {
if !nodeCreated && node.handler != nil {
// Two wildcard created with the same stuff
panic(fmt.Sprintf("conflict adding '%s'", path))
}
// Initialize stuff
node.names = names
node.handler = newHandler(handler, middlewares)
}
continue
} else {
spath := string(pathBytes[i])
node, ok := parent.children[spath]
// If the child does not exists, it will create a new one.
if !ok {
node = newNode()
parent.children[spath] = node
}
// If this is not the end
if i+1 < lpath {
parent = node
} else {
// This is the end of the path
if ok && node.handler != nil {
panic(fmt.Sprintf("conflict adding '%s'", path))
}
node.names = names
node.handler = newHandler(handler, middlewares)
return
}
}
} else if i+1 < lpath {
// Cannot deal with empty tokens
panic("empty token")
} else {
// Just set the node info
n.names = names
n.handler = newHandler(handler, middlewares)
}
}
}
func newHandler(h Handler, m []Middleware) Handler {
sagas := make([]Handler, len(m)+1)
sagas[len(m)] = h
idx := len(m) - 1
for idx > -1 {
i := idx
sagas[i] = func(nextReq Request, nextRes Response) Result {
return m[i](nextReq, nextRes, sagas[i+1])
}
idx--
}
return sagas[0]
}
func (n *node) Matches(s int, path *tokensDescriptor, values *tokensDescriptor) (bool, *node) {
for i := s; i < path.n; i++ {
token := string(path.m[i])
node, ok := n.children[token]
if ok {
if i+1 < path.n {
return node.Matches(i+1, path, values)
} else if node.handler == nil {
return false, nil
} else {
return true, node
}
} else if n.wildcard != nil {
if values != nil {
values.m = append(values.m, path.m[i])
values.n++
}
if i+1 < path.n {
return n.wildcard.Matches(i+1, path, values)
} else if n.wildcard.handler == nil {
return false, nil
} else {
return true, n.wildcard
}
} else {
return false, nil
}
}
return false, nil
}