Web Server增加启动时的路由展示特性,开发中

This commit is contained in:
john
2018-10-17 10:09:42 +08:00
parent 5997803f8d
commit 946e3a9e0d
7 changed files with 137 additions and 48 deletions

View File

@ -27,6 +27,7 @@ import (
"gitee.com/johng/gf/g/os/gtime"
"time"
"gitee.com/johng/gf/g/os/gfile"
"fmt"
)
const (
@ -52,26 +53,26 @@ const (
// ghttp.Server结构体
type Server struct {
// 基本属性变量
name string // 服务名称,方便识别
paths *gspath.SPath // 静态文件检索对象(类似nginx tryfile功能)
config ServerConfig // 配置对象
servers []*gracefulServer // 底层http.Server列表
methodsMap map[string]struct{} // 所有支持的HTTP Method(初始化时自动填充)
servedCount *gtype.Int // 已经服务的请求数(4-8字节不考虑溢出情况)同时作为请求ID
closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象)
name string // 服务名称,方便识别
paths *gspath.SPath // 静态文件检索对象(类似nginx tryfile功能)
config ServerConfig // 配置对象
servers []*gracefulServer // 底层http.Server列表
methodsMap map[string]struct{} // 所有支持的HTTP Method(初始化时自动填充)
servedCount *gtype.Int // 已经服务的请求数(4-8字节不考虑溢出情况)同时作为请求ID
closeQueue *gqueue.Queue // 请求结束的关闭队列(存放的是需要异步关闭处理的*Request对象)
// 服务注册相关
serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配)
hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配)
serveCache *gcache.Cache // 服务注册路由内存缓存
hooksCache *gcache.Cache // 事件回调路由内存缓存
routesMap map[string]string // 已经注册的路由及对应的注册方法文件地址(用以路由重复注册判断)
serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配)
hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配)
serveCache *gcache.Cache // 服务注册路由内存缓存
hooksCache *gcache.Cache // 事件回调路由内存缓存
routesMap map[string]registeredRouteItem // 已经注册的路由及对应的注册方法文件地址(用以路由重复注册判断)
// 自定义状态码回调
hsmu sync.RWMutex // status handler互斥锁
statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法)
hsmu sync.RWMutex // status handler互斥锁
statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法)
// SESSION
sessions *gcache.Cache // Session内存缓存
sessions *gcache.Cache // Session内存缓存
// Logger
logger *glog.Logger // 日志管理对象
logger *glog.Logger // 日志管理对象
}
// 路由对象
@ -89,7 +90,8 @@ type handlerMap map[string]*handlerItem
// http回调函数注册信息
type handlerItem struct {
rtype int // 注册方式
name string // 注册的方法名称信息
rtype int // 注册方式(执行对象/回调函数/控制器)
ctype reflect.Type // 控制器类型(反射类型)
fname string // 回调方法名称
faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一)
@ -104,6 +106,12 @@ type handlerParsedItem struct {
values map[string][]string // 特定URL.Path的Router解析参数
}
// 已注册的路由项
type registeredRouteItem struct {
file string // 文件路径及行数地址
handler *handlerItem // 路由注册项
}
// HTTP注册函数
type HandlerFunc func(r *Request)
@ -169,7 +177,7 @@ func GetServer(name...interface{}) (*Server) {
hooksTree : make(map[string]interface{}),
serveCache : gcache.New(),
hooksCache : gcache.New(),
routesMap : make(map[string]string),
routesMap : make(map[string]registeredRouteItem),
sessions : gcache.New(),
servedCount : gtype.NewInt(),
closeQueue : gqueue.New(),
@ -251,9 +259,28 @@ func (s *Server) Start() error {
// 开启异步关闭队列处理循环
s.startCloseQueueLoop()
// 打印展示路由表
s.DumpRoutesMap()
return nil
}
// 打印展示路由表
func (s *Server) DumpRoutesMap() {
for _, v := range s.routesMap {
fmt.Println(v.handler.name)
//switch v.handler.rtype {
// case gROUTE_REGISTER_HANDLER:
// fmt.Println(v.handler.name)
// case gROUTE_REGISTER_OBJECT:
// //fmt.Println(v.handler.name)
// case gROUTE_REGISTER_CONTROLLER:
// fmt.Println(v.handler.name)
//
//}
}
}
// 阻塞执行监听
func (s *Server) Run() error {
if err := s.Start(); err != nil {

View File

@ -78,7 +78,10 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin
} else {
defer func() {
if resultErr == nil {
s.routesMap[regkey] = caller
s.routesMap[regkey] = registeredRouteItem{
file : caller,
handler : handler,
}
}
}()
}

View File

@ -177,8 +177,8 @@ func (s *Server) searchHookHandler(method, path, domain, hook string) []*handler
return nil
}
// 生成hook key
// 生成hook key如果是hook key那么使用'%'符号分隔
func (s *Server) hookHandlerKey(hook, method, path, domain string) string {
return hook + "@" + s.serveHandlerKey(method, path, domain)
return hook + "%" + s.serveHandlerKey(method, path, domain)
}

View File

@ -11,6 +11,9 @@ import (
"errors"
"strings"
"reflect"
"fmt"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/util/gstr"
)
// 绑定控制器控制器需要实现gmvc.Controller接口
@ -25,10 +28,12 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e
}
}
// 遍历控制器获取方法列表并构造成uri
m := make(handlerMap)
v := reflect.ValueOf(c)
t := v.Type()
sname := t.Elem().Name()
m := make(handlerMap)
v := reflect.ValueOf(c)
t := v.Type()
sname := t.Elem().Name()
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
if methodMap != nil && !methodMap[mname] {
@ -37,8 +42,13 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e
if mname == "Init" || mname == "Shut" || mname == "Exit" {
continue
}
ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if ctlName[0] == '*' {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
m[key] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
rtype : gROUTE_REGISTER_CONTROLLER,
ctype : v.Elem().Type(),
fname : mname,
@ -54,6 +64,7 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e
}
}
m[p] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
rtype : gROUTE_REGISTER_CONTROLLER,
ctype : v.Elem().Type(),
fname : mname,
@ -68,15 +79,21 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e
func (s *Server)BindControllerMethod(pattern string, c Controller, method string) error {
m := make(handlerMap)
v := reflect.ValueOf(c)
e := v.Type().Elem()
t := v.Elem().Type()
sname := e.Name()
t := v.Type()
sname := t.Elem().Name()
mname := strings.TrimSpace(method)
if !v.MethodByName(mname).IsValid() {
return errors.New("invalid method name:" + mname)
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
m[key] = &handlerItem {
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if ctlName[0] == '*' {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
m[key] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
rtype : gROUTE_REGISTER_CONTROLLER,
ctype : t,
fname : mname,
@ -91,21 +108,28 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string
// 这种方式绑定的控制器每一次请求都会初始化一个新的控制器对象进行处理,对应不同的请求会话
func (s *Server)BindControllerRest(pattern string, c Controller) error {
// 遍历控制器获取方法列表并构造成uri
m := make(handlerMap)
v := reflect.ValueOf(c)
t := v.Type()
m := make(handlerMap)
v := reflect.ValueOf(c)
t := v.Type()
pkgPath := t.Elem().PkgPath()
// 如果存在与HttpMethod对应名字的方法那么绑定这些方法
for i := 0; i < v.NumMethod(); i++ {
name := t.Method(i).Name
method := strings.ToUpper(name)
mname := t.Method(i).Name
method := strings.ToUpper(mname)
if _, ok := s.methodsMap[method]; !ok {
continue
}
key := name + ":" + pattern
pkgName := gfile.Basename(pkgPath)
ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if ctlName[0] == '*' {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
key := mname + ":" + pattern
m[key] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
rtype : gROUTE_REGISTER_CONTROLLER,
ctype : v.Elem().Type(),
fname : name,
fname : mname,
faddr : nil,
}
}

View File

@ -12,11 +12,14 @@ import (
"strings"
"gitee.com/johng/gf/g/util/gstr"
"bytes"
"runtime"
"reflect"
)
// 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑
func (s *Server) BindHandler(pattern string, handler HandlerFunc) error {
return s.bindHandlerItem(pattern, &handlerItem {
name : runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
rtype : gROUTE_REGISTER_HANDLER,
ctype : nil,
fname : "",

View File

@ -11,6 +11,9 @@ import (
"errors"
"strings"
"reflect"
"fmt"
"gitee.com/johng/gf/g/util/gstr"
"gitee.com/johng/gf/g/os/gfile"
)
// 绑定对象到URI请求处理中会自动识别方法名称并附加到对应的URI地址后面
@ -23,9 +26,9 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er
methodMap[strings.TrimSpace(v)] = true
}
}
m := make(handlerMap)
v := reflect.ValueOf(obj)
t := v.Type()
m := make(handlerMap)
v := reflect.ValueOf(obj)
t := v.Type()
sname := t.Elem().Name()
finit := (func(*Request))(nil)
fshut := (func(*Request))(nil)
@ -35,6 +38,8 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er
if v.MethodByName("Shut").IsValid() {
fshut = v.MethodByName("Shut").Interface().(func(*Request))
}
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
if methodMap != nil && !methodMap[mname] {
@ -43,8 +48,13 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er
if mname == "Init" || mname == "Shut" {
continue
}
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if objName[0] == '*' {
objName = fmt.Sprintf(`(%s)`, objName)
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
m[key] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
rtype : gROUTE_REGISTER_OBJECT,
ctype : nil,
fname : "",
@ -62,6 +72,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er
}
}
m[p] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
rtype : gROUTE_REGISTER_OBJECT,
ctype : nil,
fname : "",
@ -94,8 +105,15 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string)
if v.MethodByName("Shut").IsValid() {
fshut = v.MethodByName("Shut").Interface().(func(*Request))
}
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if objName[0] == '*' {
objName = fmt.Sprintf(`(%s)`, objName)
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
m[key] = &handlerItem{
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
rtype : gROUTE_REGISTER_OBJECT,
ctype : nil,
fname : "",
@ -121,14 +139,21 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) error {
if v.MethodByName("Shut").IsValid() {
fshut = v.MethodByName("Shut").Interface().(func(*Request))
}
pkgPath := t.Elem().PkgPath()
for i := 0; i < v.NumMethod(); i++ {
name := t.Method(i).Name
method := strings.ToUpper(name)
mname := t.Method(i).Name
method := strings.ToUpper(mname)
if _, ok := s.methodsMap[method]; !ok {
continue
}
key := name + ":" + pattern
pkgName := gfile.Basename(pkgPath)
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
if objName[0] == '*' {
objName = fmt.Sprintf(`(%s)`, objName)
}
key := mname + ":" + pattern
m[key] = &handlerItem {
name : fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
rtype : gROUTE_REGISTER_OBJECT,
ctype : nil,
fname : "",

View File

@ -2,11 +2,18 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/encoding/gurl"
"gitee.com/johng/gf/g/encoding/ghtml"
"reflect"
"runtime"
)
func main() {
fmt.Println(gurl.Decode("<"))
fmt.Println(ghtml.SpecialChars("<"))
type T struct {
}
func (t *T) Test() {
}
func main() {
t := new(T)
fmt.Println(runtime.FuncForPC(reflect.ValueOf(t.Test).Pointer()).Name())
}