From d7381399aa1d626c228d413808c9a2f6c841aff7 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 20 Dec 2018 21:04:43 +0800 Subject: [PATCH] fix issue of grand.intn in x86 arch; add router group feature for WebServer --- .travis.yml | 1 - g/frame/gins/gins.go | 20 +-- g/net/ghttp/ghttp_server.go | 6 +- g/net/ghttp/ghttp_server_router.go | 26 +-- g/net/ghttp/ghttp_server_router_group.go | 171 ++++++++++++++++---- g/util/gconv/gconv_slice.go | 143 ++++++++-------- g/util/grand/grand_intn.go | 5 +- geg/database/orm/mysql/gdb_json_xml.go | 15 +- geg/net/ghttp/server/router/group/group1.go | 69 ++++++++ geg/other/test.go | 10 +- geg/other/test2.go | 26 ++- geg/util/grand/grand.go | 2 +- 12 files changed, 332 insertions(+), 162 deletions(-) create mode 100644 geg/net/ghttp/server/router/group/group1.go diff --git a/.travis.yml b/.travis.yml index 1b522a71f..db397a14b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,6 @@ install: - cd $GITEE_GF script: -# - cd g && go test -v ./... - cd g && go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic after_success: diff --git a/g/frame/gins/gins.go b/g/frame/gins/gins.go index 37b9f36a6..c9371a6e7 100644 --- a/g/frame/gins/gins.go +++ b/g/frame/gins/gins.go @@ -9,18 +9,18 @@ package gins import ( + "fmt" + "gitee.com/johng/gf/g/container/gmap" + "gitee.com/johng/gf/g/database/gdb" + "gitee.com/johng/gf/g/database/gredis" "gitee.com/johng/gf/g/os/gcfg" "gitee.com/johng/gf/g/os/gcmd" "gitee.com/johng/gf/g/os/genv" + "gitee.com/johng/gf/g/os/gfile" + "gitee.com/johng/gf/g/os/gfsnotify" "gitee.com/johng/gf/g/os/glog" "gitee.com/johng/gf/g/os/gview" - "gitee.com/johng/gf/g/os/gfile" - "gitee.com/johng/gf/g/container/gmap" "gitee.com/johng/gf/g/util/gconv" - "gitee.com/johng/gf/g/database/gdb" - "gitee.com/johng/gf/g/os/gfsnotify" - "fmt" - "gitee.com/johng/gf/g/database/gredis" "gitee.com/johng/gf/g/util/gregex" ) @@ -180,11 +180,11 @@ func Database(name...string) gdb.DB { } gdb.AddConfigGroup(group, cg) } + // 使用gfsnotify进行文件监控,当配置文件有任何变化时,清空数据库配置缓存 + gfsnotify.Add(config.GetFilePath(), func(event *gfsnotify.Event) { + instances.Remove(key) + }) } - // 使用gfsnotify进行文件监控,当配置文件有任何变化时,清空数据库配置缓存 - gfsnotify.Add(config.GetFilePath(), func(event *gfsnotify.Event) { - instances.Remove(key) - }) if db, err := gdb.New(name...); err == nil { return db } else { diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index f31cc5a7e..e09322424 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -91,13 +91,13 @@ type ( } // pattern与回调函数的绑定map - handlerMap map[string]*handlerItem + handlerMap = map[string]*handlerItem // HTTP注册函数 - HandlerFunc func(r *Request) + HandlerFunc = func(r *Request) // 文件描述符map - listenerFdMap map[string]string + listenerFdMap = map[string]string ) const ( diff --git a/g/net/ghttp/ghttp_server_router.go b/g/net/ghttp/ghttp_server_router.go index d2f35e82b..5e3cc5e9b 100644 --- a/g/net/ghttp/ghttp_server_router.go +++ b/g/net/ghttp/ghttp_server_router.go @@ -20,24 +20,28 @@ import ( // 解析pattern -func (s *Server)parsePattern(pattern string) (domain, method, uri string, err error) { - uri = strings.TrimSpace(pattern) +func (s *Server)parsePattern(pattern string) (domain, method, path string, err error) { + path = strings.TrimSpace(pattern) domain = gDEFAULT_DOMAIN method = gDEFAULT_METHOD - if array, err := gregex.MatchString(`(.+):(.+)`, pattern); len(array) > 1 && err == nil { - method = strings.TrimSpace(array[1]) - uri = strings.TrimSpace(array[2]) + if array, err := gregex.MatchString(`([a-zA-Z]+):(.+)`, pattern); len(array) > 1 && err == nil { + path = strings.TrimSpace(array[2]) + if v := strings.TrimSpace(array[1]); v != "" { + method = v + } } - if array, err := gregex.MatchString(`(.+)@(.+)`, uri); len(array) > 1 && err == nil { - uri = strings.TrimSpace(array[1]) - domain = strings.TrimSpace(array[2]) + if array, err := gregex.MatchString(`(.+)@([\w\.\-]+)`, path); len(array) > 1 && err == nil { + path = strings.TrimSpace(array[1]) + if v := strings.TrimSpace(array[2]); v != "" { + domain = v + } } - if uri == "" { + if path == "" { err = errors.New("invalid pattern") } // 去掉末尾的"/"符号,与路由匹配时处理一致 - if uri != "/" { - uri = strings.TrimRight(uri, "/") + if path != "/" { + path = strings.TrimRight(path, "/") } return } diff --git a/g/net/ghttp/ghttp_server_router_group.go b/g/net/ghttp/ghttp_server_router_group.go index 85b5cdd25..37cffbccb 100644 --- a/g/net/ghttp/ghttp_server_router_group.go +++ b/g/net/ghttp/ghttp_server_router_group.go @@ -7,12 +7,22 @@ package ghttp +import ( + "gitee.com/johng/gf/g/os/glog" + "gitee.com/johng/gf/g/util/gconv" + "strings" +) + // 分组路由对象 type RouterGroup struct { - server *Server // Web Server + server *Server // Server + domain *Domain // Domain prefix string // URI前缀 } +// 分组路由批量绑定项 +type GroupItem = []interface{} + // 获取分组路由对象 func (s *Server) Group(prefix...string) *RouterGroup { if len(prefix) > 0 { @@ -24,59 +34,160 @@ func (s *Server) Group(prefix...string) *RouterGroup { return &RouterGroup{} } -// REST路由注册 -func (g *RouterGroup) REST(pattern string, object interface{}) { +// 获取分组路由对象 +func (d *Domain) Group(prefix...string) *RouterGroup { + if len(prefix) > 0 { + return &RouterGroup{ + domain : d, + prefix : prefix[0], + } + } + return &RouterGroup{} +} +// 执行分组路由批量绑定 +func (g *RouterGroup) Bind(group string, items []GroupItem) { + for _, item := range items { + if len(item) < 3 { + glog.Fatalfln("invalid router item: %s", item) + } + if strings.EqualFold(gconv.String(item[0]), "REST") { + g.bind("REST", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2]) + } else { + if len(item) > 3 { + g.bind("HANDLER", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2], item[3]) + } else { + g.bind("HANDLER", gconv.String(item[0]) + ":" + gconv.String(item[1]), item[2]) + } + } + } } // 绑定所有的HTTP Method请求方式 -func (g *RouterGroup) ALL(pattern string, params...interface{}) { - +func (g *RouterGroup) ALL(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", gDEFAULT_METHOD + ":" + pattern, object, params...) } -func (g *RouterGroup) GET(pattern string, params...interface{}) { - +func (g *RouterGroup) GET(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "GET:" + pattern, object, params...) } -func (g *RouterGroup) PUT(pattern string, params...interface{}) { - +func (g *RouterGroup) PUT(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "PUT:" + pattern, object, params...) } -func (g *RouterGroup) POST(pattern string, params...interface{}) { - +func (g *RouterGroup) POST(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "POST:" + pattern, object, params...) } -func (g *RouterGroup) DELETE(pattern string, params...interface{}) { - +func (g *RouterGroup) DELETE(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "DELETE:" + pattern, object, params...) } -func (g *RouterGroup) PATCH(pattern string, params...interface{}) { - +func (g *RouterGroup) PATCH(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "PATCH:" + pattern, object, params...) } -func (g *RouterGroup) HEAD(pattern string, params...interface{}) { - +func (g *RouterGroup) HEAD(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "HEAD:" + pattern, object, params...) } -func (g *RouterGroup) CONNECT(pattern string, params...interface{}) { - +func (g *RouterGroup) CONNECT(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "CONNECT:" + pattern, object, params...) } -func (g *RouterGroup) OPTIONS(pattern string, params...interface{}) { - +func (g *RouterGroup) OPTIONS(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "OPTIONS:" + pattern, object, params...) } -func (g *RouterGroup) TRTACE(pattern string, params...interface{}) { +func (g *RouterGroup) TRACE(pattern string, object interface{}, params...interface{}) { + g.bind("HANDLER", "TRACE:" + pattern, object, params...) +} +// REST路由注册 +func (g *RouterGroup) REST(pattern string, object interface{}) { + g.bind("REST", pattern, object) } // 执行路由绑定 -func (g *RouterGroup) bind(method string, pattern string, params...interface{}) { - +func (g *RouterGroup) bind(bindType string, pattern string, object interface{}, params...interface{}) { + // 注册路由处理 + if len(g.prefix) > 0 { + domain, method, path, err := g.server.parsePattern(pattern) + if err != nil { + glog.Fatalfln("invalid pattern: %s", pattern) + } + if bindType == "HANDLER" { + pattern = g.server.serveHandlerKey(method, g.prefix + "/" + strings.TrimLeft(path, "/"), domain) + } else { + pattern = g.prefix + "/" + strings.TrimLeft(path, "/") + } + } + methods := gconv.Strings(params) + // 判断是否事件回调注册 + if _, ok := object.(HandlerFunc); ok && len(methods) > 0 { + bindType = "HOOK" + } + switch bindType { + case "HANDLER": + if h, ok := object.(HandlerFunc); ok { + if g.server != nil { + g.server.BindHandler(pattern, h) + } else { + g.domain.BindHandler(pattern, h) + } + } else if c, ok := object.(Controller); ok { + if len(methods) > 0 { + if g.server != nil { + g.server.BindControllerMethod(pattern, c, methods[0]) + } else { + g.domain.BindControllerMethod(pattern, c, methods[0]) + } + } else { + if g.server != nil { + g.server.BindController(pattern, c) + } else { + g.domain.BindController(pattern, c) + } + } + } else { + if len(methods) > 0 { + if g.server != nil { + g.server.BindObjectMethod(pattern, object, methods[0]) + } else { + g.domain.BindObjectMethod(pattern, object, methods[0]) + } + } else { + if g.server != nil { + g.server.BindObject(pattern, object) + } else { + g.domain.BindObject(pattern, object) + } + } + } + case "REST": + if c, ok := object.(Controller); ok { + if g.server != nil { + g.server.BindControllerRest(pattern, c) + } else { + g.domain.BindControllerRest(pattern, c) + } + } else { + if g.server != nil { + g.server.BindObjectRest(pattern, object) + } else { + g.domain.BindObjectRest(pattern, object) + } + } + case "HOOK": + if h, ok := object.(HandlerFunc); ok { + if g.server != nil { + g.server.BindHookHandler(pattern, methods[0], h) + } else { + g.domain.BindHookHandler(pattern, methods[0], h) + } + } else { + glog.Fatalfln("invalid hook handler for pattern:%s", pattern) + } + } } - -// 判断给定对象是否控制器对象: -// 控制器必须包含以下公开的属性对象:Request/Response/Server/Cookie/Session/View. -func (g *RouterGroup) isController(object interface{}) { - -} \ No newline at end of file diff --git a/g/util/gconv/gconv_slice.go b/g/util/gconv/gconv_slice.go index 2acb19884..30919872e 100644 --- a/g/util/gconv/gconv_slice.go +++ b/g/util/gconv/gconv_slice.go @@ -7,7 +7,6 @@ package gconv import ( - "fmt" "reflect" ) @@ -77,12 +76,11 @@ func Ints(i interface{}) []int { for _, v := range i.([]interface{}) { array = append(array, Int(v)) } + default: + return []int{Int(i)} } - if len(array) > 0 { - return array - } + return array } - return []int{Int(i)} } // 任意类型转换为[]string类型 @@ -95,71 +93,70 @@ func Strings(i interface{}) []string { } else { array := make([]string, 0) switch i.(type) { - case []int: - for _, v := range i.([]int) { - array = append(array, String(v)) - } - case []int8: - for _, v := range i.([]int8) { - array = append(array, String(v)) - } - case []int16: - for _, v := range i.([]int16) { - array = append(array, String(v)) - } - case []int32: - for _, v := range i.([]int32) { - array = append(array, String(v)) - } - case []int64: - for _, v := range i.([]int64) { - array = append(array, String(v)) - } - case []uint: - for _, v := range i.([]uint) { - array = append(array, String(v)) - } - case []uint8: - for _, v := range i.([]uint8) { - array = append(array, String(v)) - } - case []uint16: - for _, v := range i.([]uint16) { - array = append(array, String(v)) - } - case []uint32: - for _, v := range i.([]uint32) { - array = append(array, String(v)) - } - case []uint64: - for _, v := range i.([]uint64) { - array = append(array, String(v)) - } - case []bool: - for _, v := range i.([]bool) { - array = append(array, String(v)) - } - case []float32: - for _, v := range i.([]float32) { - array = append(array, String(v)) - } - case []float64: - for _, v := range i.([]float64) { - array = append(array, String(v)) - } - case []interface{}: - for _, v := range i.([]interface{}) { - array = append(array, String(v)) - } - } - if len(array) > 0 { - return array + case []int: + for _, v := range i.([]int) { + array = append(array, String(v)) + } + case []int8: + for _, v := range i.([]int8) { + array = append(array, String(v)) + } + case []int16: + for _, v := range i.([]int16) { + array = append(array, String(v)) + } + case []int32: + for _, v := range i.([]int32) { + array = append(array, String(v)) + } + case []int64: + for _, v := range i.([]int64) { + array = append(array, String(v)) + } + case []uint: + for _, v := range i.([]uint) { + array = append(array, String(v)) + } + case []uint8: + for _, v := range i.([]uint8) { + array = append(array, String(v)) + } + case []uint16: + for _, v := range i.([]uint16) { + array = append(array, String(v)) + } + case []uint32: + for _, v := range i.([]uint32) { + array = append(array, String(v)) + } + case []uint64: + for _, v := range i.([]uint64) { + array = append(array, String(v)) + } + case []bool: + for _, v := range i.([]bool) { + array = append(array, String(v)) + } + case []float32: + for _, v := range i.([]float32) { + array = append(array, String(v)) + } + case []float64: + for _, v := range i.([]float64) { + array = append(array, String(v)) + } + case []interface{}: + for _, v := range i.([]interface{}) { + array = append(array, String(v)) + } + default: + return []string{String(i)} } + return array } - return []string{fmt.Sprintf("%v", i)} } -// 任意类型转换为[]float64类型 +// 将类型转换为[]float64类型 func Floats(i interface{}) []float64 { if i == nil { return nil @@ -225,12 +222,11 @@ func Floats(i interface{}) []float64 { for _, v := range i.([]interface{}) { array = append(array, Float64(v)) } + default: + return []float64{Float64(i)} } - if len(array) > 0 { - return array - } + return array } - return []float64{Float64(i)} } // 任意类型转换为[]interface{}类型 @@ -318,11 +314,10 @@ func Interfaces(i interface{}) []interface{} { for i := 0; i < rv.NumField(); i++ { array = append(array, rv.Field(i).Interface()) } + default: + return []interface{}{i} } } - if len(array) > 0 { - return array - } + return array } - return []interface{}{i} } \ No newline at end of file diff --git a/g/util/grand/grand_intn.go b/g/util/grand/grand_intn.go index 9e5e51dd2..61a154594 100644 --- a/g/util/grand/grand_intn.go +++ b/g/util/grand/grand_intn.go @@ -9,7 +9,6 @@ package grand import ( "crypto/rand" "encoding/binary" - "time" ) const ( @@ -34,8 +33,8 @@ func init() { bufferChan <- binary.LittleEndian.Uint64(buffer[i : i + 8]) i ++ } - // 充分利用缓冲区数据,字节倒序生成,随机索引递增 - step = int(time.Now().UnixNano())%n + // 充分利用缓冲区数据,随机索引递增 + step = int(buffer[0])%10 for i := 0; i < n - 8; { bufferChan <- binary.BigEndian.Uint64(buffer[i : i + 8]) i += step diff --git a/geg/database/orm/mysql/gdb_json_xml.go b/geg/database/orm/mysql/gdb_json_xml.go index 74bcf37a3..2cffc9d43 100644 --- a/geg/database/orm/mysql/gdb_json_xml.go +++ b/geg/database/orm/mysql/gdb_json_xml.go @@ -1,6 +1,7 @@ package main import ( + "gitee.com/johng/gf/g" "gitee.com/johng/gf/g/database/gdb" "fmt" "gitee.com/johng/gf/g/encoding/gparser" @@ -11,18 +12,14 @@ func main() { Host : "127.0.0.1", Port : "3306", User : "root", - Pass : "123456", + Pass : "12345678", Name : "test", Type : "mysql", Role : "master", Charset : "utf8", }) - db, err := gdb.New() - if err != nil { - panic(err) - } - - one, err := db.Table("user").Where("uid=?", 1).One() + db := g.DB() + one, err := db.Table("user").Where("id=?", 1).One() if err != nil { panic(err) } @@ -33,7 +30,7 @@ func main() { // 自定义方法方法转换为json/xml jsonContent, _ := gparser.VarToJson(one.ToMap()) - fmt.Println(jsonContent) + fmt.Println(string(jsonContent)) xmlContent, _ := gparser.VarToXml(one.ToMap()) - fmt.Println(xmlContent) + fmt.Println(string(xmlContent)) } \ No newline at end of file diff --git a/geg/net/ghttp/server/router/group/group1.go b/geg/net/ghttp/server/router/group/group1.go new file mode 100644 index 000000000..9fb924873 --- /dev/null +++ b/geg/net/ghttp/server/router/group/group1.go @@ -0,0 +1,69 @@ +package main + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/frame/gmvc" + "gitee.com/johng/gf/g/net/ghttp" +) + +type Object struct {} + +func (o *Object) Show(r *ghttp.Request) { + r.Response.Writeln("Object Show") +} + +func (o *Object) Delete(r *ghttp.Request) { + r.Response.Writeln("Object REST Delete") +} + +type Controller struct { + gmvc.Controller +} + +func (c *Controller) Show() { + c.Response.Writeln("Controller Show") +} + +func (c *Controller) Post() { + c.Response.Writeln("Controller REST Post") +} + +func Handler(r *ghttp.Request) { + r.Response.Writeln("Handler") +} + +func HookHandler(r *ghttp.Request) { + r.Response.Writeln("Hook Handler") +} + +func main() { + s := g.Server() + obj := new(Object) + ctl := new(Controller) + + // 分组路由方法注册 + g := s.Group("/api") + g.ALL ("*", HookHandler, ghttp.HOOK_BEFORE_SERVE) + g.ALL ("/handler", Handler) + g.ALL ("/ctl", ctl) + g.GET ("/ctl/my-show", ctl, "Show") + g.REST("/ctl/rest", ctl) + g.ALL ("/obj", obj) + g.GET ("/obj/my-show", obj, "Show") + g.REST("/obj/rest", obj) + + // 分组路由批量注册 + s.Group("/api").Bind("/api", []ghttp.GroupItem{ + {"ALL", "*", HookHandler, ghttp.HOOK_BEFORE_SERVE}, + {"ALL", "/handler", Handler}, + {"ALL", "/ctl", ctl}, + {"GET", "/ctl/my-show", ctl, "Show"}, + {"REST", "/ctl/rest", ctl}, + {"ALL", "/obj", obj}, + {"GET", "/obj/my-show", obj, "Show"}, + {"REST", "/obj/rest", obj}, + }) + + s.SetPort(8199) + s.Run() +} diff --git a/geg/other/test.go b/geg/other/test.go index 13eb02055..3640d2911 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -7,7 +7,7 @@ type Registry struct { Object interface{} } -func BindGroup(group string, routers []Registry) { +func BindGroup(group string, routers [][]interface{}) { } @@ -21,10 +21,10 @@ func HookFunc() { func main() { user := new(User) - BindGroup("/api", []Registry { - {"ALL", "/api/*", "BeforeServe", HookFunc}, - {"ALL", "/order", "", new(Order)}, - {"REST", "/product", "", new(Product)}, + BindGroup("/api", [][]interface{} { + {"ALL", "/*", HookFunc, "BeforeServe"}, + {"ALL", "/order", new(Order)}, + {"REST", "/product", new(Product)}, {"GET", "/user/register", "Register", user}, {"GET", "/user/reset-pass", "ResetPassword", user}, {"POST", "/user/reset-pass", "ResetPassword", user}, diff --git a/geg/other/test2.go b/geg/other/test2.go index f4eb6bb4e..8dd62e7bb 100644 --- a/geg/other/test2.go +++ b/geg/other/test2.go @@ -2,24 +2,20 @@ package main import ( "fmt" - "gitee.com/johng/gf/g/os/gfile" - "gitee.com/johng/gf/g/os/gfsnotify" + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/database/gdb" "gitee.com/johng/gf/g/os/glog" ) func main() { - path := "/Users/john/Temp" - _, err := gfsnotify.Add(path, func(event *gfsnotify.Event) { - fmt.Println(event) - if event.IsWrite() { - glog.Println("写入文件 : ", event.Path) - fmt.Printf("%s\n", gfile.GetContents(event.Path)) - } + gdb.AddDefaultConfigNode(gdb.ConfigNode{ + Type : "mysql", + Linkinfo : "root:12345678@tcp(127.0.0.1:3306)/test", }) - if err != nil { - glog.Fatal(err) - } else { - select {} - } -} \ No newline at end of file + if r, err := g.Database().GetOne("select now() as time"); err != nil { + glog.Error("Mysql Init Select Now : %v", err) + } else { + fmt.Println(r.ToMap()) + } +} diff --git a/geg/util/grand/grand.go b/geg/util/grand/grand.go index 1adef54c9..5aefd3164 100644 --- a/geg/util/grand/grand.go +++ b/geg/util/grand/grand.go @@ -6,7 +6,7 @@ import ( ) func main() { - for i := 0; i < 10; i++ { + for i := 0; i < 100; i++ { fmt.Println(grand.Rand(0, 99999)) } }