mirror of
https://gitee.com/johng/gf
synced 2026-06-07 10:22:11 +08:00
ghttp对象路由注册增加Init&Shut自动回调方法;ghttp增加重复路由注册检测功能;gfsnotify增加默认递归Add/Remove特性
This commit is contained in:
1
TODO
1
TODO
@ -18,6 +18,7 @@ orm增加sqlite对Save方法的支持(去掉触发器语句);
|
||||
ghttp.Server的Cookie及Session锁机制优化(去掉map锁机制);
|
||||
ghttp.Server增加Ip访问控制功能(DenyIps&AllowIps);
|
||||
ghttp路由功能增加分组路由特性;
|
||||
解决glog串日志情况;
|
||||
|
||||
|
||||
DONE:
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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字符串
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)),
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
19
geg/net/ghttp/server/duplicate/duplicate1.go
Normal file
19
geg/net/ghttp/server/duplicate/duplicate1.go
Normal file
@ -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()
|
||||
}
|
||||
33
geg/net/ghttp/server/duplicate/duplicate2.go
Normal file
33
geg/net/ghttp/server/duplicate/duplicate2.go
Normal file
@ -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()
|
||||
}
|
||||
25
geg/net/ghttp/server/duplicate/duplicate3.go
Normal file
25
geg/net/ghttp/server/duplicate/duplicate3.go
Normal file
@ -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()
|
||||
}
|
||||
11
geg/os/gfile/gfile_scan.go
Normal file
11
geg/os/gfile/gfile_scan.go
Normal file
@ -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))
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user