From 85157c8708e6c4c587e89cf7a20403f1d858e104 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 19 Aug 2018 11:25:15 +0800 Subject: [PATCH] =?UTF-8?q?ghttp=E5=AF=B9=E8=B1=A1=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E6=B3=A8=E5=86=8C=E5=A2=9E=E5=8A=A0Init&Shut=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E6=96=B9=E6=B3=95=EF=BC=9Bghttp=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=87=8D=E5=A4=8D=E8=B7=AF=E7=94=B1=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E5=8A=9F=E8=83=BD=EF=BC=9Bgfsnotify=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=BB=98=E8=AE=A4=E9=80=92=E5=BD=92Add/Remove?= =?UTF-8?q?=E7=89=B9=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 1 + g/net/ghttp/ghttp_server.go | 6 + g/net/ghttp/ghttp_server_domain.go | 22 ++-- g/net/ghttp/ghttp_server_handler.go | 11 +- g/net/ghttp/ghttp_server_router.go | 101 ++++++++++++++-- .../ghttp/ghttp_server_service_controller.go | 4 + g/net/ghttp/ghttp_server_service_handler.go | 3 +- g/net/ghttp/ghttp_server_service_object.go | 4 + g/os/gcfg/gcfg.go | 5 +- g/os/gfile/gfile.go | 16 ++- g/os/gfsnotify/gfsnotify.go | 112 +++++++++++++----- g/os/gfsnotify/gfsnotify_event.go | 5 + g/os/glog/glog_logger.go | 4 +- g/os/gview/gview.go | 5 +- geg/net/ghttp/server/duplicate/duplicate1.go | 19 +++ geg/net/ghttp/server/duplicate/duplicate2.go | 33 ++++++ geg/net/ghttp/server/duplicate/duplicate3.go | 25 ++++ geg/os/{file.go => gfile/gfile.go} | 0 geg/os/gfile/gfile_scan.go | 11 ++ geg/os/gfsnotify/fsnotify.go | 2 +- geg/os/gfsnotify/gfsnotify.go | 2 +- 21 files changed, 322 insertions(+), 69 deletions(-) create mode 100644 geg/net/ghttp/server/duplicate/duplicate1.go create mode 100644 geg/net/ghttp/server/duplicate/duplicate2.go create mode 100644 geg/net/ghttp/server/duplicate/duplicate3.go rename geg/os/{file.go => gfile/gfile.go} (100%) create mode 100644 geg/os/gfile/gfile_scan.go diff --git a/TODO b/TODO index 99c6ea359..b7d4d95f8 100644 --- a/TODO +++ b/TODO @@ -18,6 +18,7 @@ orm增加sqlite对Save方法的支持(去掉触发器语句); ghttp.Server的Cookie及Session锁机制优化(去掉map锁机制); ghttp.Server增加Ip访问控制功能(DenyIps&AllowIps); ghttp路由功能增加分组路由特性; +解决glog串日志情况; DONE: diff --git a/g/net/ghttp/ghttp_server.go b/g/net/ghttp/ghttp_server.go index 6746ce752..275ef183b 100644 --- a/g/net/ghttp/ghttp_server.go +++ b/g/net/ghttp/ghttp_server.go @@ -50,6 +50,9 @@ const ( gDEFAULT_SESSION_ID_NAME = "gfsessionid" // 默认存放Cookie中的SessionId名称 gSERVE_CACHE_LRU_SIZE = 100000 // 服务回调函数缓存LRU大小 gHOOKS_CACHE_LRU_SIZE = 100000 // 事件回调函数缓存LRU大小 + gROUTE_REGISTER_HANDLER = 1 + gROUTE_REGISTER_OBJECT = 2 + gROUTE_REGISTER_CONTROLLER = 3 ) // ghttp.Server结构体 @@ -67,6 +70,7 @@ type Server struct { hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配) serveCache *gcache.Cache // 服务注册路由内存缓存 hooksCache *gcache.Cache // 事件回调路由内存缓存 + routesMap map[string]string // 已经注册的路由及对应的注册方法文件地址 // 自定义状态码回调 hsmu sync.RWMutex // status handler互斥锁 statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法) @@ -103,6 +107,7 @@ type handlerMap map[string]*handlerItem // http回调函数注册信息 type handlerItem struct { + rtype int // 注册方式 ctype reflect.Type // 控制器类型(反射类型) fname string // 回调方法名称 faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一) @@ -182,6 +187,7 @@ func GetServer(name...interface{}) (*Server) { hooksTree : make(map[string]interface{}), serveCache : gcache.New(), hooksCache : gcache.New(), + routesMap : make(map[string]string), cookies : gmap.NewIntInterfaceMap(), sessions : gcache.New(), servedCount : gtype.NewInt(), diff --git a/g/net/ghttp/ghttp_server_domain.go b/g/net/ghttp/ghttp_server_domain.go index a9a862e54..117e7b1ae 100644 --- a/g/net/ghttp/ghttp_server_domain.go +++ b/g/net/ghttp/ghttp_server_domain.go @@ -41,11 +41,7 @@ func (s *Server) Domain(domains string) *Domain { // 注意该方法是直接绑定方法的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑 func (d *Domain) BindHandler(pattern string, handler HandlerFunc) error { for domain, _ := range d.m { - if err := d.s.bindHandlerItem(pattern + "@" + domain, &handlerItem{ - ctype : nil, - fname : "", - faddr : handler, - }); err != nil { + if err := d.s.BindHandler(pattern + "@" + domain, handler); err != nil { return err } } @@ -66,9 +62,9 @@ func (d *Domain) BindObject(pattern string, obj interface{}, methods...string) e } // 执行对象方法注册,methods参数不区分大小写 -func (d *Domain) BindObjectMethod(pattern string, obj interface{}, methods string) error { +func (d *Domain) BindObjectMethod(pattern string, obj interface{}, method string) error { for domain, _ := range d.m { - if err := d.s.BindObjectMethod(pattern + "@" + domain, obj, methods); err != nil { + if err := d.s.BindObjectMethod(pattern + "@" + domain, obj, method); err != nil { return err } } @@ -98,20 +94,20 @@ func (d *Domain) BindController(pattern string, c Controller, methods...string) return nil } -// RESTful控制器注册 -func (d *Domain) BindControllerRest(pattern string, c Controller) error { +// 控制器方法注册,methods参数区分大小写 +func (d *Domain) BindControllerMethod(pattern string, c Controller, method string) error { for domain, _ := range d.m { - if err := d.s.BindControllerRest(pattern + "@" + domain, c); err != nil { + if err := d.s.BindControllerMethod(pattern + "@" + domain, c, method); err != nil { return err } } return nil } -// 控制器方法注册,methods参数区分大小写 -func (d *Domain) BindControllerMethod(pattern string, c Controller, methods string) error { +// RESTful控制器注册 +func (d *Domain) BindControllerRest(pattern string, c Controller) error { for domain, _ := range d.m { - if err := d.s.BindControllerMethod(pattern + "@" + domain, c, methods); err != nil { + if err := d.s.BindControllerRest(pattern + "@" + domain, c); err != nil { return err } } diff --git a/g/net/ghttp/ghttp_server_handler.go b/g/net/ghttp/ghttp_server_handler.go index df75e99aa..583ae2c91 100644 --- a/g/net/ghttp/ghttp_server_handler.go +++ b/g/net/ghttp/ghttp_server_handler.go @@ -110,7 +110,16 @@ func (s *Server)callServeHandler(h *handlerItem, r *Request) { c.MethodByName("Shut").Call([]reflect.Value{reflect.ValueOf(r)}) } } else { - h.faddr(r) + // 是否有初始化及完成回调方法 + if h.finit != nil { + h.finit(r) + } + if !r.IsExited() { + h.faddr(r) + if h.fshut != nil { + h.fshut(r) + } + } } } diff --git a/g/net/ghttp/ghttp_server_router.go b/g/net/ghttp/ghttp_server_router.go index b144461fa..727ce09f7 100644 --- a/g/net/ghttp/ghttp_server_router.go +++ b/g/net/ghttp/ghttp_server_router.go @@ -13,6 +13,9 @@ import ( "container/list" "gitee.com/johng/gf/g/util/gregex" "gitee.com/johng/gf/g/util/gstr" + "gitee.com/johng/gf/g/os/glog" + "fmt" + "runtime" ) @@ -39,13 +42,38 @@ func (s *Server)parsePattern(pattern string) (domain, method, uri string, err er return } +// 获得服务注册的文件地址信息 +func (s *Server) getHandlerRegisterCallerLine(handler *handlerItem) string { + skip := 5 + if handler.rtype == gROUTE_REGISTER_HANDLER { + skip = 4 + } + if _, cfile, cline, ok := runtime.Caller(skip); ok { + return fmt.Sprintf("%s:%d", cfile, cline) + } + return "" +} + // 路由注册处理方法。 // 如果带有hook参数,表示是回调注册方法,否则为普通路由执行方法。 -func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... string) error { +func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... string) (resultErr error) { // Web Server正字运行时无法动态注册路由方法 if s.Status() == SERVER_STATUS_RUNNING { return errors.New("cannot bind handler while server running") } + caller := s.getHandlerRegisterCallerLine(handler) + if line, ok := s.routesMap[pattern]; ok { + s := fmt.Sprintf(`duplicated route registry "%s" in %s , former in %s`, pattern, caller, line) + glog.Errorfln(s) + return errors.New(s) + } else { + defer func() { + if resultErr == nil { + s.routesMap[pattern] = caller + } + }() + } + var hookName string if len(hook) > 0 { hookName = hook[0] @@ -132,13 +160,13 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin pushed := false for e := l.Front(); e != nil; e = e.Next() { item = e.Value.(*handlerItem) - // 判断是否已存在相同的路由注册项 + // 判断是否已存在相同的路由注册项,是则进行替换 if len(hookName) == 0 { if strings.EqualFold(handler.router.Domain, item.router.Domain) && strings.EqualFold(handler.router.Method, item.router.Method) && strings.EqualFold(handler.router.Uri, item.router.Uri) { e.Value = handler - pushed = true + pushed = true break } } @@ -157,7 +185,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ... strin return nil } -// 对比两个handlerItem的优先级,需要非常注意的是,注意新老对比项的参数先后顺序 +// 对比两个handlerItem的优先级,需要非常注意的是,注意新老对比项的参数先后顺序。 // 优先级比较规则: // 1、层级越深优先级越高(对比/数量); // 2、模糊规则优先级:{xxx} > :xxx > *xxx; @@ -168,19 +196,66 @@ func (s *Server) compareRouterPriority(newRouter, oldRouter *Router) bool { if newRouter.Priority < oldRouter.Priority { return false } - // 例如:/{user}/{act} 比 /:user/:act 优先级高 - if strings.Count(newRouter.Uri, "{") > strings.Count(oldRouter.Uri, "{") { + // 精准匹配比模糊匹配规则优先级高,例如:/name/act 比 /{name}/:act 优先级高 + var fuzzyCountFieldNew, fuzzyCountFieldOld int + var fuzzyCountNameNew, fuzzyCountNameOld int + var fuzzyCountAnyNew, fuzzyCountAnyOld int + var fuzzyCountTotalNew, fuzzyCountTotalOld int + for _, v := range newRouter.Uri { + switch v { + case '{': + fuzzyCountFieldNew++ + case ':': + fuzzyCountNameNew++ + case '*': + fuzzyCountAnyNew++ + } + } + for _, v := range oldRouter.Uri { + switch v { + case '{': + fuzzyCountFieldOld++ + case ':': + fuzzyCountNameOld++ + case '*': + fuzzyCountAnyOld++ + } + } + fuzzyCountTotalNew = fuzzyCountFieldNew + fuzzyCountNameNew + fuzzyCountAnyNew + fuzzyCountTotalOld = fuzzyCountFieldOld + fuzzyCountNameOld + fuzzyCountAnyOld + if fuzzyCountTotalNew < fuzzyCountTotalOld { return true } - // 例如: /:name/update 比 /:name/:action优先级高 - if strings.Count(newRouter.Uri, "/:") < strings.Count(oldRouter.Uri, "/:") { - // 例如: /:name/:action 比 /:name/*any 优先级高 - if strings.Count(newRouter.Uri, "/*") < strings.Count(oldRouter.Uri, "/*") { - return true - } + if fuzzyCountTotalNew > fuzzyCountTotalOld { return false } - return false + + /** 如果模糊规则数量相等,那么执行分别的数量判断 **/ + + // 例如:/name/{act} 比 /name/:act 优先级高 + if fuzzyCountFieldNew > fuzzyCountFieldOld { + return true + } + if fuzzyCountFieldNew < fuzzyCountFieldOld { + return false + } + // 例如: /name/:act 比 /name/*act 优先级高 + if fuzzyCountNameNew > fuzzyCountNameOld { + return true + } + if fuzzyCountNameNew < fuzzyCountNameOld { + return false + } + // 比较HTTP METHOD,更精准的优先级更高 + if newRouter.Method != gDEFAULT_METHOD { + return true + } + if oldRouter.Method != gDEFAULT_METHOD { + return true + } + // 模糊规则数量相等,后续不用再判断*规则的数量比较了, + // 这种情况下新的规则比旧的规则优先级更高 + return true } // 将pattern(不带method和domain)解析成正则表达式匹配以及对应的query字符串 diff --git a/g/net/ghttp/ghttp_server_service_controller.go b/g/net/ghttp/ghttp_server_service_controller.go index e0ce46624..7302794f5 100644 --- a/g/net/ghttp/ghttp_server_service_controller.go +++ b/g/net/ghttp/ghttp_server_service_controller.go @@ -39,6 +39,7 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e } key := s.mergeBuildInNameToPattern(pattern, sname, mname, true) m[key] = &handlerItem { + rtype : gROUTE_REGISTER_CONTROLLER, ctype : v.Elem().Type(), fname : mname, faddr : nil, @@ -53,6 +54,7 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) e } } m[p] = &handlerItem { + rtype : gROUTE_REGISTER_CONTROLLER, ctype : v.Elem().Type(), fname : mname, faddr : nil, @@ -75,6 +77,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string } key := s.mergeBuildInNameToPattern(pattern, sname, mname, false) m[key] = &handlerItem { + rtype : gROUTE_REGISTER_CONTROLLER, ctype : t, fname : mname, faddr : nil, @@ -100,6 +103,7 @@ func (s *Server)BindControllerRest(pattern string, c Controller) error { } key := name + ":" + pattern m[key] = &handlerItem { + rtype : gROUTE_REGISTER_CONTROLLER, ctype : v.Elem().Type(), fname : name, faddr : nil, diff --git a/g/net/ghttp/ghttp_server_service_handler.go b/g/net/ghttp/ghttp_server_service_handler.go index aae61079d..9a8329b3f 100644 --- a/g/net/ghttp/ghttp_server_service_handler.go +++ b/g/net/ghttp/ghttp_server_service_handler.go @@ -16,7 +16,8 @@ import ( // 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑 func (s *Server) BindHandler(pattern string, handler HandlerFunc) error { - return s.bindHandlerItem(pattern, &handlerItem{ + return s.bindHandlerItem(pattern, &handlerItem { + rtype : gROUTE_REGISTER_HANDLER, ctype : nil, fname : "", faddr : handler, diff --git a/g/net/ghttp/ghttp_server_service_object.go b/g/net/ghttp/ghttp_server_service_object.go index 1e4160694..36fd5baeb 100644 --- a/g/net/ghttp/ghttp_server_service_object.go +++ b/g/net/ghttp/ghttp_server_service_object.go @@ -45,6 +45,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er } key := s.mergeBuildInNameToPattern(pattern, sname, mname, true) m[key] = &handlerItem { + rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", faddr : v.Method(i).Interface().(func(*Request)), @@ -61,6 +62,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) er } } m[p] = &handlerItem { + rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", faddr : v.Method(i).Interface().(func(*Request)), @@ -94,6 +96,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string) } key := s.mergeBuildInNameToPattern(pattern, sname, mname, false) m[key] = &handlerItem{ + rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", faddr : fval.Interface().(func(*Request)), @@ -126,6 +129,7 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) error { } key := name + ":" + pattern m[key] = &handlerItem { + rtype : gROUTE_REGISTER_OBJECT, ctype : nil, fname : "", faddr : v.Method(i).Interface().(func(*Request)), diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index ba8038264..90d57a0ae 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -260,10 +260,7 @@ func (c *Config) Close() { func (c *Config) addMonitor(path string) { if c.jsons.Get(path) == nil { gfsnotify.Add(path, func(event *gfsnotify.Event) { - if event.IsRemove() { - gfsnotify.Remove(event.Path) - return - } + // 删除文件内容缓存,下一次查询会自动更新 c.jsons.Remove(event.Path) }) } diff --git a/g/os/gfile/gfile.go b/g/os/gfile/gfile.go index 7b979dd4e..81c92dca1 100644 --- a/g/os/gfile/gfile.go +++ b/g/os/gfile/gfile.go @@ -287,8 +287,9 @@ func Chmod(path string, mode os.FileMode) error { return os.Chmod(path, mode) } -// 打开目录,并返回其下一级子目录名称列表,按照文件名称大小写进行排序 -func ScanDir(path string) []string { +// 打开目录,并返回其下一级子目录名称列表,按照文件名称大小写进行排序,支持目录递归遍历。 +// 当递归遍历时,结果集返回的是子级文件/目录的绝对路径,而不仅仅是一个名字 +func ScanDir(path string, recursive ... bool) []string { f, err := os.Open(path) if err != nil { return nil @@ -299,6 +300,17 @@ func ScanDir(path string) []string { if err != nil { return nil } + // 是否递归遍历 + if len(recursive) > 0 && recursive[0] && len(list) > 0 { + for k, v := range list { + p := fmt.Sprintf("%s%s%s", path, Separator, v) + list[k] = p + if IsDir(p) { + list = append(list, ScanDir(p, true)...) + } + } + } + // 默认按照字符串大小排序 sort.Slice(list, func(i, j int) bool { return list[i] < list[j] }) return list } diff --git a/g/os/gfsnotify/gfsnotify.go b/g/os/gfsnotify/gfsnotify.go index e3414fdc3..74042c979 100644 --- a/g/os/gfsnotify/gfsnotify.go +++ b/g/os/gfsnotify/gfsnotify.go @@ -44,26 +44,10 @@ const ( ) // 全局监听对象,方便应用端调用 -var watcher, _ = New() - -// 添加对指定文件/目录的监听,并给定回调函数 -func Add(path string, callback func(event *Event)) error { - if watcher == nil { - return errors.New("global watcher creating failed") - } - return watcher.Add(path, callback) -} - -// 移除监听 -func Remove(path string) error { - if watcher == nil { - return errors.New("global watcher creating failed") - } - return watcher.Remove(path) -} +var watcher, _ = newWatcher() // 创建监听管理对象 -func New() (*Watcher, error) { +func newWatcher() (*Watcher, error) { if watch, err := fsnotify.NewWatcher(); err == nil { w := &Watcher { watcher : watch, @@ -79,6 +63,22 @@ func New() (*Watcher, error) { } } +// 添加对指定文件/目录的监听,并给定回调函数;如果给定的是一个目录,默认递归监控。 +func Add(path string, callback func(event *Event)) error { + if watcher == nil { + return errors.New("global watcher creating failed") + } + return watcher.AddRecursive(path, callback) +} + +// 移除监听,默认递归删除。 +func Remove(path string) error { + if watcher == nil { + return errors.New("global watcher creating failed") + } + return watcher.RemoveRecursive(path) +} + // 关闭监听管理对象 func (w *Watcher) Close() { w.watcher.Close() @@ -110,12 +110,45 @@ func (w *Watcher) Add(path string, callback func(event *Event)) error { return nil } +// 递归添加监控 +func (w *Watcher) AddRecursive(path string, callback func(event *Event)) error { + if gfile.IsDir(path) { + list := []string{path} + list = append(list, gfile.ScanDir(path, true)...) + for _, v := range list { + if err := w.Add(v, callback); err != nil { + return err + } + } + return nil + } else { + return w.Add(path, callback) + } +} + + // 移除监听 func (w *Watcher) Remove(path string) error { w.callbacks.Remove(path) return w.watcher.Remove(path) } +// 递归移除监听 +func (w *Watcher) RemoveRecursive(path string) error { + if gfile.IsDir(path) { + list := []string{path} + list = append(list, gfile.ScanDir(path, true)...) + for _, v := range list { + if err := w.Remove(v); err != nil { + return err + } + } + return nil + } else { + return w.Remove(path) + } +} + // 监听循环 func (w *Watcher) startWatchLoop() { go func() { @@ -139,23 +172,48 @@ func (w *Watcher) startWatchLoop() { }() } +// 检索给定path的回调方法**列表** +func (w *Watcher) getCallbacks(path string) *glist.List { + for path != "/" { + if l := w.callbacks.Get(path); l != nil { + return l.(*glist.List) + } else { + path = gfile.Dir(path) + } + } + return nil +} + // 事件循环 func (w *Watcher) startEventLoop() { go func() { for { if v := w.events.PopFront(); v != nil { event := v.(*Event) - // 如果是文件删除事件,判断该文件是否存在,如果存在,那么将此事件认为“假删除”,并重新添加监控 - if event.IsRemove() && gfile.Exists(event.Path){ - w.watcher.Add(event.Path) - continue + if event.IsRemove() { + if gfile.Exists(event.Path) { + // 如果是文件删除事件,判断该文件是否存在,如果存在,那么将此事件认为“假删除”, + // 并重新添加监控(底层fsnotify会自动删除掉监控,这里重新添加回去) + w.watcher.Add(event.Path) + continue + } else { + // 如果是真实删除,那么递归删除监控信息 + w.RemoveRecursive(event.Path) + } } - if l := w.callbacks.Get(event.Path); l != nil { - go func(list interface{}) { - for _, v := range list.(*glist.List).FrontAll() { - v.(func(event *Event))(event) + callbacks := w.getCallbacks(event.Path) + // 如果创建了新的目录,那么将这个目录递归添加到监控中 + if event.IsCreate() && gfile.IsDir(event.Path) { + for _, callback := range callbacks.FrontAll() { + w.AddRecursive(event.Path, callback.(func(event *Event))) + } + } + if callbacks != nil { + go func(callbacks *glist.List) { + for _, callback := range callbacks.FrontAll() { + callback.(func(event *Event))(event) } - }(l) + }(callbacks) } } else { break diff --git a/g/os/gfsnotify/gfsnotify_event.go b/g/os/gfsnotify/gfsnotify_event.go index 86fe2004f..2950e1dcb 100644 --- a/g/os/gfsnotify/gfsnotify_event.go +++ b/g/os/gfsnotify/gfsnotify_event.go @@ -6,22 +6,27 @@ package gfsnotify +// 文件/目录创建 func (e *Event) IsCreate() bool { return e.Op & CREATE == CREATE } +// 文件/目录修改 func (e *Event) IsWrite() bool { return e.Op & WRITE == WRITE } +// 文件/目录删除 func (e *Event) IsRemove() bool { return e.Op & REMOVE == REMOVE } +// 文件/目录重命名 func (e *Event) IsRename() bool { return e.Op & RENAME == RENAME } +// 文件/目录修改权限 func (e *Event) IsChmod() bool { return e.Op & CHMOD == CHMOD } \ No newline at end of file diff --git a/g/os/glog/glog_logger.go b/g/os/glog/glog_logger.go index 8916ff2bb..4b49549bb 100644 --- a/g/os/glog/glog_logger.go +++ b/g/os/glog/glog_logger.go @@ -43,9 +43,9 @@ func (l *Logger) SetBacktraceSkip(skip int) { // 可自定义IO接口 func (l *Logger) SetIO(w io.Writer) { - l.mu.RLock() + l.mu.Lock() l.io = w - l.mu.RUnlock() + l.mu.Unlock() } // 返回自定义IO diff --git a/g/os/gview/gview.go b/g/os/gview/gview.go index f4ccdb84b..a9d6e8a77 100644 --- a/g/os/gview/gview.go +++ b/g/os/gview/gview.go @@ -159,10 +159,7 @@ func (view *View) funcInclude(file string, data...map[string]interface{}) templa func (view *View) addMonitor(path string) { if view.contents.Get(path) == "" { gfsnotify.Add(path, func(event *gfsnotify.Event) { - if event.IsRemove() { - gfsnotify.Remove(event.Path) - return - } + // 删除文件内容缓存,下一次查询会自动更新 view.contents.Remove(event.Path) }) } diff --git a/geg/net/ghttp/server/duplicate/duplicate1.go b/geg/net/ghttp/server/duplicate/duplicate1.go new file mode 100644 index 000000000..ea60e72cd --- /dev/null +++ b/geg/net/ghttp/server/duplicate/duplicate1.go @@ -0,0 +1,19 @@ +// 路由重复注册检查 - handler +package main + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/net/ghttp" +) + +func main() { + s := g.Server() + s.BindHandler("/", func(r *ghttp.Request){ + r.Response.Writeln("哈喽世界!") + }) + s.BindHandler("/", func(r *ghttp.Request){ + r.Response.Writeln("哈喽世界!") + }) + s.SetPort(8199) + s.Run() +} \ No newline at end of file diff --git a/geg/net/ghttp/server/duplicate/duplicate2.go b/geg/net/ghttp/server/duplicate/duplicate2.go new file mode 100644 index 000000000..20fc1850f --- /dev/null +++ b/geg/net/ghttp/server/duplicate/duplicate2.go @@ -0,0 +1,33 @@ +// 路由重复注册检查 - controller +package main + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/frame/gmvc" +) + +type User struct { + gmvc.Controller +} + +func (u *User) Index() { + u.Response.Write("User") +} + +func (u *User) Info() { + u.Response.Write("Info - Uid: ", u.Request.Get("uid")) +} + +func (u *User) List() { + u.Response.Write("List - Page: ", u.Request.Get("page")) +} + +func main() { + s := g.Server() + s.BindController("/user", new(User)) + s.BindController("/user/{.method}/{uid}", new(User), "Info") + s.BindController("/user/{.method}/{page}.html", new(User), "List") + s.BindController("/user/{.method}/{page}.html", new(User), "List") + s.SetPort(8199) + s.Run() +} \ No newline at end of file diff --git a/geg/net/ghttp/server/duplicate/duplicate3.go b/geg/net/ghttp/server/duplicate/duplicate3.go new file mode 100644 index 000000000..1796e159b --- /dev/null +++ b/geg/net/ghttp/server/duplicate/duplicate3.go @@ -0,0 +1,25 @@ +// 路由重复注册检查 - object +package main + +import ( + "gitee.com/johng/gf/g" + "gitee.com/johng/gf/g/net/ghttp" +) + +type Object struct {} + +func (o *Object) Index(r *ghttp.Request) { + r.Response.Write("object index") +} + +func (o *Object) Show(r *ghttp.Request) { + r.Response.Write("object show") +} + +func main() { + s := g.Server() + g.Server().BindObject("/object", new(Object)) + g.Server().BindObject("/object", new(Object)) + s.SetPort(8199) + s.Run() +} \ No newline at end of file diff --git a/geg/os/file.go b/geg/os/gfile/gfile.go similarity index 100% rename from geg/os/file.go rename to geg/os/gfile/gfile.go diff --git a/geg/os/gfile/gfile_scan.go b/geg/os/gfile/gfile_scan.go new file mode 100644 index 000000000..f47f918b0 --- /dev/null +++ b/geg/os/gfile/gfile_scan.go @@ -0,0 +1,11 @@ +package main + +import ( + "gitee.com/johng/gf/g/util/gutil" + "gitee.com/johng/gf/g/os/gfile" +) + +func main() { + gutil.Dump(gfile.ScanDir("/home/john/Documents")) + gutil.Dump(gfile.ScanDir("/home/john/temp/newproject", true)) +} \ No newline at end of file diff --git a/geg/os/gfsnotify/fsnotify.go b/geg/os/gfsnotify/fsnotify.go index e92946bbb..00366cb7b 100644 --- a/geg/os/gfsnotify/fsnotify.go +++ b/geg/os/gfsnotify/fsnotify.go @@ -13,7 +13,7 @@ func main() { } defer watch.Close() //添加要监控的对象,文件或文件夹 - err = watch.Add("/home/john/Documents/temp") + err = watch.Add("/home/john/temp") if err != nil { log.Fatal(err) } diff --git a/geg/os/gfsnotify/gfsnotify.go b/geg/os/gfsnotify/gfsnotify.go index 023411a6b..4150aed1b 100644 --- a/geg/os/gfsnotify/gfsnotify.go +++ b/geg/os/gfsnotify/gfsnotify.go @@ -6,7 +6,7 @@ import ( ) func main() { - err := gfsnotify.Add("./temp.txt", func(event *gfsnotify.Event) { + err := gfsnotify.Add("/home/john/temp", func(event *gfsnotify.Event) { if event.IsCreate() { log.Println("创建文件 : ", event.Path) }