/
dispatcher.go
169 lines (143 loc) · 3.87 KB
/
dispatcher.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
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
169
package dogo
import (
"fmt"
"net/http"
"net/url"
"strings"
)
var cache = make(map[string]*SampleRoute)
type Dispatcher struct {
App *App
Router *Router
module string
controller string
action string
found bool
DefModule string
}
func NewDispatcher(app *App, router *Router) *Dispatcher {
d := &Dispatcher{App: app, Router: router}
return d.Init()
}
//on dispatcher init
func (d *Dispatcher) Init() *Dispatcher {
d.module = "Index"
d.controller = "Index"
d.action = "Index"
return d
}
//serveHTTP
func (d *Dispatcher) ServeHTTP(w http.ResponseWriter, r *http.Request) {
d.found = false
d.Static(w, r)
if d.found == false {
d.RouteRegex(w, r)
}
if d.found == false {
d.RouteSample(w, r)
}
if d.found == false {
http.NotFound(w, r)
}
return
}
// route a static route
func (d *Dispatcher) Static(w http.ResponseWriter, r *http.Request) {
for prefix, staticDir := range d.Router.StaticRoutes {
if strings.HasPrefix(r.URL.Path, prefix) {
file := staticDir + r.URL.Path[len(prefix):]
http.ServeFile(w, r, file)
d.found = true
}
}
}
// routed an regex route
func (d *Dispatcher) RouteRegex(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
if length := len(d.Router.RegexRoutes); length == 0 {
return
}
for _, route := range d.Router.RegexRoutes {
//check if Route pattern matches url
if route.regex.MatchString(path) {
//get submatches (params)
matches := route.regex.FindStringSubmatch(path)
//double check that the Route matches the URL pattern.
if len(matches[0]) == len(path) {
if len(route.params) > 0 {
//add url parameters to the query param map
values := r.URL.Query()
for i, match := range matches[1:] {
values.Add(route.params[i], match)
}
//reassemble query params and add to RawQuery
r.URL.RawQuery = url.Values(values).Encode() + "&" + r.URL.RawQuery
}
parts := strings.Split(route.forward, "/")
d.module, d.controller, d.action = parts[1], parts[2], Util_UCFirst(parts[3])
d.Match(w, r)
break
}
}
}
}
//route a map route
func (d *Dispatcher) RouteSample(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
//get request path
parts := strings.Split(path, "/")
length := len(parts)
//get module, controller, action
if length == 4 {
d.module = strings.ToLower(parts[1])
d.controller = strings.ToLower(parts[2])
d.action = d.getAction(strings.ToLower(parts[3]))
}
if length < 4 && d.DefModule != "" {
d.module = d.DefModule
d.controller = strings.ToLower(parts[1])
if length == 3 {
d.action = d.getAction(strings.ToLower(parts[2]))
}
r.URL.Path = strings.ToLower(fmt.Sprintf("/%s/%s/%s", d.module, d.controller, d.action))
}
d.Match(w, r)
}
func (d *Dispatcher) getAction(action string) string {
acts := strings.Split(action, "_")
var fmt_acts []string
for _, str := range acts {
fmt_acts = append(fmt_acts, Util_UCFirst(str))
}
return strings.Join(fmt_acts, "_")
}
func (d *Dispatcher) Match(w http.ResponseWriter, r *http.Request) {
var sampleRoute *SampleRoute
// find maproute
for _, value := range d.Router.SampleRoutes {
if value.module == d.module && value.name == d.controller {
sampleRoute, d.found = value, true
break
}
}
if d.found {
d.Exec(sampleRoute, w, r)
}
}
func (d *Dispatcher) Exec(sampleRoute *SampleRoute, w http.ResponseWriter, r *http.Request) {
rv := sampleRoute.NewController()
//set context and dispatcher
sampleRoute.CallFunc(rv, "SetContext", w, r)
//the controller contruct can not overwrite
sampleRoute.CallFunc(rv, "BeferAction", d.module, d.controller, d.action)
//functions can overwrite
sampleRoute.CallFunc(rv, "Init")
sampleRoute.CallFunc(rv, d.action)
sampleRoute.CallFunc(rv, "Render")
//on the controller destruct
sampleRoute.CallFunc(rv, "AfterAction")
}
func (d *Dispatcher) SetDefaultModule(name string) *Dispatcher {
d.DefModule = name
return d
}