-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrest.go
500 lines (413 loc) · 13.3 KB
/
grest.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
package grest
/*
静态文件 放在 static 目录下.
默认 css/img/js 在 static 目录之下.
路由规则: /controllerName/actionName
controllerName 和 actionName 不区分大小写.
但是 actionName对应的函数名 必须大写开头,否则无法找到actionName对应的函数.
例如:
s.AddController("hotel", reflect.TypeOf(controller.TestController{}))
那么:
/Hotel/IndexFunc
/Hotel/InDexFunc
/Hotel/InDexFunc
/hoteL/IndexFunc
/HoTel/inDexFunc 都会匹配并执行 controller.TestController.IndexFunc()
最佳实践:
s.AddController("hotel", reflect.TypeOf(controller.HotelController{}))
func ( c* HotelController) HotelOrder(){
//balabala .....
}
那么用户可以通过以下url访问 action 都是可以的:
1. /hotel/Hotelorder
2. /hotel/hotelorder
3. /Hotel/Hotelorder
4. /hotel/HotelOrder
5. /hotel/HOTELORDER
6. /HOTEL/HOTELORDER
7. .....
*/
import (
"fmt"
//"io/ioutil"
//"log"
"net"
"net/http"
//"net/url"
"reflect"
"strconv"
"strings"
"github.com/dereking/grest/log"
"go.uber.org/zap"
_ "golang.org/x/net/netutil"
redisCache "github.com/dereking/grest/cache/redis"
"github.com/dereking/grest/config"
//"github.com/dereking/grest/debug"
"github.com/dereking/grest/mvc"
"github.com/dereking/grest/session"
memsession "github.com/dereking/grest/session/providers/memory"
"github.com/dereking/grest/templateManager"
"golang.org/x/net/websocket"
)
const (
max = 100
)
type GrestServer struct {
handlerMap map[string]reflect.Type
listener net.Listener
}
func NewGrestServer(confName string) *GrestServer {
s := &GrestServer{handlerMap: make(map[string]reflect.Type, 0)}
//必须最先初始化
config.Initialize(confName)
redisCache.Initialize()
//initialize memsession first.
memsession.Initialize()
session.GetSessionManager()
templateManager.Initialize()
return s
}
func (s *GrestServer) Serve() {
addr := config.AppConfig.StringDefault("addr", ":8000")
log.Logger().Info("addr", zap.String("addr", addr))
listener, err := net.Listen("tcp", addr)
if err != nil {
log.Logger().Fatal("Listen error: ", zap.Error(err))
}
defer listener.Close()
//limit listener
//l = netutil.LimitListener(l, max)
http.Handle("/css/", http.FileServer(http.Dir("static")))
http.Handle("/js/", http.FileServer(http.Dir("static")))
http.Handle("/img/", http.FileServer(http.Dir("static")))
http.Handle("/fonts/", http.FileServer(http.Dir("static")))
http.Handle("/public/", http.FileServer(http.Dir("static")))
http.HandleFunc("/", s.ServeHTTPDispatch)
//limit listener
//listener = netutil.LimitListener(listener, max)
log.Logger().Info("Server running at", zap.String("addr", listener.Addr().String()))
http.Serve(listener, nil)
}
func (s *GrestServer) AddController(name string, ctlType reflect.Type) {
log.Logger().Debug("注册 controller", zap.String("name", name),
zap.String("ctlType", ctlType.String()))
if s.handlerMap[strings.ToLower(name)] != nil {
log.Logger().Warn("WARNING 重复注册 controller", zap.String("name", name))
}
s.handlerMap[strings.ToLower(name)] = ctlType
checkController(ctlType)
}
//从url解析出controller 和action 的名称
//controller name : lowcase ; 小写
//action name: with upercase first letter. 首字母大写,其余不变.
func (s *GrestServer) parseControllerAction(path string) (controllerName string, actionName string) {
//获取controller和action
list := strings.Split(path, "/")
pathList := make([]string, 0)
for _, i := range list {
tmp := strings.TrimSpace(i)
if tmp != "" {
pathList = append(pathList, tmp)
}
}
//如果未指定,使用默认的Home.Index
controllerName = "home"
if len(pathList) >= 1 {
controllerName = strings.ToLower(pathList[0])
}
//大小写敏感 case sencitive
actionName = "Index"
if len(pathList) >= 2 {
actionName = strings.ToLower(pathList[1])
c := actionName[0]
if c >= 'a' && c <= 'z' {
c = c - 32
}
actionName =
fmt.Sprintf("%c%s", c, actionName[1:])
}
return controllerName, actionName
}
func parseParam(r *http.Request, vals map[string]string) {
if err := r.ParseForm(); err != nil {
log.Logger().Error("grest parseParam err: ", zap.Error(err))
}
//log.Logger().Info(r.PostForm)
for k, v := range r.URL.Query() {
vals[strings.ToLower(k)] = v[0]
log.Logger().Debug("grest parseParam query: ", zap.String("k",k),zap.Any("v",v))
}
for k, v := range r.PostForm {
vals[strings.ToLower(k)] = v[0]
log.Logger().Debug("grest parseParam query: ", zap.String("k",k),zap.Any("v",v))
}
/*
ct := r.Header.Get("Content-Type")
// RFC 2616, section 7.2.1 - empty type
// SHOULD be treated as application/octet-stream
if ct == "" {
ct = "application/octet-stream"
}
ct, _, err = mime.ParseMediaType(ct)
switch {
case ct == "application/json":
d, err := ioutil.ReadAll(r.Body)if err != nil {
log.Logger().Info("grest Body ReadAll err: ", err)
} else {
//如果
vals["json"] = string(d)
}
}*/
}
//stringToReflectField 把表单\query的数据str转换成对应field类型的值,并赋值给field
func (s *GrestServer) stringToReflectField(field reflect.Value, str string) {
if field.CanSet() {
fieldKind := field.Type().Kind()
switch fieldKind {
case reflect.String:
field.Set(reflect.ValueOf(str))
case reflect.Int:
num, err := strconv.ParseInt(str, 10, 32)
if err == nil {
field.Set(reflect.ValueOf(int(num)))
}
case reflect.Int8:
num, err := strconv.ParseInt(str, 10, 8)
if err == nil {
field.Set(reflect.ValueOf(int8(num)))
}
case reflect.Int16:
num, err := strconv.ParseInt(str, 10, 16)
if err == nil {
field.Set(reflect.ValueOf(int16(num)))
}
case reflect.Int32:
num, err := strconv.ParseInt(str, 10, 32)
if err == nil {
field.Set(reflect.ValueOf(int32(num)))
}
case reflect.Int64:
num, err := strconv.ParseInt(str, 10, 64)
if err == nil {
field.Set(reflect.ValueOf(num))
}
case reflect.Uint:
num, err := strconv.ParseUint(str, 10, 64)
if err == nil {
field.Set(reflect.ValueOf(uint(num)))
}
case reflect.Uint8:
num, err := strconv.ParseUint(str, 10, 8)
if err == nil {
field.Set(reflect.ValueOf(uint8(num)))
}
case reflect.Uint16:
num, err := strconv.ParseUint(str, 10, 16)
if err == nil {
field.Set(reflect.ValueOf(uint16(num)))
}
case reflect.Uint32:
num, err := strconv.ParseUint(str, 10, 32)
if err == nil {
field.Set(reflect.ValueOf(uint32(num)))
}
case reflect.Uint64:
num, err := strconv.ParseUint(str, 10, 64)
if err == nil {
field.Set(reflect.ValueOf(uint64(num)))
}
case reflect.Float32:
num, err := strconv.ParseFloat(str, 32)
if err == nil {
field.Set(reflect.ValueOf(float32(num)))
}
case reflect.Float64:
num, err := strconv.ParseFloat(str, 64)
if err == nil {
field.Set(reflect.ValueOf(num))
}
case reflect.Bool:
b, err := strconv.ParseBool(str)
if err == nil {
field.Set(reflect.ValueOf(b))
}
default:
log.Logger().Warn("WARNING: Action parameter : Unsupport field type:",
zap.String("fieldKind", fieldKind.String()))
}
} else {
log.Logger().Warn("WARNING: Action parameter field name must be start with Upper leter")
}
}
//map HTTP POST/QUERY data to func parameter object.
//把http请求参数映射到 action 对应函数的参数, 返回同参数类型的object.
//如果 action 没有参数, 返回 invalid 的reflect.Value
func (s *GrestServer) formToActionParameter(
theAction reflect.Value, vals map[string]string) reflect.Value {
var arg reflect.Value
//if action has a struct parameter
//生成 action 的参数列表
funcType := theAction.Type()
if funcType.NumIn() == 1 {
argType := funcType.In(0)
if argType.Kind() == reflect.Struct {
//new a struct of the parameter.
arg = reflect.New(argType).Elem()
for i := 0; i < argType.NumField(); i++ {
field := arg.Field(i)
fieldName := strings.ToLower(argType.Field(i).Name)
s.stringToReflectField(field, vals[fieldName])
}
}
}
return arg
}
//call the action of controller.
//调用 action 函数
func (s *GrestServer) callAction(theControllerReflect reflect.Value,
actionName string, theAction reflect.Value,
vals map[string]string) (ret mvc.IActionResult) {
defer func() {
err := recover()
if err != nil {
ret = mvc.HttpInternalError(err)
}
}()
//执行 ActionExecuting 过滤器
aec := mvc.NewActionExecutingContext(actionName,
vals)
executeFilterExecuting(theControllerReflect, aec)
//过滤器是否返回了结果. 如果是, 则停止执行action
if aec.Result != nil {
return aec.Result
} else { //继续执行action
arg := s.formToActionParameter(theAction, vals)
//如果action有参数,才传入参数.
var args []reflect.Value
if arg.Kind() != reflect.Invalid {
args = []reflect.Value{arg}
}
//执行 action
rets := theAction.Call(args)
if len(rets) != 1 {
log.Logger().Error("Controller 返回值数目错误", zap.Int("rets", len(rets)))
} else {
ret = rets[0].Interface().(mvc.IActionResult)
}
return ret
}
}
//call the ws action of controller.
//调用 ws 的 action 函数
func (s *GrestServer) callActionWS(theControllerReflect reflect.Value,
actionName string, theAction reflect.Value,
ws *websocket.Conn) {
defer func() {
err := recover()
if err != nil {
//ret = mvc.HttpInternalError(err)
ws.Write([]byte(err.(error).Error()))
ws.Close()
}
}()
args := make([]reflect.Value, 1)
args[0] = reflect.ValueOf(ws)
//执行 action
theAction.Call(args)
}
//http 请求入口, 根据类型派发到ws和http.
func (s *GrestServer) ServeHTTPDispatch(w http.ResponseWriter, r *http.Request) {
//http.Handle("/ws", websocket.Handler(s.ServeHTTPWS))
if len(r.Header.Get("Sec-WebSocket-Version")) > 0 {
ws := websocket.Handler(s.serveHTTPWS)
ws.ServeHTTP(w, r)
return
} else {
s.serveHTTP(w, r)
}
}
func (s *GrestServer) serveHTTP(w http.ResponseWriter, r *http.Request) {
//获取controller和action
controllerName, actionName := s.parseControllerAction(r.URL.Path)
log.Logger().Debug("controllerName=", zap.String("controllerName", controllerName))
log.Logger().Debug("actionName=", zap.String("actionName", actionName))
vals := make(map[string]string)
parseParam(r, vals)
log.Logger().Debug(" = request data:",
zap.Any("URL.Query", r.URL.Query() ) ,
zap.Any("PostForm",r.PostForm) ,
zap.Int("vals.len", len(vals)),
zap.Any("vals", vals))
var ar mvc.IActionResult
var theController mvc.IController //interface{}
//log.Logger().Debug(s.handlerMap)
//获取 controllerName 对应的 controller
ctype := s.handlerMap[controllerName]
if ctype != nil {
// new a controller
theControllerReflect := reflect.New(ctype)
theController = theControllerReflect.Interface().(mvc.IController)
log.Logger().Debug("call controller.Initialize")
initFunc := theControllerReflect.MethodByName("Initialize")
initFunc.Call([]reflect.Value{reflect.ValueOf(w), reflect.ValueOf(r)})
//获取 actionName 对应的 函数.
//get the func corresponding to the action name.
theAction := findFuncOfActionInController(theControllerReflect, actionName)
log.Logger().Debug("find controller." + actionName)
log.Logger().Debug("executing controller." + actionName)
if theAction.Kind() != reflect.Invalid {
//call the action
ar = s.callAction(theControllerReflect, actionName, theAction, vals)
} else {
// action 找不到, 那么返回 template 目录下对应的html 文件
// If action not found , so render the html file in template dir.
c := mvc.NewController()
ar = c.View(controllerName, actionName)
}
log.Logger().Debug("executed controller." + actionName)
} else {
//controller 不存在, 那么返回 template 目录下对应的html 文件
// If action not found , so render the html file in template dir.
log.Logger().Debug("返回 template 目录下对应的html 文件", zap.String("controllerName", controllerName),
zap.String("actionName", actionName))
c := mvc.NewController()
c.Initialize(w, r)
theController = c
ar = c.View(controllerName, actionName)
}
//render the actionresult.
//controllerContext := mvc.NewControllerContext(theController, r, w)
ar.ExecuteResult(theController)
log.Logger().Debug("ExecuteResult " + actionName)
}
// websocket handle, and dispather.
func (s *GrestServer) serveHTTPWS(ws *websocket.Conn) {
//io.Copy(ws, ws)
log.Logger().Debug("ws 已连接;", zap.Any("ws", ws))
//获取controller和action
controllerName, actionName := s.parseControllerAction(ws.Request().URL.Path)
log.Logger().Debug("controllerName=", zap.String("controllerName", controllerName))
log.Logger().Debug("actionName=", zap.String("actionName", actionName))
//获取 controllerName 对应的 controller
ctype := s.handlerMap[controllerName]
if ctype != nil {
// new a controller
theControllerReflect := reflect.New(ctype)
initFunc := theControllerReflect.MethodByName("InitializeWS")
initFunc.Call([]reflect.Value{reflect.ValueOf(ws.Request())})
//获取 actionName 对应的 函数.
//get the func corresponding to the action name.
theAction := findFuncOfActionInController(theControllerReflect, actionName)
if theAction.Kind() != reflect.Invalid {
//call the action
s.callActionWS(theControllerReflect, actionName, theAction, ws)
} else {
//controller 不存在, 那么返回 404
ws.WriteClose(404)
}
} else {
//controller 不存在, 那么返回 404
ws.Write([]byte("Controller not found."))
ws.WriteClose(404)
}
}