-
Notifications
You must be signed in to change notification settings - Fork 41
/
routes.go
114 lines (96 loc) · 2.53 KB
/
routes.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
package canopus
import (
"fmt"
"regexp"
)
// CreateNewRoute creates a new Route object
func CreateNewRegExRoute(path string, method string, fn RouteHandler) Route {
var re *regexp.Regexp
regexpString := path
// Dots
re = regexp.MustCompile(`([^\\])\.`)
regexpString = re.ReplaceAllStringFunc(regexpString, func(m string) string {
return fmt.Sprintf(`%s\.`, string(m[0]))
})
// Wildcard names
re = regexp.MustCompile(`:[^/#?()\.\\]+\*`)
regexpString = re.ReplaceAllStringFunc(regexpString, func(m string) string {
return fmt.Sprintf("(?P<%s>.+)", m[1:len(m)-1])
})
re = regexp.MustCompile(`:[^/#?()\.\\]+`)
regexpString = re.ReplaceAllStringFunc(regexpString, func(m string) string {
return fmt.Sprintf(`(?P<%s>[^/#?]+)`, m[1:len(m)])
})
s := fmt.Sprintf(`\A%s\z`, regexpString)
return &RegExRoute{
AutoAck: false,
Path: path,
Method: method,
Handler: fn,
RegEx: regexp.MustCompile(s),
}
}
// Route represents a CoAP Route/Resource
type RegExRoute struct {
Path string
Method string
Handler RouteHandler
RegEx *regexp.Regexp
AutoAck bool
MediaTypes []MediaType
}
func (r *RegExRoute) Matches(path string) (bool, map[string]string) {
re := r.RegEx
matches := re.FindAllStringSubmatch(path, -1)
attrs := make(map[string]string)
if len(matches) > 0 {
subExp := re.SubexpNames()
for idx, exp := range subExp {
attrs[exp] = matches[0][idx]
}
return true, attrs
}
return false, attrs
}
func (r *RegExRoute) GetMethod() string {
return r.Method
}
func (r *RegExRoute) GetMediaTypes() []MediaType {
return r.MediaTypes
}
func (r *RegExRoute) GetConfiguredPath() string {
return r.Path
}
func (r *RegExRoute) AutoAcknowledge() bool {
return r.AutoAck
}
func (r *RegExRoute) Handle(req Request) Response {
return r.Handler(req)
}
// MatchingRoute checks if a given path matches any defined routes/resources
func MatchingRoute(path string, method string, cf interface{}, routes []Route) (Route, map[string]string, error) {
for _, route := range routes {
if method == route.GetMethod() {
match, attrs := route.Matches(path)
if match {
if len(route.GetMediaTypes()) > 0 {
if cf == nil {
return route, attrs, ErrUnsupportedContentFormat
}
foundMediaType := false
for _, o := range route.GetMediaTypes() {
if uint32(o) == cf {
foundMediaType = true
break
}
}
if !foundMediaType {
return route, attrs, ErrUnsupportedContentFormat
}
}
return route, attrs, nil
}
}
}
return nil, nil, ErrNoMatchingRoute
}